En C, ¿cómo debo leer un archivo de texto e imprimir todas las cadenas


Tengo un archivo de texto llamado test.txt

Quiero escribir un programa en C que pueda leer este archivo e imprimir el contenido en la consola (supongamos que el archivo contiene solo texto ASCII).

No se como obtener el tamaño de mi variable string. Así:

char str[999];
FILE * file;
file = fopen( "test.txt" , "r");
if (file) {
    while (fscanf(file, "%s", str)!=EOF)
        printf("%s",str);
    fclose(file);
}

El tamaño 999 no funciona porque la cadena devuelta por fscanf puede ser más grande que eso. ¿Cómo puedo resolver esto?

Author: bta, 2010-08-12

8 answers

La forma más sencilla es leer un carácter e imprimirlo justo después de leer: {[12]]}

int c;
FILE *file;
file = fopen("test.txt", "r");
if (file) {
    while ((c = getc(file)) != EOF)
        putchar(c);
    fclose(file);
}

c es int anterior, ya que EOF es un número negativo, y un simple char puede ser unsigned.

Si desea leer el archivo en trozos, pero sin asignación de memoria dinámica, puede hacer:

#define CHUNK 1024 /* read 1024 bytes at a time */
char buf[CHUNK];
FILE *file;
size_t nread;

file = fopen("test.txt", "r");
if (file) {
    while ((nread = fread(buf, 1, sizeof buf, file)) > 0)
        fwrite(buf, 1, nread, stdout);
    if (ferror(file)) {
        /* deal with error */
    }
    fclose(file);
}

El segundo método anterior es esencialmente cómo leerá un archivo con una matriz asignada dinámicamente:

char *buf = malloc(chunk);

if (buf == NULL) {
    /* deal with malloc() failure */
}

/* otherwise do this.  Note 'chunk' instead of 'sizeof buf' */
while ((nread = fread(buf, 1, chunk, file)) > 0) {
    /* as above */
}

Su método de fscanf() con %s como formato pierde información acerca de los espacios en blanco en el archivo, por lo que no es exactamente copiar un archivo a stdout.

 107
Author: Alok Singhal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-12 00:03:45

Hay un montón de buenas respuestas aquí acerca de la lectura en trozos, solo voy a mostrar un pequeño truco que lee todo el contenido a la vez a un búfer y lo imprime.

No estoy diciendo que sea mejor. No lo es, y como Ricardo a veces puede ser malo, pero me parece que es una buena solución para los casos simples.

Lo rocié con comentarios porque están pasando muchas cosas.

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

char* ReadFile(char *filename)
{
   char *buffer = NULL;
   int string_size, read_size;
   FILE *handler = fopen(filename, "r");

   if (handler)
   {
       // Seek the last byte of the file
       fseek(handler, 0, SEEK_END);
       // Offset from the first to the last byte, or in other words, filesize
       string_size = ftell(handler);
       // go back to the start of the file
       rewind(handler);

       // Allocate a string that can hold it all
       buffer = (char*) malloc(sizeof(char) * (string_size + 1) );

       // Read it all in one operation
       read_size = fread(buffer, sizeof(char), string_size, handler);

       // fread doesn't set it so put a \0 in the last position
       // and buffer is now officially a string
       buffer[string_size] = '\0';

       if (string_size != read_size)
       {
           // Something went wrong, throw away the memory and set
           // the buffer to NULL
           free(buffer);
           buffer = NULL;
       }

       // Always remember to close the file.
       fclose(handler);
    }

    return buffer;
}

int main()
{
    char *string = ReadFile("yourfile.txt");
    if (string)
    {
        puts(string);
        free(string);
    }

    return 0;
}

Hazme saber si es útil o podrías aprender algo de él:)

 41
Author: lfzawacki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-21 18:18:03

En su lugar, solo imprima directamente los caracteres en la consola porque el archivo de texto puede ser muy grande y puede requerir mucha memoria.

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

int main() {

    FILE *f;
    char c;
    f=fopen("test.txt","rt");

    while((c=fgetc(f))!=EOF){
        printf("%c",c);
    }

    fclose(f);
    return 0;
}
 11
Author: Sagar Shah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-27 11:12:38

Use "read ()" en su lugar o fscanf:

ssize_t read(int fildes, void *buf, size_t nbyte);

DESCRIPCIÓN

La función read() intentará leer nbyte bytes del archivo asociado con el descriptor de archivo abierto, fildes, en el búfer apuntado por buf.

Aquí hay un ejemplo:

Http://cmagical.blogspot.com/2010/01/c-programming-on-unix-implementing-cat.html

Parte de trabajo de ese ejemplo:

f=open(argv[1],O_RDONLY);
while ((n=read(f,l,80)) > 0)
    write(1,l,n);

Un enfoque alternativo es utilizar getc/putc leer / escribir 1 letra a la vez. Mucho menos eficiente. Un buen ejemplo: http://www.eskimo.com/~scs/cclass/notes/sx13.html

 5
Author: DVK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-11 23:04:34

Dos enfoques saltan a la mente.

Primero, no uses scanf. Use fgets() que toma un parámetro para especificar el tamaño del búfer, y que deja intactos los caracteres de nueva línea. Un simple bucle sobre el archivo que imprime el contenido del búfer debería copiar naturalmente el archivo intacto.

En segundo lugar, use fread() o el lenguaje común C con fgetc(). Estos procesarían el archivo en trozos de tamaño fijo o un solo carácter a la vez.

Si debe procesar el archivo sobre espacios en blanco delimitados cadenas, luego use fgets o fread para leer el archivo, y algo como strtok para dividir el búfer en espacios en blanco. No olvide manejar la transición de un búfer al siguiente, ya que es probable que sus cadenas de destino abarquen el límite del búfer.

Si hay un requisito externo para usar scanf para hacer la lectura, entonces limite la longitud de la cadena que podría leer con un campo de precisión en el especificador de formato. En su caso con un búfer de 999 bytes, entonces diga scanf("%998s", str); que escribirá como máximo 998 caracteres en el búfer dejando espacio para el terminador nul. Si se permiten cadenas simples más largas que su búfer, entonces tendría que procesarlas en dos piezas. Si no, tiene la oportunidad de informar al usuario sobre un error cortésmente sin crear un agujero de seguridad de desbordamiento de búfer.

De todos modos, siempre valide los valores devueltos y piense en cómo manejar entradas malas, maliciosas o simplemente malformadas.

 1
Author: RBerteig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-11 23:03:23
#include <stdio.h>
#include <stdlib.h>
int main() {

int num;
FILE *fptr; 



if ((fptr = fopen("/root/Desktop/my_pass.txt","r")) == NULL) {       // checks if file exists
    puts("File not exists");
    exit(1);                    // for exit(1) is required #include <stdlib.h> 
} else 

fscanf(fptr,"%d", &num);                

printf("My pass is:  %d\n", num);           
fclose(fptr); 

return 0;
}
 1
Author: Odin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-14 17:45:44

Puede usar fgets y limitar el tamaño de la cadena de lectura.

char * fgets ( char * str, int num, FILE * stream );

En su código puede cambiar el while a:

while(fgets(str, 100, file) != EOF) 
 0
Author: Edu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-11 22:59:54

Puede leer todo el archivo con asignación de memoria dinámica, pero no es una buena idea porque si el archivo es demasiado grande, podría tener problemas de memoria.

Así que es mejor leer partes cortas del archivo e imprimirlo.

#include <stdio.h>
#define BLOCK   1000

int main() {
    FILE *f=fopen("teste.txt","r");
    int size;
    char buffer[BLOCK];
    // ...
    while((size=fread(buffer,BLOCK,sizeof(char),f)>0)
            fwrite(buffer,size,sizeof(char),stdout);
    fclose(f);
    // ...
    return 0;
}
 0
Author: rigon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-11 23:17:52