如何检测二进制文件已被完全消耗
How Can I Detect That a Binary File Has Been Completely Consumed?
如果我这样做:
ofstream ouput("foo.txt");
output << 13;
output.close();
ifstream input("foo.txt");
int dummy;
input >> dummy;
cout << input.good() << endl;
我会得到结果:"0"
然而,如果我这样做:
ofstream ouput("foo.txt", ios_base::binary);
auto dummy = 13;
output.write(reinterpret_cast<const char*>(&dummy), sizeof(dummy));
output.close();
ifstream input("foo.txt", ios_base::binary);
input.read(reinterpret_cast<char*>(&dummy), sizeof(dummy));
cout << input.good() << endl;
我会得到结果:"1"
这让我很沮丧。我是否必须通过检查ifstream
的缓冲区来确定它是否已被完全消耗?
关于
如何检测二进制文件已被完全消耗?
一种效率稍低但易于理解的方法是测量文件的大小:
ifstream input("foo.txt", ios_base::binary);
input.seekg(0, ios_base::end); // go to end of the file
auto filesize = input.tellg(); // current position is the size of the file
input.seekg(0, ios_base::beg); // go back to the beginning of the file
然后随时检查当前位置:
if (input.tellg() == filesize)
cout << "The file was consumed";
else
cout << "Some stuff left in the file";
这种方式有一些缺点:
- 效率不高-在文件中来回移动
- 不适用于特殊文件(例如管道)
- 如果文件被更改,则不起作用(例如,您以读写模式打开文件)
- 只适用于二进制文件(似乎是您的情况,所以可以),不适用于文本文件
因此,最好使用人们的常规方式,即尝试阅读并在失败时保释:
if (input.read(reinterpret_cast<char*>(&dummy), sizeof(dummy)))
cout << "I have read the stuff, will work on it now";
else
cout << "No stuff in file";
或者(在循环中)
while (input.read(reinterpret_cast<char*>(&dummy), sizeof(dummy)))
{
cout << "Working on your stuff now...";
}
您正在做完全不同的事情。
CCD_ 2是贪婪的并且将尽可能多地读取到CCD_ 3中。碰巧在这样做的时候,它会跑到文件的末尾。这设置了input.eof()
,并且流不再是good()
。由于在手术结束前确实找到了一些数字,手术仍然成功。
在第二次读取中,您要求指定字节数(很可能是4),读取成功。所以流仍然是good()
。
流接口不会预测任何未来I/O的结果,因为在一般情况下它无法知道。如果您使用cin
而不是input
,那么如果用户继续键入,现在可能会有更多内容可供阅读。
具体来说,eof()
状态直到有人试图读取文件末尾之后才会出现。
对于文本流,由于您只写入了整数值,甚至没有写入一个空格而不是行的末尾,因此在读取时,库必须尝试读取一个通过1
和3
并到达文件末尾的字符。所以好比特是假的,eof是真的。
对于二进制流,假设int是32位大,则写入4个字节(sizeof(int)),读取4个字节。好的仍然没有出现任何问题,好的部分是真的,而eof是假的。只有下一次读取才会到达文件末尾。
但要小心。在文本示例中,如果您在编辑器中打开文本文件并简单地保存它而不更改任何内容,那么编辑器很可能会自动添加一个行尾。在这种情况下,读取将在行尾停止,对于二进制情况,好比特将为true,eof为false。和你用output << 13 << std::endl;
写的一样
所有这一切都意味着,当good-it-true和eof为false时,您永远不能假设读取不是文件的最后一个元素,因为即使当时没有返回任何内容,文件的末尾也可能只在下一次读取时命中。
TL/DR:知道文件中什么都没有的唯一万无一失的方法是当你不能再从中读取一些东西时。
您不需要检查缓冲区。您可以确定整个文件是否已被消耗:cout << (input.peek() != char_traits<char>::eof()) << endl
这使用:peek
,它是:
从输入流中读取下一个字符,而不提取
示例中的good
为:
- 在最后一次提取操作之后返回
false
,这是因为int
提取运算符必须读取,直到找到非数字的字符。在这种情况下,这是EOF字符,当该字符被读取时,即使作为分隔符,也会设置流的eofbit
,导致good
失败 - 在调用
operator>>
1后返回true
,因为read
精确地提取sizeof(int)
字节,所以即使EOF字符是下一个字符,也不会读取它,使流的eofbit
未设置,good
通过
CCD_ 26可以在这两种情况中的任何一种之后使用,并且在两种情况下都将正确返回CCD_ 27。实际上,这是为您检查缓冲区,但二进制文件有一个重要区别:如果您自己检查二进制文件,您会发现它可能包含EOF字符。(在大多数定义为0xFF的系统上,其中4个是-1的二进制表示。)如果您正在检查缓冲区的下一个字符,您将不知道这是否真的是文件的末尾。
然而,peek
不仅仅返回char
,它还返回dummy
0。如果peek
返回0x000000FF,那么您看到的是EOF字符,但不是文件的末尾。如果peek
返回char_traits<char>::eof()
(通常为0xFFFFFFFF),那么您看到的是文件的末尾。
- 正在读取二进制文件(is_open)
- 在C++中将类(带有Vector成员)保存为二进制文件
- 如何从二进制文件中读取字符串
- 保存/加载大量短数组到二进制文件
- 从二进制文件中读取整数数组
- Android 在编译二进制文件时重建静态库
- 在 C++ 中将双精度变量写入二进制文件
- clang 的 libFuzzer 可以在同一二进制文件中测试超过 1 个 API 吗?
- C++:实际上不是从二进制文件中读取
- 如何从二进制文件中的给定符号中获取调用程序图
- 将内部带有矢量的结构保存/读取到二进制文件中
- 编译多个C++文件.调用二进制文件以运行代码
- 如何使用位字段将数据从二进制文件复制到结构中?
- 仅捕获异常就可以检测所有二进制文件在C 中读取错误是否足够
- 检测二进制文件数据的端性
- PIN - 获取正在检测的二进制文件的进程 ID
- 代码覆盖率错误(未检测二进制文件)
- 如何检测二进制文件已被完全消耗
- C++STL-检测二进制文件的末尾
- 检测二进制文件的GCC编译时标志