Haskell-读取整个Lazy ByteString



上下文:我在一个名为toXlsx :: ByteString -> Xlsx的库中定义了一个函数(ByteString来自Data.ByteString.Lazy)

现在要执行某些操作,我已经定义了对同一文件进行操作的某些函数,因此我想打开,读取并转换为Xlsx文件一次,并将其保存在内存中以对其进行操作。

现在我正在bs <- Data.ByteString.Lazy.readfile file读取文件,最后做Data.ByteString.Lazy.length bs 'seq' return value.

有没有办法使用此功能并将文件作为一个整体保存在内存中以重用它?

请注意,按照惰性字节串的工作方式,文件的内容在被"使用"之前不会被读取,但是一旦被读取,它们将保留在内存中以供任何后续操作使用。 从内存中删除它们的唯一方法是如果它们被垃圾回收,因为您的程序不再有任何方法可以访问它们。

例如,如果在大文件上运行以下程序:

import qualified Data.ByteString.Lazy as BL  
main = do
bigFile <- BL.readFile "ubuntu-14.04-desktop-amd64.iso"
print $ BL.length $ BL.filter (==0) bigFile     -- takes a while
print $ BL.length $ BL.filter (==255) bigFile   -- runs fast

第一次计算实际上会将整个文件读入内存,并将其保留在那里以进行第二次计算。

我想这本身并不太令人信服,因为操作系统也会将文件缓存到内存中,并且最终很难分辨 Haskell 从操作系统缓存中读取文件以进行每次计算并将其保存在内存中之间的时间差异。 但是,如果对此代码运行一些堆分析,您会发现第一个操作将整个文件加载到"固定"字节字符串中,并且分配在后续操作中保持不变。

如果您担心希望在开始时读取整个文件,即使第一个操作不需要读取所有文件,以便在读取文件的其他部分时不会有后续延迟,那么基于seq的解决方案可能没问题。 或者,您可以将整个文件读取为严格的字节串,然后使用fromStrict进行转换 - 此操作是即时的,不会复制任何数据。 (与toStrict相反,后者很昂贵并且确实会复制数据。 所以这将起作用:

import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
main = do
-- read strict
bigFile <- BS.readFile "whatever.mov"
-- do strict and lazy operations
print $ strictOp bigFile
print $ lazyOp (BL.fromStrict bigFile)

最新更新