2010-09-19 2 views
23

Я хочу прочитать содержимое текстового файла в массиве символов в C. Должны быть сохранены новые строки.Чтение всего текстового файла в массив символов в C

Как это сделать? Я нашел некоторые C++-решения в Интернете, но не только C-решение.

Edit: У меня есть следующий код сейчас:

void *loadfile(char *file, int *size) 
{ 
    FILE *fp; 
    long lSize; 
    char *buffer; 

    fp = fopen (file , "rb"); 
    if(!fp) perror(file),exit(1); 

    fseek(fp , 0L , SEEK_END); 
    lSize = ftell(fp); 
    rewind(fp); 

    /* allocate memory for entire content */ 
    buffer = calloc(1, lSize+1); 
    if(!buffer) fclose(fp),fputs("memory alloc fails",stderr),exit(1); 

    /* copy the file into the buffer */ 
    if(1!=fread(buffer , lSize, 1 , fp)) 
     fclose(fp),free(buffer),fputs("entire read fails",stderr),exit(1); 

    /* do your work here, buffer is a string contains the whole text */ 
    size = (int *)lSize; 
    fclose(fp); 
    return buffer; 
} 

я получаю одно предупреждение: предупреждение: назначение делает указатель из целого числа без броска. Это находится на линии size = (int)lSize;. Если я запустил приложение, он будет segfaults.

Обновление: Приведенный выше код работает сейчас. Я нашел segfault, и я задал еще один вопрос. Спасибо за помощь.

+0

Возможный дубликат [Самый простой способ получить содержимое файла в C] (http://stackoverflow.com/questions/174531/easiest-way-to-get-files-contents-in-c) –

+0

Использование fseek(), чтобы получить размер файла, ограничивает только чтение реальных файлов на диске. Использование этого означает, что вы не можете читать из канала (например, стандартный ввод), именованный канал, устройства или сетевые потоки. См. Ссылку в комментарии выше. [Самый простой способ получить содержимое файла в C] (http://stackoverflow.com/questions/174531) – anthony

ответ

27
FILE *fp; 
long lSize; 
char *buffer; 

fp = fopen ("blah.txt" , "rb"); 
if(!fp) perror("blah.txt"),exit(1); 

fseek(fp , 0L , SEEK_END); 
lSize = ftell(fp); 
rewind(fp); 

/* allocate memory for entire content */ 
buffer = calloc(1, lSize+1); 
if(!buffer) fclose(fp),fputs("memory alloc fails",stderr),exit(1); 

/* copy the file into the buffer */ 
if(1!=fread(buffer , lSize, 1 , fp)) 
    fclose(fp),free(buffer),fputs("entire read fails",stderr),exit(1); 

/* do your work here, buffer is a string contains the whole text */ 

fclose(fp); 
free(buffer); 
+14

Вы можете закрыть файл перед работой над данными, а не после. –

+1

Любая конкретная причина для calloc над malloc? – Tanaki

+3

@Tanaki Я обычно вызываю C строк как избыточный механизм безопасности, на всякий случай, если строка C, помещенная в буфер, по какой-то причине не завершена NUL. Это, вероятно, ненужная мера предосторожности в большинстве стандартных случаев. – Ephemera

2

fgets() - это функция C, которая может быть использована для этого.

Редактировать: Вы также можете рассмотреть возможность использования fread().

+2

на окнах, которые вы можете открыть в двоичном режиме, чтобы он не переводил cr –

+0

Does он читает весь файл сразу? – friedkiwi

+0

Нет, это не так. Он читает до новой строки или конца файла. Однако чтение новой строки сохраняется. Таким образом, вы можете добавлять символы чтения непосредственно в массив символов, и новые строки будут отображаться так же, как и файл. –

9

Решение в виде полной программы, которая отвечает на вопрос и демонстрирует его. Это немного более четко, чем другие ответы, и поэтому их легче понять для тех, кто менее опытен в C (IMHO).

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

/* 
* 'slurp' reads the file identified by 'path' into a character buffer 
* pointed at by 'buf', optionally adding a terminating NUL if 
* 'add_nul' is true. On success, the size of the file is returned; on 
* failure, -1 is returned and ERRNO is set by the underlying system 
* or library call that failed. 
* 
* WARNING: 'slurp' malloc()s memory to '*buf' which must be freed by 
* the caller. 
*/ 
long slurp(char const* path, char **buf, bool add_nul) 
{ 
    FILE *fp; 
    size_t fsz; 
    long off_end; 
    int rc; 

    /* Open the file */ 
    fp = fopen(path, "rb"); 
    if(NULL == fp) { 
     return -1L; 
    } 

    /* Seek to the end of the file */ 
    rc = fseek(fp, 0L, SEEK_END); 
    if(0 != rc) { 
     return -1L; 
    } 

    /* Byte offset to the end of the file (size) */ 
    if(0 > (off_end = ftell(fp))) { 
     return -1L; 
    } 
    fsz = (size_t)off_end; 

    /* Allocate a buffer to hold the whole file */ 
    *buf = malloc(fsz+(int)add_nul); 
    if(NULL == *buf) { 
     return -1L; 
    } 

    /* Rewind file pointer to start of file */ 
    rewind(fp); 

    /* Slurp file into buffer */ 
    if(fsz != fread(*buf, 1, fsz, fp)) { 
     free(*buf); 
     return -1L; 
    } 

    /* Close the file */ 
    if(EOF == fclose(fp)) { 
     free(*buf); 
     return -1L; 
    } 

    if(add_nul) { 
     /* Make sure the buffer is NUL-terminated, just in case */ 
     buf[fsz] = '\0'; 
    } 

    /* Return the file size */ 
    return (long)fsz; 
} 


/* 
* Usage message for demo (in main(), below) 
*/ 
void usage(void) { 
    fputs("USAGE: ./slurp <filename>\n", stderr); 
    exit(1); 
} 


/* 
* Demonstrates a call to 'slurp'. 
*/ 
int main(int argc, char *argv[]) { 
    long file_size; 
    char *buf; 

    /* Make sure there is at least one command-line argument */ 
    if(argc < 2) { 
     usage(); 
    } 

    /* Try the first command-line argument as a file name */ 
    file_size = slurp(argv[1], &buf, false); 

    /* Bail if we get a negative file size back from slurp() */ 
    if(file_size < 0L) { 
     perror("File read failed"); 
     usage(); 
    } 

    /* Write to stdout whatever slurp() read in */ 
    (void)fwrite(buf, 1, file_size, stdout); 

    /* Remember to free() memory allocated by slurp() */ 
    free(buf); 
    return 0; 
} 
+1

На WIndows по крайней мере вам нужно будет открыть файл в режиме «rb», иначе fread вернет неправильный номер. И я получил AccessViolation, когда add_nul был правдой. Я думаю, я исправил это, используя это: '(* buf) [fsz] = '\ 0';' –

+0

Вы уверены, что это действительно работает? – Shark

+0

@RayHulha: справедливая точка. Я не использовал Windows в течение многих лет и, как правило, забываю об этом, различая двоичный и текстовый режим. Вы также правы во 2-м пункте, в оригинале произошел посторонний разыгрыш (излишек «*»). – Emmet

3

Поскольку я использовал slurp() ожидая, что она работает, несколько дней спустя я узнал, что .... это не так.

Так что для людей, которые хотят скопировать/вставить решение для «получения содержимого ФАЙЛА в символ», вот что вы можете использовать.

char* load_file(char const* path) 
{ 
    char* buffer = 0; 
    long length; 
    FILE * f = fopen (path, "rb"); //was "rb" 

    if (f) 
    { 
     fseek (f, 0, SEEK_END); 
     length = ftell (f); 
     fseek (f, 0, SEEK_SET); 
     buffer = (char*)malloc ((length+1)*sizeof(char)); 
     if (buffer) 
     { 
     fread (buffer, sizeof(char), length, f); 
     } 
     fclose (f); 
    } 
    buffer[length] = '\0'; 
    // for (int i = 0; i < length; i++) { 
    //  printf("buffer[%d] == %c\n", i, buffer[i]); 
    // } 
    //printf("buffer = %s\n", buffer); 

    return buffer; 
} 
+1

Помните, что дети, 'buffer', должны быть освобождены вызывающим. – Shark

+1

Редактировать должно быть не менее 6 символов, чтобы не исправить его. Исправление ошибки: 'buffer [length + 1] = '\ 0';' должно быть: 'buffer [length] = '\ 0';' – Jos

+0

'length' должно быть инициализировано' 0' на начало, в случае, если 'if (f)' терпит неудачу. – Groo

Смежные вопросы