c - 我的代码中的 fread() 出了什么问题?
问题描述
这是我现在正在尝试的与我之前在 cs50 'Recover' 中的问题相关的代码的摘录。
我已经尝试了一切fread
,但由于某种原因,它根本没有按照我想要的方式工作。
在这个循环中,我试图弄清楚fread
实际是如何工作的。
我的问题是 -每次调用时它是否fread
从指向 ( ) 的文件中一次读取 512 个字节的数据 1 ?rawdata
在这种情况下,我的代码应该可以工作,因为循环无限期地运行,一遍又一遍地调用函数,因此一次移动流位置/文件光标(我不知道它叫什么)512 个字节。我从循环中休息了feof(rawdata)
。
我正在使用这个小程序来帮助我从 cs50 pset4 恢复。
// In a loop, until the end of file has been reached,
while (true) {
// Zeroing counter
jpg_counter = 0;
// Reading 512 bytes into the array of bytes
fread(bytes, 512, 1, rawdata);
// Searching the 512 bytes for JPEG signatures - bytes[3] with bitwise AND
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0) {
jpg_counter++;
}
// If found JPG, add total and keep going till end of file
if (jpg_counter != 0) {
total++;
}
//feof returns a non zero value only at the end of a file
if (feof(rawdata) != 0) {
break;
}
}
printf("%i\n", total);
解决方案
您的方法有两个主要问题:
您没有在阅读循环中正确测试文件结尾。您应该使用的返回值
fread
来确定您是否从流中读取了至少一个字节,并且您应该以相反的顺序传递参数:您正在读取多达 512 个字节:size_t n; while ((n = fread(bytes, 1, 512, rawdata)) > 0) { // n bytes were read from the file.
您只测试 JPEG 签名的前 4 个字节。除非已知该文件具有非常特定的结构,否则您可能希望在该块中搜索签名。
必须注意处理重叠块的签名,即:从 512 字节块的末尾开始但在下一个块结束。
这是修改后的版本:
int count_jpeg(FILE *rawdata) {
unsigned char bytes[3 + 512];
int pos = 0, end, i;
int total = 0;
size_t nread;
// In a loop, until the end of file has been reached,
while ((nread = fread(bytes + pos, 1, 512, rawdata)) > 0) {
end = pos + nread - 3;
for (i = 0; i < end; i++) {
// Searching the block for JPEG signatures - bytes[3] with bitwise AND
if (bytes[i] == 0xff && bytes[i + 1] == 0xd8
&& bytes[i + 2] == 0xff && (bytes[i + 3] & 0xf0) == 0xe0) {
total++;
i += 3;
}
}
// copy the last 3 bytes to the beginning of the block
for (i = pos = 0; i < 3; i++)
if (end + i >= 0) {
bytes[pos++] = bytes[end + i];
}
}
printf("%i\n", total);
return total;
}
编辑:如果已知 JPEG 签名在 512 字节边界上对齐,则可以删除扫描循环,但仍然可以读取文件末尾的部分块:
int count_jpeg(FILE *rawdata) {
unsigned char bytes[512];
int total = 0;
// In a loop, until the end of file has been reached,
while (fread(bytes + pos, 1, 512, rawdata) > 4) {
/* check for a signature at the beginning of the block */
if (bytes[0] == 0xff && bytes[1] == 0xd8
&& bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0) {
total++;
}
}
printf("%i\n", total);
return total;
}
推荐阅读
- android - 应用程序:compileDebugJavaWithJavac'。> 找不到 tools.jar 无法启动模拟器。原因:没有找到模拟器作为 `emulator -list-avds` 的输出
- html - 将图片链接作为道具传递
- laravel - Laravel 8 向 CopyAndPay Api 发出 POST 请求并呈现表单
- ios - AKOscillator 频率范围用于 iOS 中的Theremin 声音
- .net - SERVERPROPERTY 中的 EngineEdition "SQL Database" 是什么 SQL Server 版本或平台
- javascript - 作为 html 脚本的一部分更改文本属性
- android - Android studio 无法识别旧版本的 gradle 文件
- flutter - 执行 com.android.build.gradle.internal.tasks.Workers$ActionFacade 时发生故障 Flutter clean 后
- ruby-on-rails - Rails 中的验证
- python - AttributeError:“函数”对象没有属性“文本”