В C, как я должен считать текстовый файл и распечатать все строки

Мне назвали текстовый файл 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 может быть больше, чем это. Как я могу решить это?

81
задан bta 11 August 2010 в 23:07
поделиться

6 ответов

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

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

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

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

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

121
ответ дан 24 November 2019 в 09:31
поделиться

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

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

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

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

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

54
ответ дан 24 November 2019 в 09:31
поделиться

Используйте "read ()" вместо 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

6
ответ дан 24 November 2019 в 09:31
поделиться

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

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

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

while (fgets(str, 100, file)) /* printf("%s", str) */;
1
ответ дан 24 November 2019 в 09:31
поделиться

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

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

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

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

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

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

1
ответ дан 24 November 2019 в 09:31
поделиться

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

Поэтому лучше читать короткие части файла и выводить их на печать.

#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
ответ дан 24 November 2019 в 09:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: