C语言 向后读取文件(最后一行在前)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6922829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
read file backwards (last line first)
提问by hari
file looks like this:
文件如下所示:
abcd
efgh
ijkl
abcd
efgh
ijkl
I want to read the file using Cso that it read the last line first:
我想使用读取文件,C以便它首先读取最后一行:
ijkl
efgh
abcd
ijkl
efgh
abcd
I cannot seem to find a solution that does not use an arrayfor storage. Please help.
我似乎找不到不使用array存储的解决方案。请帮忙。
edit0:Thanks for all the answers. Just to let you know, I am the one creating this file. So, can I create in a way its in the reverse order? Is that possible?
编辑0:感谢所有的答案。只是为了让您知道,我是创建此文件的人。那么,我可以以相反的顺序创建吗?那可能吗?
回答by mu is too short
It goes like this:
它是这样的:
- Seek to one byte before the end of the file using
fseek. There's no guarantee that the last line will have an EOL so the last byte doesn't really matter. - Read one byte using
fgetc. - If that byte is an EOL then the last line is a single empty line and you have it.
- Use
fseekagain to go backwards two bytes and check that byte withfgetc. - Repeat the above until you find an EOL. When you have an EOL, the file pointer will be at the beginning of the next (from the end) line.
- ...
- Profit.
- 使用
fseek.在文件结束前查找一个字节。不能保证最后一行会有 EOL,所以最后一个字节并不重要。 - 使用 读取一个字节
fgetc。 - 如果该字节是 EOL,那么最后一行是一个空行,您就拥有它。
fseek再次使用向后移动两个字节并使用fgetc.- 重复以上操作,直到找到 EOL。当您有 EOL 时,文件指针将位于下一行(从末尾开始)的开头。
- ...
- 利润。
Basically you have keep doing (4) and (5) while keeping track of where you were when you found the beginning of a line so that you can seek back there before starting your scan for the beginning of the next line.
基本上,您一直在执行 (4) 和 (5),同时跟踪您找到一行开头时所处的位置,以便您可以在开始扫描下一行开头之前返回那里。
As long as you open your file in text mode you shouldn't have have to worry about multibyte EOLs on Windows (thanks for the reminder Mr. Lutz).
只要您以文本模式打开文件,您就不必担心 Windows 上的多字节 EOL(感谢 Lutz 先生的提醒)。
If you happen to be given a non-seekable input (such as a pipe), then you're out of luck unless you want to dump your input to a temporary file first.
如果您碰巧获得了不可搜索的输入(例如管道),那么除非您想先将输入转储到临时文件,否则您就不走运了。
So you can do it but it is rather ugly.
所以你可以这样做,但它相当丑陋。
You could do pretty much the same thing using mmapand a pointer if you have mmapavailable and the "file" you're working with is mappable. The technique would be pretty much the same: start at the end and go backwards to find the end of the previous line.
mmap如果您有mmap可用的并且您正在使用的“文件”是可映射的,您可以使用和 指针来做几乎相同的事情。该技术几乎相同:从末尾开始,然后向后查找前一行的末尾。
Re: "I am the one creating this file. So, can I create in a way its in the reverse order? Is that possible?"
回复:“我是创建这个文件的人。所以,我可以以相反的顺序创建它吗?这可能吗?”
You'll run into the same sorts of problems but they'll be worse. Files in C are inherently sequential lists of bytes that start at the beginning and go to the end; you're trying to work against this fundamental property and going against the fundamentals is never fun.
你会遇到同样的问题,但它们会更糟。C 中的文件本质上是从开头开始到结尾的字节顺序列表;你试图违背这个基本属性,违背基本原则从来都不是一件有趣的事情。
Do you really need your data in a plain text file? Maybe you need text/plain as the final output but all the way through? You could store the data in an indexed binary file (possibly even an SQLite database) and then you'd only have to worry about keeping (or windowing) the index in memory and that's unlikely to be a problem (and if it is, use a "real" database); then, when you have all your lines, just reverse the index and away you go.
您真的需要纯文本文件中的数据吗?也许你需要 text/plain 作为最终输出,但一直都在?您可以将数据存储在索引的二进制文件(甚至可能是 SQLite 数据库)中,然后您只需担心将索引保留(或窗口化)在内存中,这不太可能成为问题(如果是,请使用一个“真实”的数据库);然后,当您拥有所有线条时,只需反转索引即可。
回答by Skizz
In pseudocode:
在伪代码中:
open input file
while (fgets () != NULL)
{
push line to stack
}
open output file
while (stack no empty)
{
pop stack
write popped line to file
}
The above is efficient, there is no seek (a slow operation) and the file is read sequentially. There are, however, two pitfalls to the above.
以上是高效的,没有seek(慢操作)并且文件是顺序读取的。然而,上面有两个陷阱。
The first is the fgetscall. The buffer supplied to fgetsmay not be big enough to hold a whole line from the input in which case you can do one of the following: read again and concatenate; push a partial line and add logic to the second half to fix up partial lines or wrap the line into a linked list and only push the linked list when a newline/eof is encountered.
第一个是fgets调用。提供给的缓冲区fgets可能不足以容纳来自输入的整行,在这种情况下,您可以执行以下操作之一:再次读取并连接;推送部分行并将逻辑添加到后半部分以修复部分行或将行包装到链表中,并且仅在遇到换行符/ eof 时才推送链表。
The second pitfall will happen when the file is bigger than the available ram to hold the stack, in which case you'll need to write the stack structure to a temporary file whenever it reaches some threshold memory usage.
当文件大于用于保存堆栈的可用 ram 时,将发生第二个陷阱,在这种情况下,只要达到某个阈值内存使用量,您就需要将堆栈结构写入临时文件。
回答by Shehbaz Jaffer
The following code should do the necessary inversion:
下面的代码应该做必要的反转:
#include <stdio.h>
#include <stdlib.h>
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);
}
回答by Niamatullah Bakhshi
Maybe , The does the trick , It reverse content of the file in whole just like a string
也许,这有窍门,它就像一个字符串一样反转整个文件的内容
- Define a variable of type string with size of your file
- Get Contents of the file and store in the variable
- Use strrev() to reverse the string.
- 使用文件大小定义字符串类型的变量
- 获取文件内容并存储在变量中
- 使用 strrev() 反转字符串。
You can later on display the output or even write it to a file. The code goes like this:
您可以稍后显示输出,甚至可以将其写入文件。代码是这样的:
#include <stdio.h>
#include <String.h>
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;
}
回答by Bertrand
The following works for me on Linux, where the text file line separator is "\n".
以下在 Linux 上对我有用,其中文本文件行分隔符是“\n”。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}

