1. 关键词

C++ 文件系统操作 读取纯文本文件 写入纯文本文件 跨平台

2. fileutil.h


#pragma once

#include <string>
#include <cstdio>
#include <cstdint>
#include "filetype.h"
#include "filepath.h"

namespace cutl
{

    /**
     * @brief The file guard class to manage the FILE pointer automatically.
     * file_guard object can close the FILE pointer automatically when his scope is exit.
     */
    class file_guard
    {
    public:
        /**
         * @brief Construct a new file guard object
         *
         * @param file the pointer of the FILE object
         */
        explicit file_guard(FILE *file);

        /**
         * @brief Destroy the file guard object
         *
         */
        ~file_guard();

        /**
         * @brief Get the FILE pointer.
         *
         * @return FILE*
         */
        FILE *getfd() const;

    private:
        FILE *file_;
    };

    /**
     * @brief Read the text content of a file.
     *
     * @param path the filepath of the file to be read
     * @param max_read_size the maximum size to be read, default is 4096 bytes.
     *
     * If the file size is larger than max_read_size, only the first max_read_size bytes will be read. otherwise, the whole file will be read.
     *
     * @return text content of the file
     */
    std::string readtext(const filepath &path, uint64_t max_read_size = 4096);

    /**
     * @brief Write the text content to a file.
     *
     * @param path the filepath of the file to be written
     * @param content text content to be written to the file
     * @return true if the content is written successfully, false otherwise.
     */
    bool writetext(const filepath &path, const std::string &content);

} // namespace cutl

3. fileutil.cpp

#include <cstdio>
#include <map>
#include <iostream>
#include <cstring>
#include <sys/stat.h>
#include "fileutil.h"
#include "inner/logger.h"
#include "inner/filesystem.h"
#include "strutil.h"

namespace cutl
{
    file_guard::file_guard(FILE *file)
        : file_(file)
    {
    }

    file_guard::~file_guard()
    {
        if (file_)
        {
            // CUTL_DEBUG("close file");
            int ret = fclose(file_);
            if (ret != 0)
            {
                CUTL_ERROR("fail to close file, ret" + std::to_string(ret));
            }
            file_ = nullptr;
        }
        // ROBOLOG_DCHECK(file_ == nullptr);
    }

    FILE *file_guard::getfd() const
    {
        return file_;
    }

    std::string readtext(const filepath &path, uint64_t max_read_size)
    {
        file_guard fg(fopen(path.str().c_str(), "r"));
        if (fg.getfd() == nullptr)
        {
            CUTL_ERROR("open file failed for " + path.str());
            return "";
        }

        // 从文件系统的文档信息里读取文件大小,性能更高
        auto data_len = filesize(path, true);
        // 公国文件操作的方式和获取文件大小
        // fseek(fg.getfd(), 0, SEEK_END);
        // size_t data_len = static_cast<size_t>(ftell(fg.getfd()));
        // rewind(fg.getfd());
        CUTL_DEBUG("file size: " + std::to_string(data_len) + ", file: " + path.str());

        // get read size
        if (data_len > max_read_size)
        {
            data_len = max_read_size;
            CUTL_WARN("file size is large than " + std::to_string(max_read_size) + ", file:" + path.str());
        }

        char *buffer = new char[data_len + 1];
        if (buffer == nullptr)
        {
            CUTL_ERROR("buffer alloc failed, data_len:" + std::to_string(data_len));
            return "";
        }
        size_t read_len = static_cast<size_t>(fread(buffer, 1, data_len, fg.getfd()));
        if (read_len < data_len)
        {
            CUTL_ERROR("read file failed, only read " + std::to_string(read_len) + " bytes for " + path.str());
        }

        buffer[read_len] = '\0';
        auto text = std::string(buffer);
        delete[] buffer;

        return text;
    }

    // https://en.cppreference.com/w/cpp/header/cstdio
    bool writetext(const filepath &path, const std::string &content)
    {
        // std::lock_guard
        file_guard fg(fopen(path.str().c_str(), "w"));
        if (fg.getfd() == nullptr)
        {
            CUTL_ERROR("open file failed for " + path.str() + ", error: " + strerror(errno));
            return false;
        }

        size_t written_size = fwrite(content.c_str(), 1, content.length(), fg.getfd());
        if (written_size != content.length())
        {
            CUTL_ERROR("written size is not equal to content size for " + path.str());
            return false;
        }

        int ret = fflush(fg.getfd());
        if (0 != ret)
        {
            CUTL_ERROR("fail to flush file:" + path.str());
            return false;
        }

        if (!file_sync(fg.getfd()))
        {
            CUTL_ERROR("file_sync failed for " + path.str());
            return false;
        }

        return true;
    }

4. 源码地址

更多详细代码,请查看本人写的C++ 通用工具库: common_util, 本项目已开源,代码简洁,且有详细的文档和Demo。


SunLogging


陌尘
6 声望8 粉丝

花名(网名): 陌尘