2012-04-15 34 views
11

Cách hiệu quả để triển khai đuôi trong * NIX là gì? Tôi đã đưa ra (đã viết) với hai giải pháp đơn giản, cả hai đều sử dụng loại đệm tròn để tải dòng vào cấu trúc vòng tròn (mảng | gấp đôi liên kết danh sách tròn - cho vui). Tôi đã nhìn thấy một phần của việc thực hiện cũ hơn trong busybox và từ những gì tôi hiểu, họ đã sử dụng fseek để tìm EOF và sau đó đọc nội dung "ngược". Có thứ gì sạch hơn và nhanh hơn không? Tôi được hỏi về cuộc phỏng vấn và người hỏi không có vẻ hài lòng. Cảm ơn bạn trước.Bạn sẽ triển khai đuôi hiệu quả như thế nào?

+2

Tôi thích câu hỏi này vì đây là một bài học thực sự quan trọng khi học lập trình (và các công cụ hệ thống nói chung). Một số hoạt động chỉ vốn có * không thể thực hiện hiệu quả *, ít nhất không được biểu diễn chuẩn của dữ liệu bạn đang làm việc (trong trường hợp này, một tệp luồng byte tuyến tính bắt đầu từ đầu). Học cách nhận ra điều này đơn giản từ định dạng dữ liệu, và để tránh ghép nối dữ liệu và các hoạt động không thể hoạt động hiệu quả với nhau, là một phần quan trọng trong việc học viết phần mềm hiệu quả. –

Trả lời

14

Tôi không nghĩ có các giải pháp khác với "giữ N dòng mới nhất trong khi đọc chuyển tiếp dữ liệu" hoặc "bắt đầu từ đầu và lùi lại cho đến khi bạn đọc dòng thứ N".

Vấn đề là bạn nên sử dụng cái này hoặc cái khác dựa trên ngữ cảnh.

"Đi tới cuối và lùi" sẽ tốt hơn khi đuôi truy cập tệp truy cập ngẫu nhiên hoặc khi dữ liệu đủ nhỏ để đặt vào bộ nhớ. Trong trường hợp này thời gian chạy được giảm thiểu, vì bạn quét dữ liệu phải được xuất ra (vì vậy, nó "tối ưu")

Giải pháp của bạn (giữ N dòng mới nhất) tốt hơn khi đuôi được cho ăn bằng đường ống hoặc khi dữ liệu lớn. Trong trường hợp này, các giải pháp khác lãng phí quá nhiều bộ nhớ, do đó, nó không phải là thực tế và, trong trường hợp nguồn là chậm hơn đuôi (có thể xảy ra) quét tất cả các tập tin không quan trọng mà nhiều.

6

Đọc ngược từ cuối tệp đến khi N ngắt dòng được đọc hoặc bắt đầu tệp.

Sau đó in nội dung vừa đọc.

Tôi không nghĩ rằng bất kỳ cơ sở dữ liệu ưa thích nào là cần thiết ở đây.

Here is the source code of tail nếu bạn quan tâm.

0

/*This example implements the option n of tail command.*/

#define _FILE_OFFSET_BITS 64 
#include <stdio.h> 
#include <stdlib.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <unistd.h> 
#include <getopt.h> 

#define BUFF_SIZE 4096 

FILE *openFile(const char *filePath) 
{ 
    FILE *file; 
    file= fopen(filePath, "r"); 
    if(file == NULL) 
    { 
    fprintf(stderr,"Error opening file: %s\n",filePath); 
    exit(errno); 
    } 
    return(file); 
} 

void printLine(FILE *file, off_t startline) 
{ 
    int fd; 
    fd= fileno(file); 
    int nread; 
    char buffer[BUFF_SIZE]; 
    lseek(fd,(startline + 1),SEEK_SET); 
    while((nread= read(fd,buffer,BUFF_SIZE)) > 0) 
    { 
    write(STDOUT_FILENO, buffer, nread); 
    } 
} 

void walkFile(FILE *file, long nlines) 
{ 
    off_t fposition; 
    fseek(file,0,SEEK_END); 
    fposition= ftell(file); 
    off_t index= fposition; 
    off_t end= fposition; 
    long countlines= 0; 
    char cbyte; 

    for(index; index >= 0; index --) 
    { 
    cbyte= fgetc(file); 
    if (cbyte == '\n' && (end - index) > 1) 
    { 
     countlines ++; 
     if(countlines == nlines) 
     { 
    break; 
     } 
    } 
    fposition--; 
    fseek(file,fposition,SEEK_SET); 
    } 
    printLine(file, fposition); 
    fclose(file); 
} 

int main(int argc, char *argv[]) 
{ 
    FILE *file; 
    file= openFile(argv[2]); 
    walkFile(file, atol(argv[1])); 
    return 0; 
} 

/*Note: take in mind that i not wrote code to parse input options and arguments, neither code to check if the lines number argument is really a number.*/ 
5

đầu tiên sử dụng fseek để tìm các tập tin end-of-sau đó trừ đi 512 và fseek để mà bù đắp, sau đó đọc về phía trước từ đó đến cuối. Đếm số lần ngắt dòng vì nếu có quá ít, bạn sẽ phải thực hiện tương tự với khoản chênh lệch trừ là 1024 ... nhưng trong 99% trường hợp 512 sẽ là đủ.

này (1) tránh đọc toàn bộ tập tin phía trước và (2) lý do tại sao điều này có lẽ hiệu quả hơn đọc ngược từ cuối cùng là đọc về phía trước thường là nhanh hơn.

+0

và tăng gấp đôi mức bù trừ mỗi lần không thành công. –

Các vấn đề liên quan