2010-09-19 7 views
23

Quiero leer el contenido de un archivo de texto en una matriz char en C. Deben mantenerse las líneas nuevas.Lectura del archivo de texto completo en una matriz char en C

¿Cómo puedo lograr esto? Encontré algunas soluciones de C++ en la web, pero ninguna solución de C solo.

Editar: Tengo el siguiente código ahora:

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

me sale una advertencia: Advertencia: la asignación crea un puntero desde un entero sin una conversión. Esto está en la línea size = (int)lSize;. Si ejecuto la aplicación, segfaults.

Actualización: El código anterior funciona ahora. Localicé el segfault, y publiqué otra pregunta. Gracias por la ayuda.

+0

duplicado posible de [La manera más fácil de obtener los contenidos del archivo en C] (http://stackoverflow.com/questions/174531/easiest-way-to-get-files-contents-in-c) –

+0

Uso fseek() para obtener el tamaño del archivo, lo limita a leer solo archivos de disco reales. Su uso significa que no puede leer desde un conducto (como la entrada estándar), canalizaciones con nombre, dispositivos o flujos de red. Vea el enlace en el comentario anterior [La forma más fácil de obtener los contenidos del archivo en C] (http://stackoverflow.com/questions/174531) – anthony

Respuesta

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

Puede cerrar el archivo antes de trabajar en los datos, en lugar de hacerlo después. –

+1

¿Alguna razón particular para calloc sobre malloc? – Tanaki

+3

@Tanaki Por lo general, callo las cadenas C como un mecanismo de seguridad redundante, en caso de que la cadena C que se coloca en el búfer no termine en NUL por algún motivo. Sin embargo, es una precaución innecesaria en la mayoría de los casos estándar. – Ephemera

2

fgets() es una función C que se puede utilizar para lograr esto.

Editar: También puede considerar el uso de fread().

+2

en ventanas que puede querer abrir en modo binario para que no se traduzca cr –

+0

leyó todo el archivo a la vez? – friedkiwi

+0

No, no es así. Se lee hasta nueva línea o al final del archivo. Sin embargo, la lectura nueva se conserva. Por lo tanto, puede agregar los caracteres leídos directamente a la matriz de caracteres y las nuevas líneas aparecerán de la misma manera que el archivo. –

9

Una solución en forma de un programa completo que responde a la pregunta y la demuestra. Es un poco más explícito que otras respuestas y, por lo tanto, más fácil de entender para los menos expertos en C (EN MIEMBRO).

#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

En Windows, al menos, tendrá que abrir el archivo en el modo "rb" o el comando fread devolverá el número incorrecto. Y obtuve un AccessViolation cuando add_nul era verdadero. Creo que lo arreglé usando esto: '(* buf) [fsz] = '\ 0';' –

+0

¿Estás seguro de que este realmente funciona? – Shark

+0

@RayHulha: punto justo. No he usado Windows en años y tiendo a olvidarme de distinguir entre el modo binario y el modo de texto. También estás justo en el segundo punto, hubo una desreferencia ajena ("*") en el original. – Emmet

3

Desde que utiliza slurp() esperando que funcione, unos días más tarde descubrí que .... no lo hace.

Así que para las personas que están ansiosas por copiar/pegar una solución para "obtener el contenido de un ARCHIVO en un char *", aquí hay algo que puede usar.

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

Recuerde niños, 'buffer' TIENE que ser liberado por la persona que llama. – Shark

+1

La edición debe tener al menos 6 caracteres para que no pueda solucionarlo. Corrección de errores pequeños: 'buffer [longitud + 1] = '\ 0';' debe ser: 'buffer [longitud] = '\ 0';' – Jos

+0

'length' debe inicializarse a' 0' en comenzando, en caso de que 'if (f)' falle. – Groo

Cuestiones relacionadas