std::ifstream/FILE*是否可以更改大小

Can a std::ifstream/FILE* change size?

本文关键字:是否 ifstream FILE std      更新时间:2023-10-16

假设我有以下代码(只需打开一个文件,获取其大小,并一次性读取):

std::ifstream file(path, std::ios_base::binary | std::ios_base::ate);
std::istream::streampos file_size = file.tellg();
file.seekg(0);
char* buffer = new char[file_size];
file.read(buffer, file_size);

文件是否可以在file.tellg()file.read()调用之间更改大小(即另一个程序修改文件)?也就是说,如果file.read()成功,是否保证file.gcount() == file_size

将其扩展到C*(即执行fopen("rb")fseek()ftell()rewind()fread()),如果fread()成功,它是否总是返回文件大小(如ftell()之前报告的)?

我倾向于将其定义为实现,但我很好奇C++标准(或C标准,因为C++标准指的是FILE相关函数)是否在这里做出了任何保证。

*我在C++中工作,有两种方法可以用来处理文件:std::fstreamFILE*。C++标准在FILE*函数方面遵循C标准,这就是为什么我在这里明确提到C

我认为这取决于您打开的文件类型和操作系统的功能。

为了使读取不按预期进行,文件必须在ftellfread之间收缩。您可以让另一个进程使用ftruncate来完成此操作。我找不到任何信息来说明打开文件的任何其他进程会发生什么。但我不希望他们一定能够读取过去的数据。

以下实验表明,std::ifstream/FILE*在读取时确实可以改变大小:

写入1.cpp

#include <fstream>
int main() {
    for (;;) {
        std::ofstream file("file.txt", std::ios_base::binary | std::ios_base::trunc);
        file.flush();
        file << "Hello world!n";
    }
}

Reader1.cpp

#include <iostream>
#include <fstream>
int main() {
    for (;;) {
        std::ifstream file("file.txt", std::ios_base::binary | std::ios_base::ate);
        std::streamsize file_size = file.tellg();
        if (!file || file_size == -1) continue;
        file.seekg(0);
        char* buffer = new char[file_size];
        file.read(buffer, file_size);
        delete [] buffer;
        if (file.gcount() != file_size) {
            std::cout << file.gcount() << " != " << file_size << std::endl;
            break;
        }
    }
}

编译Writer1.cppReader1.cpp并同时运行它们最终得到0 != 13,这表明std::ifstream确实可以在tellg()read()之间改变大小。

Writer2.cpp

#include <iostream>
#include <fstream>
#include <cstdio>
int main() {
    for (;;) {
        FILE* file = fopen("file.txt", "wb");
        fflush(file);
        fwrite("Hello world!n", 1, 13, file);
        fclose(file);
    }
}

Reader2.cpp

#include <iostream>
#include <cstdio>
int main() {
    for (;;) {
        FILE* file = fopen("file.txt", "rb");
        if (!file) continue;
        fseek(file, 0, SEEK_END);
        long file_size = ftell(file);
        if (file_size == -1) {
            fclose(file);
            continue;
        }
        rewind(file);
        char* buffer = new char[file_size];
        size_t nread = fread(buffer, 1, file_size, file);
        fclose(file);
        delete [] buffer;
        if (nread != file_size) {
            std::cout << nread << " != " << file_size << std::endl;
            break;
        }
    }
}

同样,编译Writer2.cppReader2.cpp并同时运行它们最终会产生0 != 13,这表明FILE*确实可以在ftell()fread()之间改变大小。

有趣的是,std::ifstream对我来说比FILE*失败得更快。这些测试是在带有clang 3.5的OS X 10.9.5上完成的。