2016-01-18 5 views
1

Я работаю над реализацией функции хвоста, и я должен использовать только read(), write() и lseek() для ввода-вывода, и до сих пор у меня есть это:Печать последних 10 строк файла или stdin с чтением и lseek

int printFileLines(int fileDesc) 
{ 
    char c; 
    int lineCount = 0, charCount = 0; 
    int pos = 0, rState; 
    while(pos != -1 && lineCount < 10) 
    { 
     if((rState = read(fileDesc, &c, 1)) < 0) 
     { 
      perror("read:"); 
     } 
     else if(rState == 0) break; 
     else 
     { 
      if(pos == -1) 
      { 
       pos = lseek(fileDesc, 0, SEEK_END); 
      } 
      pos--; 
      pos=lseek(fileDesc, pos, SEEK_SET); 
      if (c == '\n') 
      { 
       lineCount++; 
      } 
      charCount++; 
     } 
    } 

    if (lineCount >= 10) 
     lseek(fileDesc, 2, SEEK_CUR); 
    else 
     lseek(fileDesc, 0, SEEK_SET); 

    char *lines = malloc(charCount - 1 * sizeof(char)); 

    read(fileDesc, lines, charCount); 
    lines[charCount - 1] = 10; 
    write(STDOUT_FILENO, lines, charCount); 

    return 0; 
} 

до сих пор он работает для файлов, которые имеют более чем 10 строк, но тормоза, когда я передать файл с менее чем 10 строк, он просто печатает последнюю строку этого файла, и я могу» t получить его для работы с stdin. Если кто-то может дать мне представление о том, как исправить эти проблемы, что было бы здорово: D

ответ

2

Первый выпуск:

Если вы читаете строку здесь ...

if(read(fileDesc, &c, 1) < 0) 
{ 
    perror("read:"); 
} 

... и затем установить позицию непосредственно к символу предыдущего, что символ новой строки ...

pos--; 
pos=lseek(fileDesc, pos, SEEK_SET); 

, а затем linecount - >= 10 (цикл while завершается), то первый символ, который вы читаете, является последним символом строки, предшествующей последней строке новой строки. Сам символ новой строки также не является частью последних 10 строк, так что просто пропустить два символа из текущей позиции потока на:

if (linecount >= 10) 
    lseek(fileDesc, 2, SEEK_CUR); 

Для второго выпуска:

Давайте предположим, что поток смещение достигло начало потока:

pos--; 
pos=lseek(fileDesc, pos, SEEK_SET); // pos is now 0 

пока условие остается в силе:

while(pos != -1 && lineCount < 10) 

Теперь читается символ. После этого файл смещение (второй символ):

if(read(fileDesc, &c, 1) < 0) 
{ 
    perror("read:"); 
} 

Здесь поз падает до -1 и lseek будет неудачу:

pos--; 
pos=lseek(fileDesc, pos, SEEK_SET); 

Поскольку lseek не удалось, то в файле теперь находится второй символ, поэтому первый символ отсутствует. Исправить это путем сброса смещения файла в начало файла, если pos == -1 после While-цикла:

if (linecount >= 10) 
    lseek(fileDesc, 2, SEEK_CUR); 
else 
    lseek(fileDesc, 0, SEEK_SET); 

Производительности:

Это требует очень много системных вызовов. Легко повышение будет использовать буферизованные F * -функции:

FILE *f = fdopen(fileDesc, "r"); 
fseek(...); 
fgetc(...); 

и т.д. Кроме того, это не требует специальных системных функций.

Еще лучше было бы прочитать фрагмент файла назад на куске и работать с этими кусками, но для этого требуется еще некоторое усилие кодирования.

Для Unix вы можете также mmap() весь файл и искать назад в памяти для символов новой строки.

+0

Спасибо !!!!!!!! Я боролся с этим часами! На заметку о производительности я бы даже не использовал эти функции, но этот черт возьми человек ... – Reaper9806