Чтение из текстовых файлов в C - PullRequest
1 голос
/ 25 ноября 2011

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

Таким образом, каждый, Frog, Is и Old будет помещен в ListNode, и все они будут считаны из файла.

Действительно, мне интересно, какую функцию лучше использовать вв сочетании с fscanf, если fscanf - даже лучший вариант.Все советы великолепны!

Приветствия.

РЕДАКТИРОВАТЬ: Мой запрос действительно, если бы я хотел разобрать большой текстовый файл, было бы лучше всего fscanf каждое слово в массив по одномудобавить в список, освободить массив и повторить?Или есть более эффективный способ

Ответы [ 3 ]

3 голосов
/ 25 ноября 2011

Спецификатор преобразования "% s" будет соответствовать непробельным символам.

#define QUOTE(s) #s
#define STR(s) QUOTE(s)

#ifndef BUFSIZE
#  define BUFSIZE 255
#endif

char buf[BUFSIZE+1];
while (fscanf(fin, "%" STR(BUFSIZE) "s", buf)) {
    /* buf holds next word. Todo:
       + allocate space for word
       + copy word to newly allocated space
       + add to linked list
     */
}

В качестве альтернативы strtok можно использовать для токенизации (разбиения) строки на подстрокииспользуя набор символов (как массив символов), который вы укажете.Ваша система также может иметь strsep, который предназначен для замены strtokstrtok, и strsep изменяют передаваемый массив, поэтому позаботьтесь о том, чтобы это не вызывало проблем с другими частями кода, которые обращаются к данным.strsep не является потокобезопасным;если у вас есть несколько потоков, обращающихся к анализируемой строке, используйте strsep или strtok_r.

#ifndef BUFSIZE
#  define BUFSIZE 256
#endif

const char separators[] = "\t\n\v\r\f !\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~";
char buf[BUFSIZE], *line, *word, *rest;

while (fgets(buf, BUFSIZE+1, fin)) {
    rest = line = buf;
    while ((word = strtok_r(line, separators, &rest))) {
        /* Todo:
           + allocate space for word
           + copy word to newly allocated space
           + add to linked list
        */
        line=rest;
    }
}

, так как второй пример читает строку из файла за раз для strtok_r для работыЕсли длина какой-либо строки файла превышает BUFSIZE-1, а символы BUFSIZE-1 st и BUFSIZE th в строке представляют собой обе буквы, во втором примере слова будут разбитыдва.Решением этой проблемы было бы создание потока буферизованной строки, чтобы при достижении конца буфера все, что осталось в буфере, смещалось вперед, а остальная часть буфера заполнялась дополнительными данными из файла (простобудьте осторожны со словами длиннее буфера, в производственном коде это потенциальная уязвимость безопасности, которая может привести к атакам типа «отказ в обслуживании».

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

Что касается эффективности, любой алгоритм, который вы используете, должен будет прочитатьиз файла (сложность O (n) и потребует ввода-вывода, что замедляет работу программы) и выделение памяти для хранения слов.Используете ли вы fscanf, strtok или какой-либо другой метод, сложность времени и пространства вряд ли будет сильно отличаться;единственное, что может, это то, сколько промежуточных буферов выделено.Лучший способ найти наиболее эффективную реализацию - попробовать пару и профилировать их.

1 голос
/ 25 ноября 2011

Если вы ищете высокую скорость, на современном настольном компьютере ... Вы можете использовать многопоточность.

  • Один поток заполняет буфер символов, скажем, 4Ko, и делает только это
  • Один поток читает буфер, разбирает слова и добавляет их в список
  • Один поток делает все, что вы чувствуете, чтобы сделать в списке, если вам не нужен список в целом

Идея состоит в том, что процесс не будет спать в ожидании ввода / вывода.Для дополнительной скорости, если у вас много ядер ЦП, стоит разрезать файл на большие порции, а одно ядро ​​обрабатывать один порцию.Много возможностей для сложного кода и ошибок, но, эй, скорость не из дешевых ...

1 голос
/ 25 ноября 2011

Вы не должны искать «более эффективный путь», пока у вас не будет «способа, который недостаточно эффективен».

Но что-то вроде strtok может соответствовать вашим потребностям без такого большого количества mallocING.Это позволяет вырезать строку на месте .(Используйте с осторожностью!)

...