#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
наверняка будет медленным.