我的问题:
我的文件大小约为4GB。我从未使用过fseeko / ftello,而且我对磁盘上文件的组织方式也不太熟悉。如果我打开一个文件,然后让fseeko跳转到比如文件的2,348,973,408个字节,它是否必须按顺序遍历数千个链接在一起的块头(或某些这样的东西),就像链接列表一样到达我的4GB文件的中间?或者它是否有更有效的方式随机访问文件?我正在寻找一种有效跳转到非常大的文件的特定字节的方法。如果这不能有效地工作,我已经考虑过将文件分成4000个1兆字节的文件,每个文件都可以更加高效。有什么建议吗?
背景:
我计算了一个具有近5亿双精度数的大型6维数组,它代表了复杂问题的解决方案。每个8字节,作为单个文件写入的数据集占用近4 GB的磁盘空间。我想编写一个小服务器应用程序来接收对这些数据的小连续范围的请求,并返回所请求的数据。
现在我可以只是将整个文件读入RAM,但我打算让这台服务器一直运行并且在我的服务器上占用8GB内存的一半。所以我不想这样做。相反,我想将它留在磁盘上并读取请求的数据页面,响应请求,然后再次从RAM中删除页面。
我的下一个想法是将数据加载到数据库中,但是当我将6个indicees与每个8字节数据值一起存储时,并在表格上抛出索引(为了快速查找),我&#39 ;我认为数据库的大小将比4GB文件大一个数量级。这不会是世界末日,但我将来可能会添加更多这些大文件,而我宁愿没有这么多数据。这里可能还有其他选项:我可以使用二进制varchar或其他类似的东西将整页数据存储到一行中。
但这让我想知道我是否找不到直接从文件中有效访问数据的方法。我知道我想要的文件的字节数。问题是,是否有快速的方式来达到目的。因此我的问题是关于上面的fseeko。
答案 0 :(得分:1)
原则上,fseek()
应该很快。
但是,您是否在文本模式下使用文件时需要注意:
如果处于文本模式,fseek()
保证仅根据ftell()
之前返回的位置按标准工作,或者从文件开头返回0。对其他参数组合的支持取决于实现。 Fortuantely,在大多数操作系统上,它也可以在文件末尾使用0。
在二进制模式下,您没有此类限制。
文本模式限制的目的是避免使用直接定位时可能出现的不一致(因为文本模式在读取的字节和磁盘上的字节之间没有一对一的映射)。
编辑:其他信息背景
我认为您使用二进制文件来存储所有这些数字并采用固定大小的格式:
在我看来,数据库在这里没有意义。
如果您的服务器运行64位操作系统并且您的交换区域有足够的磁盘空间,则可以选择将完整数据集加载到内存中:它将加载到虚拟内存中,操作系统会照顾优化加载到可用RAM中的内存页面。
如果您使用非常不规则的模式浏览文件,则交换也可能会触发大量文件读取。然后,使用fseek()直接转到使用6维索引计算的位置将是一个明智的选择。
最后,您还可以选择使用memory mapped files,例如POSIX mmap()
或Windows MapViewOfFile()
。这非常适合阵列。然而,遗憾的是,这不像标准C ++那样可移植。
答案 1 :(得分:1)
它取决于文件系统,但通常将文件内部的块编号与磁盘上的物理块之间的映射组织为浅的高扇出树。由于扇出通常为1024,因此大文件的树深度通常为2。 (ext2 / 3将树深限制为三个,仍然设法处理大量文件; ext4使用更复杂的结构,效率更高。)
(过于简单化了。这里是more precise description。
查找块编号需要读取间接块(树节点),但这些块往往留在内存缓存中,因此读取相对较少。