1

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

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

有什么想法吗?

4

3 回答 3

5

一行一行的有点难。如果我们从字节开始,这很简单:我们先到fseek底部一点:

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

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

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

于 2013-04-27T23:44:05.707 回答
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[]){

如何在代码中使用:

主程序

#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;
} 
于 2013-04-28T02:20:53.330 回答
1

GNU coreutils 中有一个名为tac的实用程序可以做到这一点。

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

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

于 2013-04-28T00:11:14.553 回答