我正在尝试学习C,目前正在制作一个玩具脚本。 现在,它只是打开一个文本文件,通过char读取它,并且 将它吐出到命令行。
我查看了如何查看文件的大小(使用fseek()然后使用ftell()), 但是当我遍历文件时,它返回的结果与我在while循环中计算字符所获得的数字不匹配。
我想知道这种差异是由于Windows使用\ r \ n而不仅仅是\ n,因为差异似乎是#newlines + 1。
以下是我正在处理的脚本:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE * fp = fopen("test.txt", "r");
fseek(fp, 0, SEEK_END);
char * stringOfFile = malloc(ftell(fp));
printf("allocated %d characters for file\n", ftell(fp));
fseek(fp,0,SEEK_SET);//reset pointer
char tmp = getc(fp); //current letter in file
int i=0;
while (tmp != EOF) //End-Of-File (defined in stdio.h)
{
*(stringOfFile+i) = tmp;
tmp = getc(fp);
i++;
}
fclose(fp);
printf("Turns out we had %d characters to store.\nThe file was as follows:\n", i);
printf("%s", stringOfFile);
}
我得到的输出(你可以从输出中看到一个简单的测试文件):
allocated 67 characters for file
Turns out we had 60 characters to store.
The file was as follows:
line1
line2
line3
line4
line5
(last)line6
lmnopqrstuvw▬$YL Æ
其中打印的尾部比特似乎是垃圾而不是为字符串分配太多内存。
提前感谢您提供的任何帮助/答案!
答案 0 :(得分:3)
如果您正在运行Windows:
FILE * fp = fopen("test.txt", "r");
以 text 模式打开文件,这意味着\r\n
转换为\n
因此,如果您的文件有7行,则转换将删除7个字符(即,如果文件使用Windows样式的行终止)
修复是以二进制模式打开它
FILE * fp = fopen("test.txt", "rb");
所以ftell
和逐个阅读字符应匹配。
当然,这是浪费空间和在你的文本中使用\r
字符不是很方便,所以你可以像你正在做的那样进行分配,并最终执行realloc
以使用实际的字符数减少分配的内存(从那以后)它更小,没关系)
stringOfFile = realloc(stringOfFile,i+1);
请注意,由于我已经考虑了添加nul-terminator的需要,因此我在chars的数量上加了1,所以如果文件中没有\r
个字符,那么realloc
可以将块的大小增加1。
所以,正如我所暗示的那样,不要忘记终止你的字符串或printf
没有正确停止:
stringOfFile[i] = '\0';
(除非你不关心创建一个C字符串,因为存储字符串大小+显示char-by-char也是正确的)
我们已经看到ftell
方法很棘手,在某些情况下,当流是例如命令的输出时(popen
返回FILE *
但你不能fseek
它或者套接字,无论如何,由于我们事先不知道数据的大小,所以不能应用这个原则。
在一般情况下,最好是:
realloc
以增加一些步骤的大小(不是每个字符,性能都会很差)realloc
以更精确地调整尺寸(它也透明地解决了二进制/文本问题)
请注意,如果您使用的是大型文件(> 4GB),则必须使用64位无符号整数作为位置和fopen64
种I / O函数(以及所有偏移变量,如{{1}应该是unsigned /符合i
的返回类型,否则你将开始遇到2GB的问题。好吧,我想在处理适度小的文本文件时并不重要。
另外,检查大卫回答。对于文本文件,将ftell
的结果放在getc
中应该有效,但在二进制文件的一般情况下则不行。
答案 1 :(得分:1)
char tmp = getc(fp); //current letter in file
int i=0;
while (tmp != EOF) //End-Of-File (defined in stdio.h)
您需要检查getc
为EOF
返回的值。相反,您将其转换为char
,然后检查是否等于EOF
转换为char
。但是如果转换为char
的{{1}}的值实际上在文件中呢?检查文档,EOF
返回getc
。
你也有其他错误。