如何在大文件上有效地使用 file input/output 函数(使用有限大小的内存)
How to use file input/output functions efficiently on large files (using limited size of memory)
我想在 C++ 上实现一个算法,其中包括许多文件 i/o。虽然我已经在较小的规模上实现了类似的东西,但这次我需要处理几个 GB 的文件。我知道当文件大小大于可用内存大小时,我应该考虑一些新的事情,而且我还应该关心成本。
我的计划是获取分配的内存大小并用它读取预定部分并保存结果在 txt 文件上 每次通过。但是,我需要在每次通过后逐行读取和修改生成的txt文件来更新它,因为生成的txt文件将是一个链表(字节块将对应于节点).
将这些遍的结果保存在一个 txt 文件中并为每个遍逐行更新它是否有效?如果您能告诉我任何可以提高算法效率的更改,我将不胜感激。如果您能写一些 short/quick 示例,我将不胜感激,因为除了 "read this entire file"、"write this as entire file" 类型的命令之外,我从未使用过文件输入输出。
编辑:
操作系统是 Linux 和 Mac OS。
二进制文件中有很多重复的字节段,我想对某些组合重复的次数进行排序。例如,如果一个二进制文件是 111111100000001110101010100000111,我将计算一些预定模式(如 110111001010、10101011 等)的出现次数并对其进行排序。我预计的最小文件大小为 1GB,最大文件大小约为 10-20GB。我将寻找大约 1,000,000,000 种模式并将它们全部排序。所以我想既然每次缓冲区满了我都需要更新输出文件,我不妨把它做成一个链表并更新列表(应该是~O(n))以避免进行快速排序(应该是~ nlog(n)) 最后。
这是一种有效的方法:
打开您的源文件并使用 mmap()
访问您的数据。通过这种方式,您可以直接访问 OS disk-cahe
,并且 无需将内存 从 kernel mode
复制到 user mode
。如果你的文件真的很大,最好使用较小的 mmapp-ed views
来防止创建大页表。
根据您使用的不同模式的数量,您有以下选择:
如果模式的数量足够小以适应内存:
- 如果值稀疏:将它们存储在
map
和 pattern/count 对中。
- 如果值有些连续,将计数存储在
vector
中,其中位置是您的模式的值,如果需要,基于偏移量。
如果花样的数量可以变大:
(你说的是 10 亿个模式——取决于它们的独特性),你可以创建一个 mmap-ed outputfile
并将计数存储在那里,但要确保所有值(或对)都是相同的宽度,即以二进制形式存储所有内容(您可以像使用数组一样使用它)。
如果大多数值是不同的,将它们存储在您的模式值的位置 - 例如,如果模式(32 位?)+ 计数是 8 个字节,将它们存储在位置 pattern-value * 8
以便快速使用权。如果您的模式值存在较大差距,但您希望避免插入移动数据,请考虑使用(临时)sparse file
将值直接存储在正确的位置。
如果您只需要一个计数,您可以只将计数(32 位)存储在它们的特定位置,但如果您需要排序,您还需要某种模式值。
要对它们进行排序,我更喜欢使用 radix sort
。
我想在 C++ 上实现一个算法,其中包括许多文件 i/o。虽然我已经在较小的规模上实现了类似的东西,但这次我需要处理几个 GB 的文件。我知道当文件大小大于可用内存大小时,我应该考虑一些新的事情,而且我还应该关心成本。
我的计划是获取分配的内存大小并用它读取预定部分并保存结果在 txt 文件上 每次通过。但是,我需要在每次通过后逐行读取和修改生成的txt文件来更新它,因为生成的txt文件将是一个链表(字节块将对应于节点).
将这些遍的结果保存在一个 txt 文件中并为每个遍逐行更新它是否有效?如果您能告诉我任何可以提高算法效率的更改,我将不胜感激。如果您能写一些 short/quick 示例,我将不胜感激,因为除了 "read this entire file"、"write this as entire file" 类型的命令之外,我从未使用过文件输入输出。
编辑: 操作系统是 Linux 和 Mac OS。
二进制文件中有很多重复的字节段,我想对某些组合重复的次数进行排序。例如,如果一个二进制文件是 111111100000001110101010100000111,我将计算一些预定模式(如 110111001010、10101011 等)的出现次数并对其进行排序。我预计的最小文件大小为 1GB,最大文件大小约为 10-20GB。我将寻找大约 1,000,000,000 种模式并将它们全部排序。所以我想既然每次缓冲区满了我都需要更新输出文件,我不妨把它做成一个链表并更新列表(应该是~O(n))以避免进行快速排序(应该是~ nlog(n)) 最后。
这是一种有效的方法:
打开您的源文件并使用 mmap()
访问您的数据。通过这种方式,您可以直接访问 OS disk-cahe
,并且 无需将内存 从 kernel mode
复制到 user mode
。如果你的文件真的很大,最好使用较小的 mmapp-ed views
来防止创建大页表。
根据您使用的不同模式的数量,您有以下选择:
如果模式的数量足够小以适应内存:
- 如果值稀疏:将它们存储在
map
和 pattern/count 对中。 - 如果值有些连续,将计数存储在
vector
中,其中位置是您的模式的值,如果需要,基于偏移量。
如果花样的数量可以变大:
(你说的是 10 亿个模式——取决于它们的独特性),你可以创建一个 mmap-ed outputfile
并将计数存储在那里,但要确保所有值(或对)都是相同的宽度,即以二进制形式存储所有内容(您可以像使用数组一样使用它)。
如果大多数值是不同的,将它们存储在您的模式值的位置 - 例如,如果模式(32 位?)+ 计数是 8 个字节,将它们存储在位置 pattern-value * 8
以便快速使用权。如果您的模式值存在较大差距,但您希望避免插入移动数据,请考虑使用(临时)sparse file
将值直接存储在正确的位置。
如果您只需要一个计数,您可以只将计数(32 位)存储在它们的特定位置,但如果您需要排序,您还需要某种模式值。
要对它们进行排序,我更喜欢使用 radix sort
。