美文网首页
使用C++17 标准库处理文件系统文件

使用C++17 标准库处理文件系统文件

作者: FredricZhu | 来源:发表于2021-06-13 06:22 被阅读0次

    C++ 17 std::filesystem库还是挺顺滑的,使用前需要注意把Visual Studio的默认Cpp标准设置为 C++17,如图所示。


    image.png

    否则自动提示会比较难受。

    这个库需要注意的一点是,std::filesystem::path类重载了类型转换运算符
    operator string_type() const,
    这个意思就是,凡是需要传std::filesystem::path的地方,都可以直接传 std::string,标准库会帮你处理这一切的。

    程序代码如下,
    CMakeList.txt

    
    cmake_minimum_required(VERSION 2.6)
    project(chat_room)
    
    add_definitions(-std=c++17)
    
    
    find_package(Boost REQUIRED COMPONENTS
        system
        filesystem
        serialization
        program_options
        thread
        )
    
    include_directories(${Boost_INCLUDE_DIRS})
    
    file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
    foreach( sourcefile ${APP_SOURCES} )
            file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile})
        if( "${filename}" STREQUAL "main.cpp")
            string(REPLACE ".cpp" "" file ${filename})
            add_executable(${file}  ${APP_SOURCES})
            target_link_libraries(${file} ${Boost_LIBRARIES})
            target_link_libraries(${file} pthread)
        endif()
    endforeach( sourcefile ${APP_SOURCES})
    

    main.cpp

    #include "f_copy.h"
    #include <filesystem>
    #include <iostream>
    #include <fstream>
    #include <string>
    
    int main(int argc, char* argv[]) {
        std::filesystem::path cur_path = std::filesystem::current_path().parent_path();
        std::filesystem::path textSrcF {cur_path};
        std::filesystem::path textDstF {cur_path};
        textSrcF /= "main.cpp";
        textDstF /= "dst.cpp";
        TextFileCopy(textSrcF, textDstF);
    
        std::filesystem::path binSrcF {R"(/Users/aabjfzhu/spark-snowflake_2.11-2.8.5-spark_2.4.jar)"};
        std::filesystem::path binDstF {cur_path};
        binDstF /= "spark-snowflake.jar";
        BinaryFileCopy(binSrcF, binDstF);
        return 0;
    }
    

    f_copy.h

    #ifndef _FREDRIC_F_COPY_H_
    #define _FREDRIC_F_COPY_H_
    
    #include <string>
    
    void TextFileCopy(const std::string& srcF, const std::string& dstF); 
    void BinaryFileCopy(const std::string& srcF, const std::string& dstF);
    
    #endif
    

    f_copy.cpp

    #include "f_copy.h"
    
    #include <filesystem>
    #include <fstream>
    #include <iostream>
    #include <string>
    
    void TextFileCopy(const std::string& srcF, const std::string& dstF) {
        std::ifstream input{srcF};
        if (!input) {
            std::cout << "Source File not found" << std::endl;
            return;
        }
    
        std::filesystem::path destPath{dstF};
        if (std::filesystem::exists(destPath)) {
            std::cout << "File already exists, will override the exist file: "
                      << dstF << std::endl;
        }
    
        std::ofstream output{dstF};
        if (!output) {
            std::cout << "Could not open the dest file" << std::endl;
            return;
        }
    
        std::string line;
        while (std::getline(input, line)) {
            output << line << std::endl;
        }
    
        input.close();
        output.close();
    }
    
    void BinaryFileCopy(const std::string& srcF, const std::string& dstF) {
        std::ifstream input{srcF, std::ios::in | std::ios::binary};
        if (!input) {
            std::cout << "Could not open the source file" << std::endl;
            return;
        }
    
        if (std::filesystem::exists(dstF)) {
            std::cout << "File Already exists, will override the exists file: "
                      << dstF << std::endl;
        }
    
        std::ofstream output{dstF, std::ios::out | std::ios::binary};
        if (!output) {
            std::cout << "Could not open the destination file" << std::endl;
            return;
        }
    
        auto file_size = std::filesystem::file_size(srcF);
        const unsigned BufferSize = 512;
        char buffer[BufferSize]{};
    
        std::cout << "Copying: " << srcF;
        // 文件不到一个Buffer大
        if (file_size < BufferSize) {
            if (!input.read(buffer, file_size)) {
                throw std::runtime_error("Error occurred during read operation");
            }
            if (!output.write(buffer, file_size)) {
                throw std::runtime_error("Error occurred during write operation");
            }
        } else {
            // 大文件分为多个块来拷,并打印进度,进度乘10,是为了不让结果看起来都是0,一直不打印
            auto chunks = file_size / BufferSize;
            // 这里用int是因为 剩余大小小于 512,用int就可以了,不需要 std::size_t
            int remaining = file_size % BufferSize;
            int progress{}, oldProgress{};
            for (int i = 0; i < chunks; ++i) {
                if (!input.read(buffer, BufferSize)) {
                    throw std::runtime_error(
                        "Error occurred during read operation");
                }
    
                if (!output.write(buffer, BufferSize)) {
                    throw std::runtime_error(
                        "Error occurred during write operation");
                }
    
                // 先转浮点避免全零,再转整型便于比较
                // 类型转换建议使用 static_cast,不要直接强转
                // 因为static_cast会做类型检查
                progress = static_cast<int>((10 * static_cast<float>(i) / chunks));
                if (progress != oldProgress) {
                    std::cout << '.';
                }
                oldProgress = progress;
            }
    
            // 下一次的读取将会小于 BufferSize
            // 但是buffer 里面可能还有上次读取的残存数据,
            // 所以需要使用memset清空
            // 比较底层的C操作,但是没办法,因为读写二进制必须按char* [byte]处理
            memset(buffer, '\0', BufferSize);
    
            if (remaining > 0) {
                if (!input.read(buffer, remaining)) {
                    throw std::runtime_error(
                        "Error occurred during read operation");
                }
                if (!output.write(buffer, remaining)) {
                    throw std::runtime_error(
                        "Error occurred during write operation");
                }
                std::cout << '.';
            }
    
            std::cout << "Done! " << std::endl;
    
            input.close();
            output.close();
        }
    }
    

    相关文章

      网友评论

          本文标题:使用C++17 标准库处理文件系统文件

          本文链接:https://www.haomeiwen.com/subject/axuweltx.html