1

ファイルを下から 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[]){

コードでの使用方法:

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: 注: 多くのコンパイラが使用しているため、2 つのアンダースコアを使用するのは不適切な形式です。

#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

まさにそれを行う tacと呼ばれる GNU coreutils のユーティリティがあります。

以下のソースを表示できます。

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

于 2013-04-28T00:11:14.553 に答える