繁体   English   中英

用C读取任意长度的文件

[英]Reading a file of arbitrary length in C

在 C 中读取任意长度文件的最惯用/最有效的方法是什么?

  1. 以字节为单位获取文件的文件大小并发出单个fread()
  2. 保持fread()一个恒定大小的缓冲区,直到获得 EOF
  3. 还要别的吗?

避免使用任何需要提前知道文件大小的技术。 只剩下一种技术:一次读取一点文件,以方便的大小块为单位。

这就是您不想尝试提前查找文件大小的原因:

  1. 如果它不是常规文件,则可能无法分辨。 例如,您可能直接从控制台读取数据,或者从以前的数据生成器获取管道输入。 如果您的程序要求文件大小是可知的,那么这些有用的输入机制对您的用户将不可用,他们会抱怨或选择不同的工具。

  2. 即使您可以计算出文件大小,您也无法在读取文件时阻止其更改。 如果您不小心阅读文件的方式,您可能会打开一个漏洞,该漏洞可能会被对抗性程序利用。

    例如,如果您分配一个“正确”大小的缓冲区,然后读取直到出现文件结束条件,您最终可能会覆盖随机内存。 (如果您使用read()类的接口可能读取的数据少于请求的数据,则可能需要多次读取。)或者您可能会发现文件已被截断; 如果不检查读取的数据量,最终可能会处理未初始化的内存,从而导致信息泄漏。

实际上,您通常不需要将整个文件内容保存在内存中。 您经常会解析文件(特别是如果它是文本文件),或者至少以较小的部分读取文件,为此您不需要完全在内存中。 对于文本文件,逐行读取(可能在解析器中包含某种状态)通常就足够了(使用fgetsgetline )。

文件存在(特别是在磁盘SSD 上),因为它们通常比您的计算机 RAM“大”得多。 实际上,已经发明了文件(50 多年前)能够处理大于内存的数据。 分布式文件系统也可以非常大(甚至可以从笔记本电脑远程访问,例如通过NFSCIFS等......)

某些文件系统能够存储 PB 级的数据(在超级计算机上),单个文件的容量为 TB 级(远大于可用 RAM)。

您还可能会使用一些database 这些通常具有数 TB 的数据。 另请参阅答案(关于sqlite数据库的实际大小)。

如果你真的想使用 stdio 完全读取内存中的文件(但你应该避免这样做,因为你通常希望你的程序能够处理文件上的大量数据;所以读取内存中的整个文件通常是一种设计错误),你确实可以循环fread (或fscanf ,甚至fgetc )直到文件结束。 请注意, feof某些输入操作之后才有用。

在当前的膝上型计算机或台式计算机上,您可能更喜欢(为了效率)使用几兆字节的缓冲区,并且您当然可以处理数百 GB(比您的 RAM 大得多)的大文件。

在 POSIX 文件系统上,您可以使用例如mmap(2)进行内存映射 IO - 但这可能不会比使用大缓冲区(几兆字节)的read(2)快。 您可以使用readahead(2) (Linux 特定)和posix_fadvise(2) (或madvise(2)如果使用mmap )通过提示您的操作系统内核来调整性能。

如果您必须为 Microsoft Windows 编写代码,您可以研究它的WinAPI找到一些方法来进行内存映射 IO。

在实践中,文件数据(尤其是最近访问过的文件)通常保留在页面缓存中,这对性能至关重要。 如果不是这种情况,您的硬件(磁盘、控制器等)就会成为瓶颈,并且您的程序会受到I/O 限制(在这种情况下,没有任何软件技巧可以显着提高性能)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM