转到 C 中二进制文件的某个点(使用 fseek),然后从该位置读取(使用 fread)
Posted
技术标签:
【中文标题】转到 C 中二进制文件的某个点(使用 fseek),然后从该位置读取(使用 fread)【英文标题】:Go to a certain point of a binary file in C (using fseek) and then reading from that location (using fread) 【发布时间】:2012-04-09 09:42:15 【问题描述】:我想知道这是否是解决我的问题的最佳方法。
我知道保存我想要的信息的二进制文件的特定偏移量的值...我想做的是跳转到偏移量,然后从该位置开始读取一定数量的字节。
使用 google 后,我得出的结论是,我最好的选择是使用 fseek() 移动到偏移的位置,然后使用 fread() 从该位置读取一定数量的字节。
我这样想对吗?如果是这样,最好怎么做?即如何将两者结合在一起。
如果我不正确,你会建议我做什么?
非常感谢您的帮助。
马特
编辑:
我按照 fread() 的教程进行了调整,并将其调整为以下内容:
`#include <stdio.h>
int main()
FILE *f;
char buffer[11];
if (f = fopen("comm_array2.img", "rt"))
fread(buffer, 1, 10, f);
buffer[10] = 0;
fclose(f);
printf("first 10 characters of the file:\n%s\n", buffer);
return 0;
`
所以我使用了文件 'comm_array2.img' 并从文件中读取了前 10 个字符。
但据我了解,这是从文件开始,我想从文件中的某个位置(偏移量)开始
这样更有意义吗?
编辑编号 2:
看来我有点昏暗,所需要做的(从我的尝试看来)就是将 fseek() 放在上面代码中的 fread() 之前,它试图该位置,然后从那里读取。
【问题讨论】:
是的。使用 fseek() 和 fread()。你试过什么代码? 是的,你是对的,但你的问题或问题是什么? 网上有教程展示了如何使用它们。使用搜索词“fseek fread C tutorial”,应该很容易找到一些。你有没有工作过? 查找pread()
系统调用。使用流而不是文件描述符来模拟它。也许你给自己写了一个函数,比如:ssize_t fpread(char *buffer, size_t nbytes, size_t offset, FILE *fp);
.
如果您的平台支持,您可以改用pread()
,它会同时执行这两项操作。
【参考方案1】:
如果您使用文件流而不是文件描述符,那么您可以自己编写一个类似于 POSIX pread()
系统调用的(简单)函数。
您可以使用流而不是文件描述符轻松模拟它1。也许您应该为自己编写一个这样的函数(与我在评论中建议的界面略有不同):
size_t fpread(void *buffer, size_t size, size_t mitems, size_t offset, FILE *fp)
if (fseek(fp, offset, SEEK_SET) != 0)
return 0;
return fread(buffer, size, nitems, fp);
这是pread()
和fread()
约定之间的合理折衷。
函数调用的语法是什么样的?例如,从偏移量 732 读取,然后再次从偏移量 432(都从文件开头)和名为
f
的文件流读取。
由于您没有说要读取多少字节,我将假设每次读取 100 个字节。我假设目标变量(缓冲区)是buffer1
和buffer2
,并且它们都足够大。
if (fpread(buffer1, 100, 1, 732, f) != 1)
...error reading at offset 732...
if (fpread(buffer2, 100, 1, 432, f) != 1)
...error reading at offset 432...
返回计数是每个 100 字节的完整单元的数量; 1(得到了一切)或 0(出了差错)。
还有其他编写代码的方法:
if (fpread(buffer1, sizeof(char), 100, 732, f) != 100)
...error reading at offset 732...
if (fpread(buffer2, sizeof(char), 100, 432, f) != 100)
...error reading at offset 432...
这每次读取 100 个单字节;测试确保您按预期获得了全部 100 个。如果您在第二个示例中捕获返回值,您可以知道您确实获得了多少数据。如果第一次读取成功而第二次读取失败,那将是非常令人惊讶的;其他一些程序(或线程)将不得不在两次调用 fpread()
之间截断文件,但已知会发生更有趣的事情。
1 仿真不会完美; pread()
调用保证了fseek()
和fread()
的组合无法提供的原子性。但这在实践中很少会成为问题,除非您在尝试定位和读取文件时有多个进程或线程同时更新文件。
【讨论】:
谢谢你,我正要让你进一步评论你的评论,你抢先了我,所以谢谢。因此,如果我理解这一点,我将创建该函数,并以与我最初使用 pread 相同的方式使用它,并将文件名(而不是文件描述符)和偏移量传递给它? 排序...您的评论提到了文件名,但fread()
和fseek()
都不适用于文件名;那是fopen()
的工作。 fpread()
函数几乎可以替代 fseek()
和 fread()
调用。显然,如果你想让它取一个文件名,你必须在函数内使用fopen()
和(大概)fclose()
文件,并且你不会传递fp
参数。您可能会将文件名作为第一个参数。您可以使用"rb"
打开二进制文件进行读取; b 在 Unix 上是否存在并不重要,但在其他平台上,它确实存在。
啊,是的,我很抱歉,我的意思是说传递什么是“fp”(即我理解的使用 fopen() 时通常返回的内容)但是,从您的评论中我看到我实际上不会传递 'fp' 参数?
显示的代码需要FILE *
;我希望你传递文件流。 (我被您的第一条评论弄糊涂/误导了。)您可以编写一个函数来打开、定位、读取、关闭给定的文件名,然后您将传递一个文件名而不是文件流.但是,如果您要一次阅读文件的多个部分,我不建议您这样做。 fopen()
是一个相对较慢的函数,不应经常调用。因此,鉴于您的原始评论意味着文件流而不是文件名,那么是的:您可以根据需要使用fpread()
。
好的,非常感谢您的帮助和澄清。最后一件事,以便我可以完全理解您创建的函数,函数调用的语法是什么样的?例如,从偏移量 732 读取,然后再次从偏移量 432(都从文件的开头)和称为“f”的文件流读取。如果这似乎是一个简单的问题,我深表歉意,但我想确保我完全理解这一点。再次感谢您的宝贵时间,非常感谢。【参考方案2】:
这通常取决于您关心的部分之间的距离。如果您只是跳过/忽略您关心的部分之间的几个字节,通常更容易读取该数据并忽略您读取的内容,而不是使用fseek
跳过它。执行此操作的典型方法是定义一个结构,其中包含您关心的数据和您不关心的数据的占位符,读入结构,然后只使用您关心的部分:
struct whatever
long a;
long ignore;
short b;
w;
fread(&w, 1, sizeof(w), some_file);
// use 'w.a' and 'w.b' here.
但是,如果您关心的部分之间有很大的距离,那么您最初使用 fseek
到达重要部分的想法可能会更简单。
【讨论】:
【参考方案3】:你的理论听起来是正确的。打开、寻找、阅读、关闭。
为要读取的数据创建一个结构,并将指针传递给结构分配的内存的 read()。您可能需要在结构上使用 #pragma pack(1) 或类似的东西来防止错位问题。
【讨论】:
以上是关于转到 C 中二进制文件的某个点(使用 fseek),然后从该位置读取(使用 fread)的主要内容,如果未能解决你的问题,请参考以下文章
请问C语言对文件的读取都有哪些函数,都有啥功能?像fseek();fscanf();fread......啥的
C 语言文件操作 ( fseek 使用注意事项 | fseek 函数返回值分析 )