【问题标题】:Using fseek to backtrack使用 fseek 回溯
【发布时间】:2009-04-23 04:21:26
【问题描述】:

使用fseek回溯字符fscanf操作可靠吗?

例如,如果我只有 fscanf-ed 10 个字符,但我想回溯这 10 个字符,我可以只使用 fseek(infile, -10, SEEK_CUR) 吗?

在大多数情况下它都有效,但我似乎对字符 ^M 有问题。显然fseek 将其注册为一个字符,但fscanf 没有注册它,因此在我之前的示例中,一个包含^M 的10 字符块将需要fseek(infile, -11, SEEK_CUR)fseek(infile, -10, SEEK_CUR) 会缩短 1 个字符。

为什么会这样?

编辑:我在文本模式下使用fopen

【问题讨论】:

    标签: c file-io fseek


    【解决方案1】:

    您看到了“文本”和“二进制”文件之间的区别。当以文本模式打开文件时(在 fopen 第二个参数中没有“b”),stdio 库可能(实际上,必须)根据操作系统对文本文件的约定来解释文件的内容。例如,在 Windows 中,一行以 \r\n 结尾,而这会被 stdio 转换为单个 \n,因为这是 C 约定。写入文本文件时,单个 \n 将输出为 \r\n。

    这使得编写处理文本文件的可移植 C 程序变得更加容易。然而,有些细节变得复杂,fseeking 就是其中之一。正因为如此,C 标准只在少数情况下在文本文件中定义 fseek:到最开始、到最后、到当前位置,以及到使用 ftell 检索到的先前位置。换句话说,您无法计算要查找文本文件的位置。或者您可以,但您必须自己处理所有特定于平台的细节。

    或者,您可以使用二进制文件并自己进行行尾转换。同样,便携性受到影响。

    在您的情况下,如果您只想回到上次执行 fscancf 的位置,最简单的方法是在 fscanf 之前使用 ftell。

    【讨论】:

    • 谢谢,我不知道 ftell... 绝对比手动 fseek 更好的实现方式
    【解决方案2】:

    这是因为 fseek 处理字节,而 fscanf 智能地处理回车和换行是两个字节,并将它们作为一个字符吞下。

    【讨论】:

    • 是的,我认为你是对的;这与观察相符。我忘了考虑文本和二进制模式,如果我没记错的话,我的 fopen 默认为文本模式
    • 我会质疑“智能”一词的使用。以二进制模式自己处理\r\n 有多难?这样您就可以在系统之间获得统一的行为(例如,如果您的程序在 unix 上运行,但有人向其中抛出了一个充满 \r 的 DOS 文本文件,它仍然可以工作)。我总是选择“被认为有害的文本模式”。
    • 听起来你是在说,与其使用库的内置功能,不如自己复制它,因为这并不难。按照这个逻辑,为什么要使用任何库?
    【解决方案3】:

    Fseek 不了解文件的内容,只是将文件指针向后移动 10 个字符。

    fscanf 取决于操作系统,可能会以不同的方式解释换行符;如果您在 DOS 上并且 ^M 未出现在文件中,甚至可能 fscanf 将插入 ^M。检查 C 编译器附带的手册

    【讨论】:

      【解决方案4】:

      刚刚用VS2008试过这个,发现fscanf和fseek处理CR和LF字符的方式相同(作为单个字符)。

      所以有两个文件:

      0000000: 3132 3334 3554 3738 3930 3132 3334 3536 12345X7890123456

      0000000: 3132 3334 350d 0a37 3839 3031 3233 3435 12345..789012345

      如果我读取了 15 个字符,我会找到第二个 '5',然后再寻找 10 个字符,我读取的下一个字符是第一种情况下的 'X' 和第二种情况下的 CRLF。

      这似乎是一个非常特定于操作系统/编译器的问题。

      【讨论】:

        【解决方案5】:

        你测试fscanf的返回值了吗?贴一些代码。

        看看ungetc。你可能需要在它上面运行一个循环。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-28
          • 2018-07-07
          • 2015-10-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多