【问题标题】:y with umlaut in filey 文件中有变音符号
【发布时间】:2019-05-15 21:12:44
【问题描述】:

我正在处理一个示例问题,我必须使用 fseek() 和 ftell() 反转文本文件中的文本。我成功了,但是将相同的输出打印到文件中,我得到了一些奇怪的结果。 我输入的文本文件如下:

再分配器
赛车
皮划艇
公民
等级
参考
这些都是回文

命令行中的结果效果很好。然而,在我创建的文本文件中,我得到以下内容:

ÿsemordnilap lla 时代 esehTT
推荐人
等级
公民
皮划艇
赛车手
重新划分

我从this question 的回答中知道这对应于 C 中 EOF 的文本文件版本。我只是对为什么命令行和文本文件输出不同感到困惑。

#include <stdio.h>
#include <stdlib.h>

/**********************************
This program is designed to read in a text file and then reverse the order 
of the text.
The reversed text then gets output to a new file.
The new file is then opened and read.
**********************************/

int main()
{
    //Open our files and check for NULL
    FILE *fp = NULL;
    fp = fopen("mainText.txt","r");
    if (!fp)
        return -1;

    FILE *fnew = NULL;
    fnew = fopen("reversedText.txt","w+");
    if (!fnew)
        return -2;

    //Go to the end of the file so we can reverse it
    int i = 1;
    fseek(fp, 0, SEEK_END);
    int endNum = ftell(fp);
    while(i < endNum+1)
    {
        fseek(fp,-i,SEEK_END);
        printf("%c",fgetc(fp));
        fputc(fgetc(fp),fnew);
        i++;
    }

    fclose(fp);
    fclose(fnew);
    fp = NULL;
    fnew = NULL;

    return 0;
}

没有错误,我只想要相同的输出。

【问题讨论】:

  • 换行符可能会占用文件中的两个字符。
  • ÿ 是特殊的,字符代码 0xff。获得它的最简单方法是将 EOF 转换或打印到字符。

标签: c eof fseek ftell


【解决方案1】:

输出不同,因为您的循环每次迭代都会从 fp 读取两个字符。

例如,在第一次迭代中,i1,因此fseekfp 的当前文件位置设置在最后一个字节之前:

...
These are all palindromes
                        ^

然后printf("%c",fgetc(fp)); 读取一个字节(s)并将其打印到控制台。读过s,文件位置现在是

...
These are all palindromes
                         ^

即我们在文件的末尾。

然后fputc(fgetc(fp),fnew); 尝试从fp 读取另一个字节。这失败了,fgetc 返回EOF(一个负值,通常是-1)。但是,您的代码并没有为此做好准备,并且盲目地将-1 视为字符代码。转换为字节,-1对应255,也就是ÿ在ISO-8859-1编码中的字符码。这个字节被写入你的文件。

在循环的下一次迭代中,我们回溯到e

...
These are all palindromes
                       ^

循环再次读取两个字符:e 写入控制台,s 写入文件。

这将继续向后直到我们到达输入文件的开头:

redivider
^

循环再次读取两个字符:r 被写入控制台,e 被写入文件。

这结束了循环。最终结果是您的输出文件包含一个不存在的字符(从尝试读取输入文件末尾之后)并且永远不会看到第一个字符。

解决方法是每个循环只调用一次fgetc

while(i < endNum+1)
{
    fseek(fp,-i,SEEK_END);
    int c = fgetc(fp);
    if (c == EOF) {
        perror("error reading from mainText.txt");
        exit(EXIT_FAILURE);
    }
    printf("%c", c);
    fputc(c, fnew);
    i++;
}

【讨论】:

    【解决方案2】:

    除了@melpomene 更正关于每个循环仅使用 1 个fgetc() 之外,还存在其他问题。

    fseek(questionable_offset)

    fopen("mainText.txt","r");text 模式而不是 binary 模式打开文件。因此,使用fseek(various_values) 作为文件的有效偏移量很容易出现问题。在 *nix 系统中通常不是问题。

    我没有简单的选择。

    ftell() 返回类型

    ftell() 返回long。使用long 而不是int i, endNum。 (与小文件无关)

    检查返回值

    ftell()fseek() 可能会失败。测试错误返回。

    【讨论】:

    • 是的,ftell 不需要在文本模式下返回文件偏移量。它理论上可以只返回fseek 理解的任意值(但不允许任何有意义的算术)。
    猜你喜欢
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    • 2018-07-16
    • 1970-01-01
    • 2020-04-30
    • 2011-08-13
    • 2016-01-21
    相关资源
    最近更新 更多