Come leggere il contenuto di un file in una stringa in C?

Qual è il modo più semplice (meno incline agli errori, meno righe di codice, comunque lo si voglia interpretare) per aprire un file in C e leggerne il contenuto in una stringa (char *, char [], qualunque sia)?

Tendo a caricare l’intero buffer come un blocco di memoria grezza in memoria e faccio il parsing da solo. In questo modo ho il miglior controllo su ciò che la lib standard fa su più piattaforms.

Questo è uno stub che uso per questo. potresti anche voler controllare i codici di errore per fseek, ftell e fread. (omesso per chiarezza).

 char * buffer = 0; long length; FILE * f = fopen (filename, "rb"); if (f) { fseek (f, 0, SEEK_END); length = ftell (f); fseek (f, 0, SEEK_SET); buffer = malloc (length); if (buffer) { fread (buffer, 1, length, f); } fclose (f); } if (buffer) { // start to process your data / extract strings here... } 

Un’altra soluzione, purtroppo altamente dipendente dal sistema operativo, è la memoria che mappa il file. I vantaggi generalmente includono le prestazioni della lettura e l’utilizzo ridotto della memoria poiché la vista delle applicazioni e la cache dei file del sistema operativo possono effettivamente condividere la memoria fisica.

Il codice POSIX sarebbe simile a questo:

 int fd = open("filename", O_RDONLY); int len = lseek(fd, 0, SEEK_END); void *data = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0); 

Windows invece è un po ‘più complicato, e sfortunatamente non ho un compilatore davanti a me da testare, ma la funzionalità è fornita da CreateFileMapping() e MapViewOfFile() .

Se “leggi il suo contenuto in una stringa” significa che il file non contiene caratteri con il codice 0, puoi anche usare la funzione getdelim (), che accetta un blocco di memoria e lo rialloca se necessario, o semplicemente alloca l’intero buffer per tu e leggi il file fino a quando non incontra un delimitatore o una fine del file specificato. Basta passare ‘\ 0’ come delimitatore per leggere l’intero file.

Questa funzione è disponibile nella libreria GNU C, http://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getdelim-994

Il codice di esempio potrebbe sembrare semplice

 char* buffer = NULL; size_t len; ssize_t bytes_read = getdelim( &buffer, &len, '\0', fp); if ( bytes_read != -1) { /* Success, now the entire file is in the buffer */ 

Se il file è di testo e si desidera ottenere il testo riga per riga, il modo più semplice è usare fgets ().

 char buffer[100]; FILE *fp = fopen("filename", "r"); // do not use "rb" while (fgets(buffer, sizeof(buffer), fp)) { ... do something } fclose(fp); 

Se stai leggendo file speciali come stdin o pipe, non sarai in grado di usare fstat per ottenere le dimensioni del file in anticipo. Inoltre, se stai leggendo un file binario, fgets perde le informazioni sulla dimensione della stringa a causa dei caratteri “\ 0” incorporati. Il modo migliore per leggere un file è usare read e realloc:

 #include  #include  #include  #include  int main () { char buf[4096]; ssize_t n; char *str = NULL; size_t len = 0; while (n = read(STDIN_FILENO, buf, sizeof buf)) { if (n < 0) { if (errno == EAGAIN) continue; perror("read"); break; } str = realloc(str, len + n + 1); memcpy(str + len, buf, n); len += n; str[len] = '\0'; } printf("%.*s\n", len, str); return 0; } 

Se stai usando glib , allora puoi usare g_file_get_contents ;

 gchar *contents; GError *err = NULL; g_file_get_contents ("foo.txt", &contents, NULL, &err); g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL)); if (err != NULL) { // Report error to user, and free error g_assert (contents == NULL); fprintf (stderr, "Unable to read file: %s\n", err->message); g_error_free (err); } else { // Use file contents g_assert (contents != NULL); } } 
 // Assumes the file exists and will seg. fault otherwise. const GLchar *load_shader_source(char *filename) { FILE *file = fopen(filename, "r"); // open fseek(file, 0L, SEEK_END); // find the end size_t size = ftell(file); // get the size in bytes GLchar *shaderSource = calloc(1, size); // allocate enough bytes rewind(file); // go back to file beginning fread(shaderSource, size, sizeof(char), file); // read each char into ourblock fclose(file); // close the stream return shaderSource; } 

Questa è una soluzione piuttosto grezza perché nulla viene verificato rispetto a null.

Appena modificato dalla risposta accettata sopra.

 #include  #include  #include  char *readFile(char *filename) { FILE *f = fopen(filename, "rt"); assert(f); fseek(f, 0, SEEK_END); long length = ftell(f); fseek(f, 0, SEEK_SET); char *buffer = (char *) malloc(length + 1); buffer[length] = '\0'; fread(buffer, 1, length, f); fclose(f); return buffer; } int main() { char *content = readFile("../hello.txt"); printf("%s", content); }