В C, как я должен прочитать текстовый файл и распечатать все строки - PullRequest
78 голосов
/ 12 августа 2010

У меня есть текстовый файл с именем test.txt

Я хочу написать программу на C, которая может прочитать этот файл и распечатать содержимое на консоли (предположим, что файл содержит только текст ASCII).

Я не знаю, как получить размер моей строковой переменной. Как это:

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

Размер 999 не работает, потому что строка, возвращаемая fscanf, может быть больше, чем эта. Как я могу решить это?

Ответы [ 8 ]

119 голосов
/ 12 августа 2010

Самый простой способ - прочитать символ и распечатать его сразу после прочтения:

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

c - это int выше, поскольку EOF - отрицательное число, а обычное char может быть unsigned.

Если вы хотите прочитать файл порциями, но без динамического выделения памяти, вы можете сделать:

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

Второй метод, описанный выше, по сути, заключается в том, как вы будете читать файл с динамически размещенным массивом:

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

Ваш метод fscanf() с форматом %s теряет информацию о пробелах в файле, поэтому он не копирует файл точно в stdout.

51 голосов
/ 12 августа 2010

Здесь есть много хороших ответов о чтении этого в виде фрагментов, я просто покажу вам небольшой трюк, который читает все содержимое сразу в буфер и печатает его.

Я не говорю, что лучше. Это не так, и, как Рикардо, иногда это может быть плохо, но я считаю, что это хорошее решение для простых случаев.

Я посыпал его комментариями, потому что там много чего происходит.

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

Дайте мне знать, если это полезно, или вы могли бы чему-то научиться из этого:)

12 голосов
/ 23 августа 2013

Вместо этого просто печатайте символы непосредственно на консоли, потому что текстовый файл может быть очень большим и вам может потребоваться много памяти.

#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;
}
5 голосов
/ 12 августа 2010

Используйте «read ()» вместо o fscanf:

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

ОПИСАНИЕ

Функция read () должна попытаться прочитать nbyte байт из файла, связанного с дескриптором открытого файла, fildes, в буфер, на который указывает buf.

Вот пример:

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

Рабочая часть из этого примера:

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

Альтернативный подход заключается в использовании getc / putc для чтения / записи 1 символа за раз. Намного менее эффективно. Хороший пример: http://www.eskimo.com/~scs/cclass/notes/sx13.html

1 голос
/ 14 августа 2018
#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 голос
/ 12 августа 2010

Вы можете использовать fgets и ограничить размер прочитанной строки.

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

Вы можете изменить while в своем коде на:

while (fgets(str, 100, file)) /* printf("%s", str) */;
0 голосов
/ 12 августа 2010

Вы можете прочитать весь файл с динамическим распределением памяти, но это не очень хорошая идея, потому что, если файл слишком большой, у вас могут возникнуть проблемы с памятью.

Так что лучше читать короткие части файлаи распечатайте его.

#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 голосов
/ 12 августа 2010

Два подхода приходят на ум.

Во-первых, не используйте scanf.Используйте fgets(), который принимает параметр для указания размера буфера и который оставляет любые символы новой строки без изменений.Простой цикл по файлу, который печатает содержимое буфера, должен естественным образом копировать файл без изменений.

Во-вторых, используйте fread() или обычную C-идиому с fgetc().Они будут обрабатывать файл в виде фрагментов фиксированного размера или по одному символу за раз.

Если вам нужно обработать файл через строки, разделенные пробелами, то используйте fgets или fread для чтенияфайл и что-то вроде strtok, чтобы разделить буфер в пробел.Не забудьте обработать переход от одного буфера к следующему, так как ваши целевые строки могут охватывать границу буфера.

Если существует внешнее требование использовать scanf для чтения, тогдаограничить длину строки, которую он может прочитать, с помощью поля точности в спецификаторе формата.В вашем случае с 999-байтовым буфером, затем произнесите scanf("%998s", str);, который запишет не более 998 символов в буфер, оставляя место для нулевого терминатора.Если разрешены отдельные строки длиннее, чем ваш буфер, то вам придется обрабатывать их двумя частями.Если нет, у вас есть возможность вежливо сообщить пользователю об ошибке, не создавая дыру в безопасности переполнения буфера.

Независимо от этого, всегда проверяйте возвращаемые значения и думайте о том, как обрабатывать неверный, злонамеренный или просто искаженный ввод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...