Корректный способ считать текстовый файл в буфер в C? [дубликат]

Этот вопрос уже имеет ответ здесь:

Я имею дело с небольшими текстовыми файлами, которые я хочу считать в буфер, в то время как я обрабатываю их, таким образом, я придумал следующий код:

...
char source[1000000];

FILE *fp = fopen("TheFile.txt", "r");
if(fp != NULL)
{
    while((symbol = getc(fp)) != EOF)
    {
        strcat(source, &symbol);
    }
    fclose(fp);
}
...

Это корректный способ поместить содержание файла в буфер или я злоупотребление strcat()?

Я тогда выполняю итерации через буфер таким образом:

for(int x = 0; (c = source[x]) != '\0'; x++)
{
    //Process chars
}
24
задан Gary Willoughby 8 January 2010 в 16:44
поделиться

7 ответов

char source[1000000];

FILE *fp = fopen("TheFile.txt", "r");
if(fp != NULL)
{
    while((symbol = getc(fp)) != EOF)
    {
        strcat(source, &symbol);
    }
    fclose(fp);
}

В этом коде есть несколько ошибок:

  1. Он очень медленный ( вы извлекаете буфер по одному символу за раз).
  2. Если размер файла превышает sizeof (source) , это может привести к переполнению буфера.
  3. На самом деле, если присмотреться, этот код вообще не должен работать. Как указано на страницах руководства:

Функция strcat () добавляет копию строки с нулевым символом в конце s2 в конец строки с нулевым символом в конце s1, а затем добавляет завершающий `\ 0 ' .

Вы добавляете символ (не строку с завершающим NUL!) К строке, которая может или не может быть завершена NUL. Единственный раз, когда я могу представить эту работу в соответствии с описанием man-страницы, если каждый символ в файле завершается NUL, и в этом случае это было бы бессмысленно. Так что да, это определенно ужасное злоупотребление strcat () .

Ниже приведены две альтернативы, которые можно использовать вместо этого.

Если вы заранее знаете максимальный размер буфера:

#include <stdio.h>
#define MAXBUFLEN 1000000

char source[MAXBUFLEN + 1];
FILE *fp = fopen("foo.txt", "r");
if (fp != NULL) {
    size_t newLen = fread(source, sizeof(char), MAXBUFLEN, fp);
    if ( ferror( fp ) != 0 ) {
        fputs("Error reading file", stderr);
    } else {
        source[newLen++] = '\0'; /* Just to be safe. */
    }

    fclose(fp);
}

Или, если вы не знаете:

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

char *source = NULL;
FILE *fp = fopen("foo.txt", "r");
if (fp != NULL) {
    /* Go to the end of the file. */
    if (fseek(fp, 0L, SEEK_END) == 0) {
        /* Get the size of the file. */
        long bufsize = ftell(fp);
        if (bufsize == -1) { /* Error */ }

        /* Allocate our buffer to that size. */
        source = malloc(sizeof(char) * (bufsize + 1));

        /* Go back to the start of the file. */
        if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }

        /* Read the entire file into memory. */
        size_t newLen = fread(source, sizeof(char), bufsize, fp);
        if ( ferror( fp ) != 0 ) {
            fputs("Error reading file", stderr);
        } else {
            source[newLen++] = '\0'; /* Just to be safe. */
        }
    }
    fclose(fp);
}

free(source); /* Don't forget to call free() later! */
70
ответ дан 28 November 2019 в 22:22
поделиться

Да, вы, вероятно, были бы арестованы за ужасное злоупотребление strcat!

Взгляните на getline (), она считывает данные построчно, но, что важно, может ограничивать количество читаемых символов, чтобы вы не переполняли буфер.

Strcat работает относительно медленно, потому что ему приходится искать конец всей строки при каждой вставке символа. Обычно вы сохраняете указатель на текущий конец хранилища строк и передаете его в getline в качестве позиции для чтения следующей строки.

5
ответ дан 28 November 2019 в 22:22
поделиться

См. эту статью из JoelOnSoftware , чтобы узнать, почему вы не хотите использовать strcat .

Посмотрите fread для альтернативы. Используйте его с 1 для размера, когда вы читаете байты или символы.

1
ответ дан 28 November 2019 в 22:22
поделиться

Мне кажется, вам нужен fread:

http://www.cplusplus.com/reference/clibrary/cstdio/fread/

0
ответ дан 28 November 2019 в 22:22
поделиться

Почему бы вам просто не использовать имеющийся у вас массив символов? Это должно сделать это:

   source[i] = getc(fp); 
   i++;
1
ответ дан 28 November 2019 в 22:22
поделиться

Задумывались ли вы о mmap ()? Вы можете читать из файла напрямую, как если бы он уже был в памяти.

http://beej.us/guide/bgipc/output/html/multipage/mmap.html

-1
ответ дан 28 November 2019 в 22:22
поделиться

Не тестировалось, но должно работать .. И да, это можно было бы лучше реализовать с помощью fread, я оставлю это в качестве упражнения для читателя.

#define DEFAULT_SIZE 100
#define STEP_SIZE 100

char *buffer[DEFAULT_SIZE];
size_t buffer_sz=DEFAULT_SIZE;
size_t i=0;
while(!feof(fp)){
  buffer[i]=fgetc(fp);
  i++;
  if(i>=buffer_sz){
    buffer_sz+=STEP_SIZE;
    void *tmp=buffer;
    buffer=realloc(buffer,buffer_sz);
    if(buffer==null){ free(tmp); exit(1);} //ensure we don't have a memory leak
  }
}
buffer[i]=0;
1
ответ дан 28 November 2019 в 22:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: