¿Cómo leer el contenido de un archivo en una cadena en C?

¿Cuál es la forma más simple (menos propensa a errores, menos líneas de código, como quiera interpretarla) para abrir un archivo en C y leer su contenido en una cadena (char *, char [], lo que sea)?

Tiendo a simplemente cargar todo el búfer como un fragmento de memoria en bruto en la memoria y hacer el análisis por mi cuenta. De esta forma, tengo el mejor control sobre lo que hace la lib estándar en múltiples plataformas.

Este es un apéndice que uso para esto. es posible que también desee verificar los códigos de error para fseek, ftell y fread. (omitido para mayor claridad).

 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... } 

Otra solución, lamentablemente muy dependiente del sistema operativo, es la asignación de memoria del archivo. Los beneficios generalmente incluyen el rendimiento de la lectura y el uso reducido de la memoria, ya que la vista de aplicaciones y la memoria caché de los sistemas operativos pueden compartir la memoria física.

El código POSIX se vería así:

 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, por otro lado, es un poco más complicado, y desafortunadamente no tengo un comstackdor delante de mí para probar, pero la funcionalidad es proporcionada por CreateFileMapping() y MapViewOfFile() .

Si “lee su contenido en una cadena” significa que el archivo no contiene caracteres con el código 0, también puede usar la función getdelim (), que acepta un bloque de memoria y lo reasigna si es necesario, o simplemente asigna el búfer completo para usted, y lee el archivo en él hasta que encuentra un delimitador o un final de archivo especificado. Simplemente pase ‘\ 0’ como el delimitador para leer todo el archivo.

Esta función está disponible en la Biblioteca GNU C, http://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getdelim-994

El código de muestra puede verse tan simple como

 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 */ 

Si el archivo es texto y desea obtener el texto línea por línea, la manera más fácil es usar fgets ().

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

Si está leyendo archivos especiales como stdin o un tubo, no podrá usar fstat para obtener el tamaño del archivo de antemano. Además, si estás leyendo un archivo binario, fgets va a perder la información del tamaño de cadena debido a los caracteres incrustados ‘\ 0’. La mejor manera de leer un archivo es usar read y 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; } 

Si está utilizando glib , puede usar 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; } 

Esta es una solución bastante cruda porque nada se compara con nulo.

Recién modificado de la respuesta aceptada arriba.

 #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); }