Программа не работает для больших файлов на C

#c #file #fopen

#c #файл #открыть

Вопрос:

Я использую следующую программу на C для фильтрации файла журнала, содержащего около 200 000 строк. Но программа перестает отвечать примерно через 12000 строк. Любые объяснения, почему это происходит, и любое решение для этого? Код скомпилирован в GCC (Windows).

PS: Код выполняется правильно и выдает желаемый результат для небольших файлов.

 #include<stdio.h>
#include<string.h>

int check(char *url)
{
    //some code to filter the data and return either 0 or 1 depending upon input
}

int main()
{
    FILE *fpi, *fpo;
    fpi=fopen("access.log","r");
    fpo=fopen("edited\filter.txt","w");
    char date[11],time[9],ip[16],url[500],temp[3];
    while(!feof(fpi))
    {
        printf(".");
        fscanf(fpi," %s %s %s %s %s %s",date,time,temp,ip,temp,url);
        if(check(url)) 
            fprintf(fpo,"%s %s %s %s %s %sn",date,time,temp,ip,temp,url);
    }
    fclose(fpi);
    fclose(fpo);
    printf("nnnDONE! :)");
    return 0;
}
  

Комментарии:

1. Вы уверены, что формат файла правильный? fscanf не допускает никаких отклонений. Попробуйте удалить первые 12000 строк, чтобы увидеть, есть ли проблема в данных. Также попробуйте увеличить размеры вашего буфера.

2. Черт возьми, это звучит как работа для awk .

3. О да, я увеличил размер буфера и его работоспособность… Спасибо

Ответ №1:

Возможно, что одна из строк во входном файле содержит поле, размер которого превышает размер передаваемой вами строковой переменной fscanf() . Это может привести к переполнению буфера, что позже приведет к бесконечному циклу где-нибудь. Просто предположение. Я предлагаю вам разделить %s в fscanf() строке формата максимальную длину выходной строковой переменной.

Например, это гарантирует отсутствие переполнения буфера и завершение результирующих строк:

  fscanf(fpi," s %8s %2s s Is %2s", date, time, temp, ip, temp, url);
 date[10] = '';
 time[8] = ''; 
 ip[15] = ''; 
 temp[2] = ''; 
 url[499] = ''; 
  

Кроме того, вы дважды считываете temp. Последнее чтение переопределит первое. Это то, что вы имели в виду?

Другое улучшение, предполагающее, что входной файл заканчивается строкой, а каждый журнал находится в отдельной строке, заключается в использовании fgets() для чтения строки и только затем использования sscanf() в промежуточном буфере. Таким образом, вы гарантируете, что ошибки форматирования не выходят за пределы одной строки. Кроме того, sscanf возвращает количество прочитанных элементов, в вашем случае — 6. Было бы безопаснее проверить возвращаемое значение.

Комментарии:

1. Вы могли бы использовать getline для чтения целой строки (по крайней мере, в Linux и последних версиях POSIX; Я понятия не имею, работает ли это в Windows).

2. getline легко реализуется с точки зрения fgets и getdelim может даже быть реализована вручную с точки зрения getc или с помощью fscanf with %[ . Итак, дело в том, что если на платформе их не хватает, вы всегда можете добавить замены, построенные на функциях более низкого уровня. fgets Версия должна иметь примерно ту же скорость, что и родная getline , но использование getc наверняка будет медленным.