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

时间:2011-08-03 07:09:05

标签: c file

文件如下所示:

  

abcd
  efgh
  ijkl

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

  

ijkl
  efgh
  abcd

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

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

6 个答案:

答案 0 :(得分:9)

它是这样的:

  1. 使用fseek在文件结尾前寻找一个字节。不能保证最后一行会有EOL,所以最后一个字节并不重要。
  2. 使用fgetc读取一个字节。
  3. 如果该字节是EOL,那么最后一行是一个空行,你就拥有它。
  4. 再次使用fseek后退两个字节并使用fgetc检查该字节。
  5. 重复上述步骤直至找到EOL。当你有一个EOL时,文件指针将位于下一行(从结尾)开始。
  6. ...
  7. 利润。
  8. 基本上你一直在做(4)和(5),同时跟踪你找到一条线的开头时的位置,这样你就可以在开始扫描下一行之前找回那里。 / p>

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

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

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

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


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

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

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

答案 1 :(得分:3)

在伪代码中:

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来保存堆栈时,会发生第二个陷阱,在这种情况下,只要达到某个阈值内存使用量,就需要将堆栈结构写入临时文件。

答案 2 :(得分:1)

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

#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);
}

答案 3 :(得分:0)

以下适用于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;
}

答案 4 :(得分:0)

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

  1. 使用文件大小
  2. 定义字符串类型的变量
  3. 获取文件的内容并存储在变量
  4. 使用strrev()来反转字符串。
  5. 您可以稍后显示输出,甚至可以将其写入文件。代码如下:

    #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;
    }
    

答案 5 :(得分:0)

我知道这个问题已被 awnsered,但接受的 awnser 不包含代码片段,其他片段感觉太复杂了。 这是我的实现:

#include <stdio.h>

long file_size(FILE* f) {
    fseek(f, 0, SEEK_END); // seek to end of file
    long size = ftell(f); // get current file pointer
    fseek(f, 0, SEEK_SET); // seek back to beginning of file
    return size;
}

int main(int argc, char* argv[]) {
    FILE *in_file = fopen(argv[1], "r");
    long in_file_size = file_size(in_file);
    printf("Got file size: %ld\n", in_file_size);

    // Start from end of file
    fseek(in_file, -1, SEEK_END); // seek to end of file
    for (int i = in_file_size; i > 0; i--) {
        char current_char = fgetc(in_file); // This progresses the seek location
        printf("Got char: |%c| with hex: |%x|\n", current_char, current_char);
        fseek(in_file, -2, SEEK_CUR); // Go back 2 bytes (1 to compensate)
    }
    printf("Done\n");

    fclose(in_file);
}