当前位置:  开发笔记 > 编程语言 > 正文

如何在C中读取文件的内容?

如何解决《如何在C中读取文件的内容?》经验,为你挑选了5个好方法。

什么是最简单的方法(最不容易出错,最少的代码行,但是你想要解释它)在C中打开一个文件并将其内容读入一个字符串(char*,char [],等等)?



1> Nils Pipenbr..:

我倾向于将整个缓冲区作为原始内存块加载到内存中并自行进行解析.这样我就可以最好地控制标准库在多个平台上的功能.

这是我用于此的存根.您可能还想检查fseek,ftell和fread的错误代码.(为清楚起见,省略).

char * buffer = 0;
long length;
FILE * f = fopen (filename, "rb");

if (f)
{
  fseek (f, 0, SEEK_END);
  length = ftell (f);
  fseek (f, 0, SEEK_SET);
  buffer = malloc (length);
  if (buffer)
  {
    fread (buffer, 1, length, f);
  }
  fclose (f);
}

if (buffer)
{
  // start to process your data / extract strings here...
}


由于这是一个登陆页面,我想指出``fread`不会对你的字符串进行零终止.这可能会导致一些麻烦.
正如@Manbroski所说,缓冲区需要'\ 0'终止.所以我会改变`buffer = malloc(length + 1);`并在fclose之后添加:`buffer [length] ='\ 0';`(由Valgrind验证)
像rmeador所说,fseek将失败文件> 4GB.
真正.对于大文件,这个解决方案很糟糕.
我还会检查fread的返回值,因为它可能由于错误而没有实际读取整个文件.
按照freespace所说的,您可能需要检查以确保文件不大.例如,假设有人决定将6GB文件输入该程序......
完成后,不要忘记释放缓冲区。
fseek(f,0,SEEK_END);是二进制流的显式未定义行为。[7.21.9.2`fseek`函数,第3段](http://port70.net/~nsz/c/c11/n1570.html#7.21.9.2p3):* ...二进制流不必有意义地支持*且[C标准的每个脚注268](http://port70.net/~nsz/c/c11/n1570.html#note268):*设置与`fseek(file,0,SEEK_END)`一样,文件末尾的文件位置指示符对于二进制流具有未定义的行为... *
我不认为这曾经打算成为大文件解决方案。将GB的文件读取为单个字符串不是一个好主意。但是对于较小的文件可能就好了:)

2> Jeff Mc..:

另一个不幸的是高度依赖操作系统的解决方案是内存映射文件.优点通常包括读取的性能和减少的内存使用,因为应用程序视图和操作系统文件缓存实际上可以共享物理内存.

POSIX代码如下所示:

int fd = open("filename", O_RDONLY);
int len = lseek(fd, 0, SEEK_END);
void *data = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);

另一方面,Windows稍微有点棘手,不幸的是我没有在我面前测试编译器,但功能是由CreateFileMapping()和提供的MapViewOfFile().


调用lseek()时必须使用off_t而不是int.
不要忘记检查那些系统调用的返回值!

3> dmityugov..:

如果"将其内容读入字符串"意味着该文件不包含代码为0的字符,则还可以使用getdelim()函数,该函数接受内存块并在必要时重新分配,或者仅为整个缓冲区分配您,并将文件读入其中,直到遇到指定的分隔符或文件结尾.只需传递'\ 0'作为分隔符即可读取整个文件.

该功能在GNU C库中可用,http://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getdelim-994

示例代码可能看起来很简单

char* buffer = NULL;
size_t len;
ssize_t bytes_read = getdelim( &buffer, &len, '\0', fp);
if ( bytes_read != -1) {
  /* Success, now the entire file is in the buffer */



4> selwyn..:

如果文件是文本,并且您想逐行获取文本,最简单的方法是使用fgets().

char buffer[100];
FILE *fp = fopen("filename", "r");                 // do not use "rb"
while (fgets(buffer, sizeof(buffer), fp)) {
... do something
}
fclose(fp);



5> Jake..:

如果您正在读取stdin或管道等特殊文件,则无法事先使用fstat来获取文件大小.此外,如果您正在读取二进制文件,则由于嵌入的"\ 0"字符,fgets将丢失字符串大小信息.读取文件的最佳方法是使用read和realloc:

#include 
#include 
#include 
#include 

int main () {
    char buf[4096];
    ssize_t n;
    char *str = NULL;
    size_t len = 0;
    while (n = read(STDIN_FILENO, buf, sizeof buf)) {
        if (n < 0) {
            if (errno == EAGAIN)
                continue;
            perror("read");
            break;
        }
        str = realloc(str, len + n + 1);
        memcpy(str + len, buf, n);
        len += n;
        str[len] = '\0';
    }
    printf("%.*s\n", len, str);
    return 0;
}


realloc()可以将现有内存扩展到新的大小,而无需将旧内存复制到新的更大的内存中。只有在对malloc()进行中间调用时,才需要移动内存并使该解决方案变为O(n ^ 2)。在这里,在对realloc()的调用之间没有对malloc()的调用,因此解决方案应该没问题。
您可以直接读入"str"缓冲区(具有适当的偏移量),而无需从中间"buf"复制.然而,该技术通常会过度分配文件内容所需的内存.另外注意二进制文件,printf无法正确处理它们,你可能不想打印二进制文件!
推荐阅读
依然-狠幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有