【问题标题】:fgets not reading the beginning of a linefgets 不读取行首
【发布时间】:2014-10-06 22:00:37
【问题描述】:

我在使用 fgets 从文件中读取几行文本时遇到问题。该文件是一些基本用户数据,在插件第一次启动时写入捆绑包中的文件。插件的任何后续启动都应导致用户数据被读取并交叉引用以检查用户的真实性。

数据总是3行长,用frwite完全按原样写入,用fopen打开。

我最初的理论是调用 fgets 3 次,将每一行读入它自己的 char 数组,该数组是数据结构的一部分。问题是第一行被正确读取,第二行被读取,就好像位置指示器从下一行开始但是偏移了从第 1 行读取的字符数。然后根本不读取第三行。

fgets 没有返回任何错误,并且表现得好像它已经读取了它应该拥有的数据,所以我显然遗漏了一些东西。

无论如何,这是我的代码的一部分,希望有人能对我的错误有所了解!

int length;

fgets(var.n, 128, regFile);
length = strlen(var.n);
var.n[length-1] = NULL;

fgets(var.em, 128, regFile);
length = strlen(var.em);
var.em[length-1] = NULL;

fgets(var.k, 128, regFile);
length = strlen(var.k);
var.k[length-1] = NULL;

fclose(regFile);

将每个字符串中的最后一个字符设置为 NULL 只是为了删除 /n

此代码序列输出整个第 1 行,第 2 行后半部分,第 3 行不输出。

【问题讨论】:

  • 您是否检查过该文件是否有正确的 EOL 字符? dos 文本文件与 unix 文本文件或 mac 文本文件的读取方式不同。
  • 注意:在某些情况下,strlen(var.n) --> 0var.n[length-1] = anything 是一个问题。建议检查fgets()NULL 的结果,并在执行var.n[length-1] = '\0' 之前测试length > 0
  • 1) 显示var.n 的定义。 2)次要,使用'\0',如var.em[length-1] ='\0';而不是NULL
  • var.nvar.emchar * 类型吗?
  • 可以显示文件内容吗?

标签: c macos file fgets


【解决方案1】:

感谢@alvits 对此的回答:

fwrite() 与 fgets() 不兼容。使用 fwrite() 创建的文件应该使用 fread() 来读取它们?>返回。 fwrite() 和 fread() 都在二进制流上运行,除非显式转换为 >strings。 fgets() 与 fputs() 兼容,都对字符串进行操作。

我使用 fputs() 来写入我的数据,它可以完美地读回。

【讨论】:

  • fwrite()fgets() 可以兼容。这取决于代码如何使用它们。由于该问题没有发布代码是如何编写的,因此确定写入和读取的数据之间为什么存在不兼容是一个挑战。
  • "fwrite()fread() 都对流进行操作:二进制文本。它们是对二进制流还是文本流进行操作取决于流/文件的模式被打开了,不是在什么函数上,fwrite()fgets()使用它们。当然像fwrite()这样的函数更适合二进制流和fgets()带文本流,但它们不限于那些流模式。跨度>
  • @chux 我在最初的问题中确实提到过我使用了 frwite() 但正如我在上面对 alvits 的评论中也提到的那样,我自己看不出任何合乎逻辑的原因为什么它们不兼容.我没有在对 fopen() 的调用中指定“b”标志,因此默认情况下文件应该以“文本”形式打开。除了 alvits 建议的所有这些都解决了这个问题,我所做的只是用 fputs() 替换我的 fwrite() 调用,所以它一定有一些道理。
  • 该帖子未显示如何使用fwrite()。提到代码使用 fwrite() 是不完整的。由于问题在于没有正确阅读所写的内容,因此不仅发布代码而不是阅读,而且发布编写代码是有意义的。 @alvits 的建议可能会为您解决问题,这很好。看起来你仍然不知道为什么事情失败了。如果使用工具失败,并不能证明工具是错误的,可能是工具是如何使用的问题?
【解决方案2】:

在包括 Linux 在内的 POSIX 系统中,二进制文件和文本文件没有区别。打开文件流时,b 标志被忽略。这在fopen() 中有描述。

您可能会问“如何区分文本和二进制文件?”。内容将它们区分开来。内容的编写方式使它们成为二进制文件或文本文件。

查看签名size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)。你会注意到它写了*ptr 的内容,size 描述了每个成员的大小,nmemb。写入的流不会转换为字符串。如果你要写 97,它将写二进制 97,在 ascii 中是A。二进制数据不服从字符串终止。数据中存在\n\0 是按原样写入的。

现在查看签名int fputs(const char *s, FILE *stream)。它写入*s 的字符串内容。如果你要写 97,它必须是一个字符串“97”,而不是A。遵守字符串终止。 \n 会自动转换为操作系统支持的换行符(CRLF 或 LF)。

您可以强制fwrite() 表现得像fputs(),但不能反过来。例如,如果您将ptr 声明为指向字符串的指针并计算大小与不包括字符串终止符的内容的长度完全相同,您将能够将其写为文本而不是二进制。您还需要处理 \0\n 并将它们转换为 O/S 支持的换行符。写入整个字符串缓冲区将写入包括字符串终止符在内的所有内容。

【讨论】:

  • 感谢您的解释,这很有帮助。我确切地知道现在发生了什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-21
  • 2017-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多