提问人:James Schek 提问时间:10/3/2008 最后编辑:Jim FellJames Schek 更新时间:8/10/2015 访问量:16151
为什么 EOF 会提前到达 EOF?
Why is fread reaching the EOF early?
问:
我正在编写一个将文件读入内存的 C 库。它跳过文件的前 54 个字节(标头),然后将其余部分作为数据读取。我使用 fseek 来确定文件的长度,然后使用 fread 读取文件。
循环运行一次,然后结束,因为已达到 EOF(无错误)。最后,bytesRead = 10624,ftell(stream) = 28726,缓冲区包含 28726 个值。我预计 fread 将读取 30,000 字节,当达到 EOF 时,文件位置为 30054。
C语言不是我的母语,所以我怀疑我在某个地方犯了一个愚蠢的初学者错误。
代码如下:
const size_t headerLen = 54;
FILE * stream;
errno_t ferrno = fopen_s( &stream, filename.c_str(), "r" );
if(ferrno!=0) {
return -1;
}
fseek( stream, 0L, SEEK_END );
size_t bytesTotal = (size_t)(ftell( stream )) - headerLen; //number of data bytes to read
size_t bytesRead = 0;
BYTE* localBuffer = new BYTE[bytesTotal];
fseek(stream,headerLen,SEEK_SET);
while(!feof(stream) && !ferror(stream)) {
size_t result = fread(localBuffer+bytesRead,sizeof(BYTE),bytesTotal-bytesRead,stream);
bytesRead+=result;
}
根据您使用的引用,很明显,在模式标志中添加“b”是答案。寻求骨头徽章的提名。:-)
这个参考资料在第二段第二句话中谈到了它(尽管没有在他们的表格中)。
MSDN 直到页面的一半才讨论二进制标志。
OpenGroup 提到了“b”标签的存在,但指出它“无效”。
答:
56赞
Evan Teran
10/3/2008
#1
也许这是一个二进制模式问题。尝试以模式打开文件。"r+b"
编辑:如评论中所述,它可能更符合您的原始意图,因为将打开它进行读/写并且是只读的。"rb"
"r+b"
"rb"
评论
0赞
user7116
10/3/2008
+1 代表 Mike F 和我自己。Windows 总是用 +b 咬我。
0赞
Greg Hewgill
10/3/2008
我建议先尝试“rb”,因为“r+b”打开文件进行读写,如果您不打算写入该文件,则应继续以只读方式打开它。
0赞
James Schek
10/3/2008
这就是答案。“RB”有效。RTFM的另一个案例。第一段也这样说:cplusplus.com/reference/clibrary/cstdio/fopen.html
0赞
Paul Tomblin
10/3/2008
我同意 Evan 的观点,这可能是一个二进制模式问题。但是,我很确定 C 标准并不能保证您正在使用的 ftell 将返回文件的实际长度。我似乎记得需要返回一个“令牌”,如果您将其传递给 fseek,它将让您回到文件中的相同位置。
0赞
James Schek
10/3/2008
我也有同样的想法......根据这个参考,它是实际位置:opengroup.org/onlinepubs/009695399/functions/ftell.html
0赞
Richard Harrison
10/3/2008
#2
还值得注意的是,只需将binmode.obj包含在链接命令中即可在所有文件打开时为您执行此操作。
-1赞
Kumar Pushkar
6/26/2014
#3
基于前面答案的解决方案:
size_t bytesRead = 0;
BYTE* localBuffer = new BYTE[bytesTotal];
fseek(stream,headerLen,SEEK_SET);
while(!feof(stream) && !ferror(stream)) {
size_t result = fread(localBuffer+bytesRead,sizeof(BYTE),bytesTotal-
bytesRead,stream);
bytesRead+=result;
}
评论