转到 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 个字节。我假设目标变量(缓冲区)是buffer1buffer2,并且它们都足够大。

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 函数

C 语言文件操作 ( fseek 使用注意事项 | fseek 函数返回值分析 )

C 语言文件操作 ( 使用 fseek 函数生成指定大小文件 | 偏移量 文件字节数 - 1 )

C 语言文件操作 ( fseek 函数 )

使用C套接字在HTTP响应中发送二进制文件