Чтение данных из текстового файла в C?

Так что я новичок в чтении данных из текстового файла на C. Я привык получать ввод с помощью scanf или жесткого кодирования.

Я пытаюсь научиться не только читать данные из текстового файла, но и манипулировать этими данными. Например, предположим, что текстовый файл с именем bst.txt содержит следующую информацию, используемую для выполнения операций с двоичным деревом поиска:

insert 10
insert 13
insert 5
insert 7
insert 20
delete 5
delete 10
....

В этом примере у меня будет следующий код:

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

int main()
{ 
  FILE *fptr;
  char *charptr;
  char temp[50];

  fptr = fopen("bst.txt", "r");

  while(fgets(temp, 50, fptr) != NULL)
  {
    charptr = strtok(temp, " ");

    while(charptr != NULL)
    {
      charptr = strtok(NULL, " ");
    }
  }

return 0;
}

Я знаю, что в первом цикле while strtok() разбивает каждую строку в текстовом файле, а во втором цикле while strtok() отделяется, когда программа распознает пробел, который в этом случае отделил бы операции от целых чисел.

Итак, мой главный вопрос: после того, как, например, слово «вставить» отделено от целого числа «10», как мне заставить программу продолжаться так:

if(_____ == "insert")
{
  //read integer from input file and call insert function, i.e. insert(10);
}

Мне нужно заполнить пробел.

Любая помощь будет принята с благодарностью!


person user3418283    schedule 14.03.2014    source источник
comment
не забывайте, что вы также можете scanf, а затем передать ввод в программу ... предполагая, что вы находитесь в старой доброй командной строке unixy! Маленькие программы вместе == большие результаты!   -  person Daniel Farrell    schedule 14.03.2014
comment
Предложение: вместо этого попробуйте fscanf(): int n = fscanf (fptr, "%s %d", cmd, &num);   -  person FoggyDay    schedule 14.03.2014
comment
Обратите внимание, что _____ является допустимым идентификатором в C.   -  person jxh    schedule 14.03.2014


Ответы (4)


Если бы я делал то, что вы делаете, я бы делал это так :)

Я вижу, что многие люди получают одобрение (не здесь, я имею в виду на SO в целом) за рекомендацию людям использовать такие функции, как scanf() и strtok(), несмотря на то, что эти функции повсеместно считаются злыми, а не только потому, что они не являются потокобезопасными, а потому, что они изменяют свои аргументы таким образом, который трудно предсказать, и отладка которых является огромной головной болью.

Если вы malloc()ing являетесь входным буфером для чтения из файла, всегда делайте его размером не менее 4 КБ — это наименьшая страница, которую ядро ​​может предоставить вам в любом случае, поэтому, если вы не Делая миллион глупых маленьких 100-байтовых malloc(), вы могли бы также — и не бойтесь выделять в 10 или 100 раз больше, если это облегчает жизнь.

Итак, для таких проблем, когда вы имеете дело с небольшими текстовыми файлами входных данных, вот что вы делаете:

  • malloc() себе хороший большой буфер, достаточно большой, чтобы впихнуть в него весь файл ведрами и ведрами запаса
  • откройте файл, проглотите всю эту чертову штуку с помощью read() и закройте его
  • запишите, сколько байтов вы прочитали в n_chars (или что-то еще)
  • сделать один проход через буфер и 1) заменить все новые строки на NUL и 2) записать начало каждой строки (происходит после новой строки!) в последовательные позиции в массиве lines (например, char **lines; lines=malloc(n_chars*sizeof(char *)): не может быть больше строк, чем байт!)
  • (необязательно) по мере продвижения перемещайте указатели начала строки, чтобы пропустить начальные пробелы
  • (необязательно) по мере продвижения перезаписывайте завершающие пробелы с помощью NUL
  • вести подсчет строк по ходу дела и сохранять его в n_lines
  • не забудьте free() этот буфер, когда закончите с ним

Итак, что у вас есть? У вас есть массив строк, которые являются строками вашего файла (необязательно с каждой строкой, лишенной начальных и конечных пробелов), и вы можете делать с ним все, что вам нравится.

Ну так что ты делаешь?

Пройдите через массив строк одну за другой, например:

for(i=0; i<n_lines; i++) {
    if( '\0'==*lines[i] || '#' == *lines[i] )
        continue;
    // More code

}

Уже вы проигнорировали пустые строки и строки, начинающиеся с "#". Ваш конфигурационный файл теперь имеет комментарии!

long n;
int  len;
for(i=0; i<n_lines; i++) {
    if( '\0'==*lines[i] || '#' == *lines[i] )
        continue;
    // More code

    len = strlen("insert");
    if( 0== strncmp(lines[i], "insert", len) ) {
        n = strtol(lines[i]+len+1, &endp, 10);
        // error checking
        tree_insert( (int)n );
        continue;
    }

    len = strlen("delete");
    if( 0== strncmp(lines[i], "delete", len) ) {
        n = strtol(lines[i]+len+1, &endp, 10);
        // error checking
        tree_delete( (int)n );
    }
}

Теперь вы, вероятно, видите 10 способов сделать этот код лучше. Я тоже. Как насчет структуры, содержащей ключевые слова и указатель на соответствующую функцию дерева?

Другие идеи? Выруби себя!

person Emmet    schedule 14.03.2014

вы можете вызывать следующим образом. Например, я поставил printf, но вместо этого вы можете заменить свою функцию insert/delete.

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

int main()
{ 
  FILE *fptr;
  char *charptr;
  char temp[50];

  fptr = fopen("bst.txt", "r");

  while(fgets(temp, 50, fptr) != NULL)
  {
    charptr = strtok(temp, " ");

    if(strcmp(charptr,"insert")==0)
    {
      charptr = strtok(NULL, " ");

      printf("insert num %d\n",atoi(charptr));
    }
    else if(strcmp(charptr,"delete")==0)
    {
      charptr = strtok(NULL, " ");

      printf("delete num %d\n",atoi(charptr));
    }
  }

return 0;
}
person Jayesh Bhoi    schedule 14.03.2014
comment
Это было очень полезно, спасибо. А что, если я захочу добавить еще один условный оператор для вывода того, что находится в дереве? (т. е. в текстовом файле будет строка с надписью print). Я попытался имитировать то, что вы делали для других операций, за исключением (в целях тестирования) оператора печати, который просто говорит printf(print\n); но печать слова не выводится, когда я запускаю программу. Есть идеи, почему? - person user3418283; 14.03.2014

Я думаю, что лучший способ прочитать отформатированные строки в файле — использовать fscanf, в следующем примере показано, как анализировать файл. Вы можете сохранить charptr и value для дальнейших операций:

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

int main()
{ 
  FILE *fptr;
  char charptr[50];
  int value;

  fptr = fopen("bst.txt", "r");

  while (fscanf(fptr, "%s%d", charptr, &value) > 0)
  {
      printf("%s: %d\n", charptr, value);
  }

  return 0;
}
person feihu    schedule 14.03.2014

попробуйте этот код

int main(){
FILE *fp;
char character[50];
int value;
fptr = fopen("input.txt", "r");

while (fscanf(fp, "%s%d", character, &value) > 0)
{
  if(strcmp(character,"insert")==0){
      insert(value);//call you function which you want value is 10 or change according to file
  }
}
return 0;
}
person Rishi Dwivedi    schedule 14.03.2014