Мне назвали текстовый файл 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
может быть больше, чем это. Как я могу решить это?
Самый простой способ - прочитать символ и распечатать его сразу после прочтения:
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
.
Здесь есть много хороших ответов о чтении его по частям. Я просто покажу вам небольшой трюк, который считывает все содержимое сразу в буфер и печатает его.
Я не говорю, что так лучше. Это не так, и, как Рикардо, иногда это может быть плохо, но я считаю, что это хорошее решение для простых случаев.
Я посыпал это комментариями, потому что там много всего происходит.
#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;
}
Дайте мне знать, если это будет полезно или вы могли бы чему-то научиться :)
Используйте "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
Вы можете использовать fgets
и ограничить размер строки чтения.
char *fgets(char *str, int num, FILE *stream);
Вы можете изменить while
в вашем коде на:
while (fgets(str, 100, file)) /* printf("%s", str) */;
На ум приходят два подхода.
Во-первых, не используйте scanf
. Используйте fgets ()
, который принимает параметр для указания размера буфера и оставляет любые символы новой строки нетронутыми. Простой цикл над файлом, который печатает содержимое буфера, должен, естественно, скопировать файл без изменений.
Во-вторых, используйте fread ()
или обычную идиому C с fgetc ()
. Они будут обрабатывать файл кусками фиксированного размера или по одному символу за раз.
Если вы должны обработать файл по строкам, разделенным пробелами, используйте либо fgets
, либо fread
, чтобы прочитать файл, и что-то вроде strtok
для разделить буфер на пробелы.Не забудьте обработать переход от одного буфера к другому, так как ваши целевые строки, вероятно, будут выходить за границу буфера.
Если есть внешнее требование использовать scanf
для чтения, то ограничьте длину строки, которую она может прочитать, с помощью поля точности в спецификаторе формата. В вашем случае с 999-байтовым буфером, скажите scanf ("% 998s", str);
, который запишет в буфер не более 998 символов, оставляя место для нулевого терминатора. Если разрешены отдельные строки длиннее, чем ваш буфер, вам придется обрабатывать их двумя частями. Если нет, у вас есть возможность вежливо сообщить пользователю об ошибке, не создавая дыры в защите от переполнения буфера.
В любом случае, всегда проверяйте возвращаемые значения и думайте о том, как обрабатывать неверный, злонамеренный или просто искаженный ввод.
Вы можете прочитать весь файл с динамическим распределением памяти, но это не очень хорошая идея, потому что если файл слишком большой, у вас могут возникнуть проблемы с памятью.
Поэтому лучше читать короткие части файла и выводить их на печать.
#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;
}