In C, how should I read a text file and print all strings

I have a text file named test.txt

I want to write a C program that can read this file and print the content to the console (assume the file contains only ASCII text).

I don't know how to get the size of my string variable. Like this:

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

The size 999 doesn't work because the string returned by fscanf can be larger than that. How can I solve this?

742125 次浏览

使用“ read ()”代替 fScanf:

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

描述

Read ()函数将尝试从与打开的文件描述符 fildes相关联的文件中读取 nbyte字节到 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);

You can change the while in your code to:

while (fgets(str, 100, file)) /* printf("%s", str) */;

Two approaches leap to mind.

首先,不要使用 scanf。使用 fgets(),它接受一个参数来指定缓冲区大小,并保留所有换行符的完整性。在打印缓冲区内容的文件上进行一个简单的循环,就可以完整地复制文件。

第二,在 fgetc()中使用 fread()或常用的 C 语言习惯用法。它们将一次处理固定大小的块或单个字符的文件。

If you must process the file over white-space delimited strings, then use either fgets or fread to read the file, and something like strtok to split the buffer at whitespace. Don't forget to handle the transition from one buffer to the next, since your target strings are likely to span the buffer boundary.

如果外部需要使用 scanf进行读取,那么在格式说明符中使用精确字段限制它可能读取的字符串的长度。在使用999字节缓冲区的情况下,然后说 scanf("%998s", str);,它将向缓冲区写入最多998个字符,从而为 null 结束符留出空间。如果允许单个字符串长于缓冲区,则必须将它们分成两部分进行处理。如果没有,您就有机会礼貌地告诉用户一个错误,而不会造成缓冲区溢出安全漏洞。

Regardless, always validate the return values and think about how to handle bad, malicious, or just malformed input.

您可以使用动态内存分配来读取整个文件,但这不是一个好主意,因为如果文件太大,您可能会出现内存问题。

因此,最好读取文件的简短部分并打印它。

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

最简单的方法是阅读一个字符,并在阅读后立即打印出来:

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

cint之上,因为 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 */
}

使用 %s作为格式的 fscanf()方法丢失了关于文件中空格的信息,所以它并不是将文件复制到 stdout

这里有很多关于分块读取的好答案,我将给你们展示一个小技巧,它可以一次读取所有内容到一个缓冲区并打印出来。

我不是说这样更好。不是这样的,就像 Ricardo 有时候会很糟糕,但是我发现这对于简单的情况来说是一个很好的解决方案。

我加了一些评论,因为发生了很多事情。

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

让我知道它是否有用,或者你可以从中学到一些东西:)

而是直接将字符打印到控制台上,因为文本文件可能非常大,并且可能需要大量内存。

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

您可以使用 getline()读取文本文件,而不必担心大行:

getline()stream中读取整行,将包含文本的缓冲区的地址存储到 *lineptr中。缓冲区以空结尾,如果找到换行符,则包含换行符。

如果在调用之前将 *lineptr设置为 NULL,那么 getline()将分配一个用于存储线路的缓冲区。此缓冲区由用户程序 should be freed编写 即使 getline() 失败了。

bool read_file(const char *filename)
{
FILE *file = fopen(filename, "r");
if (!file)
return false;
    

char *line = NULL;
size_t linesize = 0;


while (getline(&line, &linesize, file) != -1) {
printf("%s", line);
free(line);
}
    

free(line);
fclose(file);


return true;
}

你可以这样使用它:

int main(void)
{
if (!read_file("test.txt")) {
printf("Error reading file\n");
exit(EXIT_FAILURE);
}
}

我用这个版本

char* read(const char* filename){
FILE* f = fopen(filename, "rb");
if (f == NULL){
exit(1);
}
fseek(f, 0L, SEEK_END);
long size = ftell(f)+1;
fclose(f);
f = fopen(filename, "r");
void* content = memset(malloc(size), '\0', size);
fread(content, 1, size-1, f);
fclose(f);
return (char*) content;
}