txt manejo lenguaje leer guardar fscanf fputs fprintf ejercicios datos binarios archivos archivo c file-io

manejo - guardar y leer datos en un archivo.txt en c



C Programación: Cómo leer todo el contenido del archivo en un buffer (4)

Esto es lo que recomendaría.

Debe cumplir con C89 y ser completamente portátil. En particular, funciona también en tuberías y enchufes en sistemas POSIXy.

La idea es que leamos la entrada en fragmentos de gran tamaño ( READALL_CHUNK ), reasignando dinámicamente el buffer según lo necesitemos. Solo usamos realloc() , fread() , ferror() y free() :

#include <stdlib.h> #include <stdio.h> #include <errno.h> /* Size of each input chunk to be read and allocate for. */ #ifndef READALL_CHUNK #define READALL_CHUNK 262144 #endif #define READALL_OK 0 /* Success */ #define READALL_INVALID -1 /* Invalid parameters */ #define READALL_ERROR -2 /* Stream error */ #define READALL_TOOMUCH -3 /* Too much input */ #define READALL_NOMEM -4 /* Out of memory */ /* This function returns one of the READALL_ constants above. If the return value is zero == READALL_OK, then: (*dataptr) points to a dynamically allocated buffer, with (*sizeptr) chars read from the file. The buffer is allocated for one extra char, which is NUL, and automatically appended after the data. Initial values of (*dataptr) and (*sizeptr) are ignored. */ int readall(FILE *in, char **dataptr, size_t *sizeptr) { char *data = NULL, *temp; size_t size = 0; size_t used = 0; size_t n; /* None of the parameters can be NULL. */ if (in == NULL || dataptr == NULL || sizeptr == NULL) return READALL_INVALID; /* A read error already occurred? */ if (ferror(in)) return READALL_ERROR; while (1) { if (used + READALL_CHUNK + 1 > size) { size = used + READALL_CHUNK + 1; /* Overflow check. Some ANSI C compilers may optimize this away, though. */ if (size <= used) { free(data); return READALL_TOOMUCH; } temp = realloc(data, size); if (temp == NULL) { free(data); return READALL_NOMEM; } data = temp;      } n = fread(data + used, 1, READALL_CHUNK, in); if (n == 0) break; used += n; } if (ferror(in)) { free(data); return READALL_ERROR; } temp = realloc(data, used + 1); if (temp == NULL) { free(data); return READALL_NOMEM; } data = temp; data[used] = ''/0''; *dataptr = data; *sizeptr = used; return READALL_OK; }

Arriba, he usado un tamaño de fragmento constante, READALL_CHUNK == 262144 ( 256*1024 ). Esto significa que, en el peor de los casos, se desperdician hasta 262145 caracteres (asignados pero no utilizados), pero solo temporalmente. Al final, la función reasigna el búfer al tamaño óptimo. Además, esto significa que realizamos cuatro reasignaciones por megabyte de datos leídos.

El valor predeterminado de 262144 bytes en el código anterior es un valor conservador; funciona bien incluso para minilaptops viejas y Raspberry Pis y la mayoría de los dispositivos integrados con al menos unos pocos megabytes de RAM disponibles para el proceso. Sin embargo, no es tan pequeño que ralentiza la operación (debido a muchas llamadas de lectura y muchas reasignaciones de búfer) en la mayoría de los sistemas.

Para máquinas de escritorio en este momento (2017), recomiendo un READALL_CHUNK mucho más READALL_CHUNK , quizás #define READALL_CHUNK 2097152 (2 MiB).

Debido a que la definición de READALL_CHUNK está protegida (es decir, está definida solo si todavía no está definida en ese punto), puede anular el valor predeterminado en tiempo de compilación, utilizando (en la mayoría de los compiladores C) -DREADALL_CHUNK=2097152 comando opción de línea, pero verifique las opciones de compilación para definir una macro de preprocesador utilizando las opciones de línea de comandos.

Esta pregunta ya tiene una respuesta aquí:

Quiero escribir el contenido completo de un archivo en un búfer. El archivo en realidad solo contiene una cadena que necesito comparar con una cadena.

Cuál sería la opción más eficiente que es portátil incluso en Linux.

ENV: Windows


La portabilidad entre Linux y Windows es un gran dolor de cabeza, ya que Linux es un sistema que cumple con POSIX, generalmente con una cadena de herramientas adecuada y de alta calidad para C, mientras que Windows ni siquiera proporciona muchas funciones en la biblioteca estándar de C.

Sin embargo, si quiere seguir el estándar, puede escribir algo como esto:

#include <stdio.h> #include <stdlib.h> FILE *f = fopen("textfile.txt", "rb"); fseek(f, 0, SEEK_END); long fsize = ftell(f); fseek(f, 0, SEEK_SET); //same as rewind(f); char *string = malloc(fsize + 1); fread(string, fsize, 1, f); fclose(f); string[fsize] = 0;

Aquí, la string contendrá el contenido del archivo de texto como una cadena C correctamente terminada en 0. Este código es solo estándar C, no es específico de POSIX (aunque no garantiza que funcione / compile en Windows ...)


Si conoce el tamaño máximo de buffer antes de tiempo:

#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 (newLen == 0) { fputs("Error reading file", stderr); } else { source[++newLen] = ''/0''; /* Just to be safe. */ } fclose(fp); }

O, si no:

#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) { /* Handle error here */ } /* Read the entire file into memory. */ size_t newLen = fread(source, sizeof(char), bufsize, fp); if (newLen == 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! */


Una solución portátil podría usar getc .

#include <stdio.h> char buffer[MAX_FILE_SIZE]; size_t i; for (i = 0; i < MAX_FILE_SIZE; ++i) { int c = getc(fp); if (c == EOF) { buffer[i] = 0x00; break; } buffer[i] = c; }

Si no desea tener una macro MAX_FILE_SIZE o si se trata de un número grande (tal que el buffer sería demasiado grande para caber en la pila), use la asignación dinámica.