在 C 中,我应该如何读取文本文件并打印所有字符串
Posted
技术标签:
【中文标题】在 C 中,我应该如何读取文本文件并打印所有字符串【英文标题】:In C, how should I read a text file and print all strings 【发布时间】:2011-03-28 15:58:00 【问题描述】:我有一个名为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
返回的字符串可能比这更大。我该如何解决这个问题?
【问题讨论】:
【参考方案1】:最简单的方法是读取一个字符,读取后立即打印:
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
。
【讨论】:
不用c/c++打开文件就可以从文件中读取数据?? 如果文本文件包含逗号分隔的整数值怎么办?比代码是什么,您也可以在其中编辑您的答案。 以上适用于任何类型的文本文件。如果你想解析 CSV 文件中的数字,那就是另外一个问题了。 @overexchange 这个问题不涉及行 - 它是关于读取文件并将其内容复制到stdout
。
@shjeff 文件不能包含 EOF 字符。注意c
是int,C会保证EOF
不等于任何有效字符。【参考方案2】:
这里有很多关于分块读取的好答案,我只是向您展示一个小技巧,它可以一次将所有内容读取到缓冲区并打印出来。
我并不是说它更好。并非如此,正如 Ricardo 有时它可能会很糟糕,但我发现它对于简单的情况来说是一个很好的解决方案。
我在上面撒了 cmets,因为发生了很多事情。
#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)
调用fclose(handle)的地方有个错字,应该是fclose(handler)
您可以使用calloc(2)
而不是malloc(1)
来跳过必须设置空终止符。【参考方案3】:
而只是直接将字符打印到控制台上,因为文本文件可能非常大并且您可能需要大量内存。
#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;
【讨论】:
【参考方案4】:使用“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
【讨论】:
read
会让你读入一定数量的字符。读入足够的内容以填充缓冲区,然后将缓冲区转储到屏幕上,将其清除,然后重复直到到达文件末尾。【参考方案5】:
想到了两种方法。
首先,不要使用scanf
。使用fgets()
,它接受一个参数来指定缓冲区大小,并且保持任何换行符不变。打印缓冲区内容的文件的简单循环自然会完整地复制文件。
其次,使用fread()
或常见的C 习惯用法与fgetc()
。它们会以固定大小的块或一次处理单个字符来处理文件。
如果您必须通过空格分隔的字符串处理文件,则使用fgets
或fread
读取文件,并使用strtok
之类的东西在空格处分割缓冲区。不要忘记处理从一个缓冲区到下一个缓冲区的转换,因为您的目标字符串可能会跨越缓冲区边界。
如果有使用scanf
进行读取的外部要求,则使用格式说明符中的精度字段限制它可能读取的字符串的长度。在您使用 999 字节缓冲区的情况下,然后说 scanf("%998s", str);
最多将 998 个字符写入缓冲区,为 nul 终止符留出空间。如果允许长于缓冲区的单个字符串,则必须将它们分成两部分处理。如果没有,您有机会礼貌地告诉用户错误,而不会造成缓冲区溢出安全漏洞。
无论如何,始终验证返回值并考虑如何处理错误、恶意或格式错误的输入。
【讨论】:
【参考方案6】:您可以使用fgets
并限制读取字符串的大小。
char *fgets(char *str, int num, FILE *stream);
您可以将代码中的while
更改为:
while (fgets(str, 100, file)) /* printf("%s", str) */;
【讨论】:
【参考方案7】:您可以通过动态内存分配读取整个文件,但这不是一个好主意,因为如果文件太大,您可能会遇到内存问题。
所以最好阅读文件的一小部分并打印出来。
#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;
【讨论】:
【参考方案8】:您可以使用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);
fclose(file);
return true;
你可以这样使用它:
int main(void)
if (!read_file("test.txt"))
printf("Error reading file\n");
exit(EXIT_FAILURE);
【讨论】:
【参考方案9】:我用这个版本
char* read(char* filename)
FILE* f = fopen(filename, "rb");
if (f == NULL)
exit(1);
fseek(f, 0L, SEEK_END);
long size = ftell(f);
fclose(f);
f = fopen(filename, "r");
void* content = memset(malloc(size), '\0', size);
fread(content, 1, size, f);
fclose(f);
return (char*) content;
【讨论】:
以上是关于在 C 中,我应该如何读取文本文件并打印所有字符串的主要内容,如果未能解决你的问题,请参考以下文章