是否可以从下往上遍历文件? [C]

时间:2013-04-27 23:40:31

标签: c file traversal

如何从下往上逐行遍历文件?例如,这是我从上到下遍历它的代码:

void *readFileTB(char *str1)
{
    int size = 1024;
    char *buffer = malloc(size);
    FILE *fp;
    fp = fopen("testfile.txt", "r");
    while(fgets(buffer, 1024, fp)) //get a line from a file
    {
            printf(buffer);
    }
    return 0;
}

如果文件包含:

line1onetest
line2twotest
line3threetest

如果执行此功能将打印以下内容:

line1onetest
line2twotest
line3threetest

如何编写一个执行上述功能但功能相反的函数,以便输出以下内容?

line3threetest
line2twotest
line1onetest

有什么想法吗?

3 个答案:

答案 0 :(得分:5)

一行一行有点困难。如果我们从字节开始,那很简单:我们首先fseek到底部之前一点:

if(fseek(fp, 256, SEEK_END) == -1) { /* handle error */ }

由于我们在结束之前寻找了256个字节,因此我们可以读取256个字节。然后我们可以回寻256个字节等,直到我们到达文件的顶部。

现在,如果您正在尝试读取文本行,这可能很棘手:您需要在文件末尾读取一些字节并找到最后一个换行符。如果没有,你就读不够,你需要阅读更多内容。一旦你找到它,你的线就从那里开始。要阅读下一行,您需要再次向后搜索,并且不要超过上一行开头。

答案 1 :(得分:4)

在这里,我对它进行了一些编码并对整个事情进行了编码。我不知道它是否有任何好处,但至少你可以了解它是如何工作的。 (我觉得有更好的方法可以做到这一点)

编译和使用程序:

$ gcc -Wall -o reverser main.c

<强>用法:

$ ./reverser text.txt

text.txt内容:

int main(int argc, char *argv[]){
    if(argc != 2)
        return 1;

    print_rev_file(argv[1], 64);

    return 0;
}

结果:

}
    return 0;

    print_rev_file(argv[1]);

        return 1;
    if(argc != 2)
int main(int argc, char *argv[]){

如何在代码中使用

<强>的main.c

#include <header.h>

int main(int argc, char *argv[]){
    if(argc != 2)
        return 1;

    print_rev_file(argv[1], 64);

    return 0;
}

<强> header.h: 注意:使用双下划线是不好的形式,因为许多编译器都使用它们。

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>

///SUPPORT for get_line

size_t __file_size(FILE ** file); //It'd make sense to homogenize the parameters...
char * __get_line_copy(FILE ** file, size_t chunk_size, size_t position);
char * __get_line(int line_number, FILE ** file, size_t chunk_size);
size_t __nth_line(FILE ** file, int line_number, size_t chunk_size);
unsigned int __line_count(FILE ** file, size_t chunk_size);

#define file_size(x) __file_size(&x)
size_t __file_size(FILE ** file){
    size_t old_pos = ftell(*file);

    fseek(*file, 0, SEEK_END);
    int file_size = ftell(*file);

    fseek(*file, 0, old_pos);
    return file_size;
}

char * __get_line_copy(FILE ** file, size_t chunk_size, size_t position){
    int i;
    char c;
    char * buffer = malloc(chunk_size);
    memset(buffer, 0, chunk_size);

    size_t old_pos = ftell(*file);
    fseek(*file, position, SEEK_SET);

    for(i = 0; (i < chunk_size && (c = fgetc(*file)) != '\n' && !feof(*file)); i++){
        *(buffer+i) = c;
    }

    *(buffer+chunk_size) = '\0';

    fseek(*file, 0, old_pos);
    return buffer;
}

#define FIRST 0
#define LAST -1
#define get_line(x, y, z) __get_line(x, &y, z);

char * __get_line(int line_number, FILE ** file, size_t chunk_size){
    char * line = __get_line_copy(file, chunk_size, __nth_line(file, line_number, chunk_size));

    return line;
}

size_t __nth_line(FILE ** file, int line_number, size_t chunk_size){
    int i = 0, index;
    size_t old_pos = ftell(*file);
    fseek(*file, 0, SEEK_SET);

    if(line_number > 0){
        while(i <= line_number && !feof(*file)){
            if(fgetc(*file) == '\n')
                i++;
        }
    } else {
        while(!feof(*file)){
            if(fgetc(*file) == '\n')
                i++;
        }

        index = i + (line_number+1);
        fseek(*file, 0, SEEK_SET);
        int i = 0;

        while(i < index){
            if(fgetc(*file) == '\n')
                i++;
        }
    }

    size_t position = ftell(*file);

    fseek(*file, 0, old_pos);
    return position;
}

#define line_count(x, y) __line_count(&x, y)
unsigned int __line_count(FILE ** file, size_t chunk_size){
    int i = 1;

    while(!feof(*file))
        if(fgetc(*file) == '\n')
            i++;

    return i;
}

int print_rev_file(char * filename, size_t buffer){
    FILE * file = fopen(filename, "r");
    if(file == NULL){
        return -1;
    }

    int i, lines = line_count(file, buffer);
    for(i = 0; i < lines; i++){
        char * line = get_line(LAST-i, file, buffer);
        puts(line);
        free(line);
    }


    return 0;
}

int main(int argc, char *argv[]){
    if(argc != 2)
        return 1;

    print_rev_file(argv[1], 64);

    return 0;
} 

答案 2 :(得分:1)

GNU coreutils中有一个名为 tac 的实用程序就是这样做的。

您可以在下面查看它的来源。

http://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=blob_plain;f=src/tac.c;hb=HEAD