如何确定由std :: ofstream打开的文件的当前大小?

时间:2019-01-17 13:47:39

标签: c++ fstream ofstream

我有一个类,其文件流类型为ofstream。构造函数以附加模式打开文件,并且所有消息总是写在文件末尾。

我需要以最大固定大小(例如1Mb)写入outputFile,然后关闭,重命名和压缩它,然后打开一个同名的新文件。

当达到一定大小的文件时,需要执行此操作。

我尝试使用tellg(),但在互联网上阅读了东西(和this)后,我知道这是不正确的方法。

由于我是C ++的新手,所以我试图找出最优化,最正确的方法来获取ofstream打开的文件的当前准确大小?

class Logger {
    std::ofstream outputFile;
    int curr_size;
    Logger (const std::string logfile) : outputFile(FILENAME,
                                                     std::ios::app)
    {
        curr_size = 0;
    }
};

在程序的某个地方,我正在向其中写入数据:

    // ??? Determine the size of current file ???

    if (curr_size >= MAX_FILE_SIZE) {
        outputFile.close();
        //Code to rename and compress file
        // ...
        outputFile.open(FILENAME, std::ios::app);
        curr_size = 0;
    }

    outputFile << message << std::endl;
    outputFile.flush();

3 个答案:

答案 0 :(得分:2)

fstreams既可以是输入流,也可以是输出流。 tellg()将返回输入位置,而tellp()将告诉您输出位置。 tellp()将在附加到文件后告诉您文件的大小。

考虑像这样初始化您的Logger(编辑:添加了输出流运算符的示例):

#include <iostream>
#include <fstream>

class Logger {
    std::string m_filename;
    std::ofstream m_os;
    std::ofstream::pos_type m_curr_size;
    std::ofstream::pos_type m_max_size;
public:
    Logger(const std::string& logfile, std::ofstream::pos_type max_size) :
        m_filename(logfile),
        m_os(m_filename, std::ios::app),
        m_curr_size(m_os.tellp()),
        m_max_size(max_size)
    {}

    template<typename T>
    friend Logger& operator<<(Logger&, const T&);
};

template<typename T>
Logger& operator<<(Logger& log, const T& msg) {
    log.m_curr_size = (log.m_os << msg << std::flush).tellp();

    if(log.m_curr_size>log.m_max_size) {
        log.m_os.close();
        //rename & compress
        log.m_os = std::ofstream(log.m_filename, std::ios::app);
        log.m_curr_size = log.m_os.tellp();
    }
    return log;
}

int main()
{
    Logger test("log", 4LL*1024*1024*1024*1024);
    test << "hello " << 10 << "\n";
    return 0;
}

如果您使用C ++ 17或有<filesystem>的实验版本,也可以使用它来获取绝对文件大小,如下所示:

#include <iostream>
#include <fstream>
#include <filesystem>

namespace fs = std::filesystem;

class Logger {
    fs::directory_entry m_logfile;
    std::ofstream m_os;
    std::uintmax_t m_max_size;

    void rotate_if_needed() {
        if(max_size_reached()) {
            m_os.close();
            //rename & compress
            m_os = std::ofstream(m_logfile.path(), std::ios::app);
        }
    }
public:
    Logger(const std::string& logfile, std::uintmax_t max_size) :
        m_logfile(logfile),
        m_os(m_logfile.path(), std::ios::app),
        m_max_size(max_size)
    {
        // make sure the path is absolute in case the process
        // have changed current directory when we need to rotate the log
        if(m_logfile.path().is_relative())
            m_logfile = fs::directory_entry(fs::absolute(m_logfile.path()));
    }

    std::uintmax_t size() const { return m_logfile.file_size(); }
    bool max_size_reached() const { return size()>m_max_size; }

    template<typename T>
    friend Logger& operator<<(Logger&, const T&);
};

template<typename T>
Logger& operator<<(Logger& log, const T& msg) {
    log.m_os << msg << std::flush;
    log.rotate_if_needed();
    return log;
}

int main()
{
    Logger test("log", 4LL*1024*1024*1024*1024);
    std::cout << test.size() << "\n";
    test << "hello " << 10 << "\n";
    std::cout << test.size() << "\n";
    test << "some more " << 3.14159 << "\n";
    std::cout << test.size() << "\n";
    return 0;
}

答案 1 :(得分:1)

我尝试了tellp(),对我来说效果很好:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
  ofstream myFile("data.txt", ios_base::app);
  myFile << "Hello World!" << endl;

  cout << myFile.tellp() << endl;
  return 0;
}

这是调用此程序时的输出:

$ ./program
13
$ ./program
26
$ ./program
39

答案 2 :(得分:1)

使用std::ofstream::tellp()

std::ofstream file{"file.txt", std::ios::app};
std::cout << "file size: " << file.tellp();