Этот вопрос уже имеет ответ здесь:
Я имею дело с небольшими текстовыми файлами, которые я хочу считать в буфер, в то время как я обрабатываю их, таким образом, я придумал следующий код:
...
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
}
char source[1000000];
FILE *fp = fopen("TheFile.txt", "r");
if(fp != NULL)
{
while((symbol = getc(fp)) != EOF)
{
strcat(source, &symbol);
}
fclose(fp);
}
В этом коде есть несколько ошибок:
sizeof (source)
, это может привести к переполнению буфера. Функция
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! */
Да, вы, вероятно, были бы арестованы за ужасное злоупотребление strcat!
Взгляните на getline (), она считывает данные построчно, но, что важно, может ограничивать количество читаемых символов, чтобы вы не переполняли буфер.
Strcat работает относительно медленно, потому что ему приходится искать конец всей строки при каждой вставке символа. Обычно вы сохраняете указатель на текущий конец хранилища строк и передаете его в getline в качестве позиции для чтения следующей строки.
См. эту статью из JoelOnSoftware , чтобы узнать, почему вы не хотите использовать strcat
.
Посмотрите fread для альтернативы. Используйте его с 1 для размера, когда вы читаете байты или символы.
Почему бы вам просто не использовать имеющийся у вас массив символов? Это должно сделать это:
source[i] = getc(fp);
i++;
Задумывались ли вы о mmap ()? Вы можете читать из файла напрямую, как если бы он уже был в памяти.
Не тестировалось, но должно работать .. И да, это можно было бы лучше реализовать с помощью 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;