2013-04-27 61 views
1

如何從下往上逐行遍歷文件?例如,這裏是我的代碼從頂部穿過它底:是否可以從下往上遍歷文件? [C]

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 

有什麼想法?

+1

void *函數總是返回0; ? erm?.... – 2013-04-27 23:42:05

+0

@MitchWheat:'0'是寫'NULL'的有效方法。 – icktoofay 2013-04-27 23:44:25

+0

@icktoofay:是的,我知道! 20年的C開發人員會教我的驚人之作! – 2013-04-27 23:45:26

回答

5

一行一行有點困難。如果我們開始與字節,這是很簡單的:我們首先fseek到一點底前:

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

由於我們已經在年底前seeked 256個字節,我們可以讀取256個字節。然後我們可以追回256個字節等等,直到我們達到文件的頂部。

現在,如果您嘗試讀取文本行,這可能會非常棘手:您需要在文件末尾讀取大量字節並找到最後一個換行符。如果沒有,你沒有足夠的閱讀,你需要閱讀更多。一旦你找到它,你的線路就從那裏開始。要閱讀下一行,您需要再次向後尋找,並且不要超過您之前的行開始。

4

在這裏,我有點爲它和編碼的整個事情。我不知道它是否有用,但至少你可以知道它是如何工作的。 (我有一種感覺,有更好的方法來做到這一點)

編譯和使用程序:

$ gcc -Wall -o reverser main.c

用法:

$ ./reverser text.txt

文本。 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; 
}