У меня есть текстовый файл с именем 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
может быть больше. Как я могу это решить?
источник
stdout
.c
это int, и C гарантирует, чтоEOF
он не равен ни одному допустимому символу.Здесь есть много хороших ответов о чтении его по частям, я просто покажу вам небольшой трюк, который считывает весь контент сразу в буфер и печатает его.
Я не говорю, что лучше. Это не так, и, как и у Рикардо, иногда это может быть плохо, но я считаю, что это хорошее решение для простых случаев.
Я посыпал это комментариями, потому что там много всего происходит.
#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; }
Дайте мне знать, если это будет полезно или вы могли бы чему-то научиться :)
источник
buffer[string_size] = '\0';
вместоstring_size+1
? Afaik фактическая строка идет от0
кstring_size-1
и\0
символ, таким образом, должен быть вstring_size
, верно?ftell
иfseek
для определения размера файла небезопасно: securecoding.cert.org/confluence/display/seccode/…fclose(handle)
calloc(2)
а неmalloc(1)
пропустить установку нулевого терминатора.Вместо этого просто напечатайте символы прямо на консоли, потому что текстовый файл может быть очень большим, и вам может потребоваться много памяти.
#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; }
источник
Используйте "read ()" вместо fscanf:
ssize_t read(int fildes, void *buf, size_t nbyte);
Вот пример:
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источник
read
позволит вам прочитать определенное количество символов. Прочтите достаточно, чтобы заполнить буфер, затем выгрузите буфер на экран, очистите его и повторяйте, пока не дойдете до конца файла.На ум приходят два подхода.
Во-первых, не используйте
scanf
. Используйтеfgets()
который принимает параметр, чтобы указать размер буфера, и оставляет любые символы новой строки нетронутыми. Простой цикл над файлом, который печатает содержимое буфера, должен, естественно, скопировать файл без изменений.Во- вторых, использование
fread()
или общий C идиомы сfgetc()
. Они будут обрабатывать файл кусками фиксированного размера или по одному символу за раз.Если вы должны обработать файл поверх строк, разделенных пробелами, используйте либо,
fgets
либо,fread
чтобы прочитать файл, и что-то вродеstrtok
разделения буфера на пробелы. Не забывайте обрабатывать переход от одного буфера к другому, так как ваши целевые строки, вероятно, будут выходить за границы буфера.Если есть внешнее требование для использования
scanf
для чтения, ограничьте длину строки, которую она может прочитать, с помощью поля точности в описателе формата. В вашем случае с 999-байтовым буфером скажите,scanf("%998s", str);
который будет записывать не более 998 символов в буфер, оставляя место для нулевого терминатора. Если разрешены отдельные строки длиннее, чем ваш буфер, вам придется обрабатывать их двумя частями. Если нет, у вас есть возможность вежливо сообщить пользователю об ошибке, не создавая бреши в защите от переполнения буфера.В любом случае всегда проверяйте возвращаемые значения и думайте о том, как обрабатывать неверный, злонамеренный или просто искаженный ввод.
источник
Вы можете использовать
fgets
и ограничивать размер читаемой строки.char *fgets(char *str, int num, FILE *stream);
Вы можете изменить
while
в своем коде на:while (fgets(str, 100, file)) /* printf("%s", str) */;
источник
Вы можете прочитать весь файл с динамическим распределением памяти, но это не лучшая идея, потому что, если файл слишком большой, у вас могут быть проблемы с памятью.
Так что лучше читать короткие части файла и распечатывать.
#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; }
источник