我想读取一个文件,但是它太大了,无法将它完全装入内存中。
有没有一种不用把它装入内存就能读取它的方法?还是有更好的解决方案?
发布于 2018-01-02 20:23:42
我需要内容来做校验和,所以我需要完整的消息。
许多校验和库支持对校验和的增量更新。例如,GLib有g_checksum_update()
。因此,您可以使用fread
一次读取一个块文件,并在读取时更新校验和。
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <glib.h>
int main(void) {
char filename[] = "test.txt";
// Create a SHA256 checksum
GChecksum *sum = g_checksum_new(G_CHECKSUM_SHA256);
if( sum == NULL ) {
fprintf(stderr, "Could not create checksum.\n");
exit(1);
}
// Open the file we'll be checksuming.
FILE *fp = fopen( filename, "rb" );
if( fp == NULL ) {
fprintf(stderr, "Could not open %s: %s.\n", filename, strerror(errno));
exit(1);
}
// Read one buffer full at a time (BUFSIZ is from stdio.h)
// and update the checksum.
unsigned char buf[BUFSIZ];
size_t size_read = 0;
while( (size_read = fread(buf, 1, sizeof(buf), fp)) != 0 ) {
// Update the checksum
g_checksum_update(sum, buf, (gssize)size_read);
}
// Print the checksum.
printf("%s %s\n", g_checksum_get_string(sum), filename);
}
我们可以通过与sha256sum
的结果进行比较来检验它的工作性能。
$ ./test
0c46af5bce717d706cc44e8c60dde57dbc13ad8106a8e056122a39175e2caef8 test.txt
$ sha256sum test.txt
0c46af5bce717d706cc44e8c60dde57dbc13ad8106a8e056122a39175e2caef8 test.txt
发布于 2018-01-02 18:27:16
如果问题是内存而不是虚拟地址空间,那么其中一种方法是内存映射文件,或者在POSIX系统上映射mmap
,或者在CreateFileMapping
上映射文件。
这可以获得文件字节的原始数组,但是操作系统负责在执行过程中分页内容(如果您更改它们,则将它们写回磁盘)。映射为只读时,它非常类似于内存块malloc
-ing和填充它的fread
-ing,但是:
malloc
-ed内存,它必须将其写出来以进行交换,从而增加磁盘上可能已经超额订阅的磁盘流量。就性能而言,在默认设置下,这可能会稍微慢一些(因为在没有内存压力的情况下,读取整个文件可以保证当请求时它将在内存中,而随机访问内存映射的文件可能会触发按需页错误以在第一次访问时填充每个页面),尽管您可以使用posix_madvise
与POSIX_MADV_WILLNEED
(POSIX系统)或PrefetchVirtualMemory
(Windows 8及更高版本)一起提供整个文件将被需要的提示,从而导致系统(通常)在后台(通常)在访问它时将其分页。在POSIX系统上,当不需要(或可能)同时分页整个文件时,其他advise
提示可以用于更细粒度的提示,例如,如果您从头到尾读取文件数据,则使用POSIX_MADV_SEQUENTIAL
通常会触发对后续页面的更积极的预取,增加它们在到达时在内存中的可能性。通过这样做,您可以获得两个世界的优势;您几乎可以立即开始访问数据,延迟访问尚未被传呼的页面,但是操作系统将在后台为您预装页面,因此您最终将以最快的速度运行(同时仍然能够更好地抵御内存压力,因为操作系统只会丢弃干净的页面,而不是先编写它们以进行交换)。
这里的主要限制是虚拟地址空间。如果您使用的是32位系统,则很可能被限制在(取决于现有地址空间的碎片化程度) 1-3 GB的连续地址空间,这意味着您必须以块的形式映射该文件,并且不能在任何时候按需随机访问文件中的任何点而不需要额外的系统调用。值得庆幸的是,在64位系统上,这种限制很少出现;即使是最限制的64位系统(Windows 7)也为每个进程提供了8 TB的用户虚拟地址空间,远远大于您可能遇到的绝大多数文件(后来的版本将上限提高到128 TB)。
https://stackoverflow.com/questions/48065547
复制相似问题