向后读取文件(最后一行)

文件看起来像这样:

A B C D
EFGH
IJKL

我想用C读取文件,以便它首先读取最后一行:

IJKL
EFGH
A B C D

我似乎无法找到不使用array进行存储的解决方案。 请帮忙。

edit0:谢谢你的所有答案。 只是为了让您知道,我是创建此文件的人。 那么,我可以以相反的顺序创建它吗? 那可能吗?

它是这样的:

  1. 使用fseek在文件结尾前寻找一个字节。 不能保证最后一行会有EOL,所以最后一个字节并不重要。
  2. 使用fgetc读取一个字节。
  3. 如果该字节是EOL,那么最后一行是一个空行而你拥有它。
  4. 再次使用fseek向后移动两个字节并使用fgetc检查该字节。
  5. 重复上述步骤,直到找到EOL。 当您有EOL时,文件指针将位于下一行(从结尾)行的开头。
  6. 利润。

基本上你一直在做(4)和(5),同时跟踪你找到一条线的开始时的位置,这样你就可以在开始扫描下一行之前找回那里。

只要您在文本模式下打开文件,您就不必担心Windows上的多字节EOL(感谢提示Lutz先生)。

如果您碰巧得到了一个不可搜索的输入(例如管道),那么除非您想先将输入转储到临时文件,否则您运气不佳。

所以你可以做到,但它相当难看。

如果你有mmap可用,并且你正在使用的“文件”是可映射的,你可以使用mmap和指针做同样的事情。 这种技术几乎是一样的:从最后开始然后向后找到前一行的结尾。


回复:“我是创建这个文件的人。所以,我可以以相反的顺序创建它吗?这可能吗?”

你会遇到同样的问题,但情况会更糟。 C中的文件本质上是连续的字节列表,从开头开始到结尾; 你正试图反对这个基本的财产,反对基本面是没有乐趣的。

您真的需要纯文本文件中的数据吗? 也许你需要text / plain作为最终输出但是一直都是如此? 您可以将数据存储在索引的二进制文件(甚至可能是SQLite数据库)中,然后您只需要担心将索引保留(或窗口化)在内存中并且这不太可能是一个问题(如果是,请使用一个“真正的”数据库); 然后,当你拥有所有的线条时,只需反转索引即可离开。

在伪代码中:

 open input file while (fgets () != NULL) { push line to stack } open output file while (stack no empty) { pop stack write popped line to file } 

以上是有效的,没有搜索(慢速操作)并且文件被顺序读取。 然而,上面有两个陷阱。

第一个是fgets电话。 提供给fgets的缓冲区可能不够大,无法从输入中保存整行,在这种情况下,您可以执行以下操作之一:再次读取并连接; 推送部分行并向后半部分添加逻辑以修复部分行或将行包装到链接列表中,并仅在遇到换行符/ eof时推送链接列表。

当文件大于可用ram来保存堆栈时,会发生第二个陷阱,在这种情况下,只要达到某个阈值内存使用量,就需要将堆栈结构写入临时文件。

以下代码应执行必要的反转:

 #include  #include  int main(int argc, char *argv[]) { FILE *fd; char len[400]; int i; char *filename = argv[1]; int ch; int count; fd = fopen(filename, "r"); fseek(fd, 0, SEEK_END); while (ftell(fd) > 1 ){ fseek(fd, -2, SEEK_CUR); if(ftell(fd) <= 2) break; ch =fgetc(fd); count = 0; while(ch != '\n'){ len[count++] = ch; if(ftell(fd) < 2) break; fseek(fd, -2, SEEK_CUR); ch =fgetc(fd); } for (i =count -1 ; i >= 0 && count > 0 ; i--) printf("%c", len[i]); printf("\n"); } fclose(fd); } 

以下适用于Linux,其中文本文件行分隔符为“\ n”。

 #include  #include  #include  void readfileinreverse(FILE *fp) { int i, size, start, loop, counter; char *buffer; char line[256]; start = 0; fseek(fp, 0, SEEK_END); size = ftell(fp); buffer = malloc((size+1) * sizeof(char)); for (i=0; i< size; i++) { fseek(fp, size-1-i, SEEK_SET); buffer[i] = fgetc(fp); if(buffer[i] == 10) { if(i != 0) { counter = 0; for(loop = i; loop > start; loop--) { if((counter == 0) && (buffer[loop] == 10)) { continue; } line[counter] = buffer[loop]; counter++; } line[counter] = 0; start = i; printf("%s\n",line); } } } if(i > start) { counter = 0; for(loop = i; loop > start; loop--) { if((counter == 0) && ((buffer[loop] == 10) || (buffer[loop] == 0))) { continue; } line[counter] = buffer[loop]; counter++; } line[counter] = 0; printf("%s\n",line); return; } } int main() { FILE *fp = fopen("./1.txt","r"); readfileinreverse(fp); return 0; } 

也许,诀窍就是这样,它就像一个字符串一样反转整个文件的内容

  1. 使用文件大小定义字符串类型的变量
  2. 获取文件的内容并存储在变量中
  3. 使用strrev()来反转字符串。

您可以稍后显示输出,甚至可以将其写入文件。 代码如下:

 #include  #include  int main(){ FILE *file; char all[1000]; // give any name to read in reverse order file = fopen("anyFile.txt","r"); // gets all the content and stores in variable all fscanf(file,"%[]",all); // Content of the file printf("Content Of the file %s",all); // reverse the string printf("%s",strrev(all)); fclose(file); return 0; }