【问题标题】:Haskell - Reading entire Lazy ByteStringHaskell - 读取整个惰性字节字符串
【发布时间】:2018-08-07 11:57:20
【问题描述】:

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

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

现在我以bs <- Data.ByteString.Lazy.readfile file 的身份读取文件,最后以Data.ByteString.Lazy.length bs 'seq' return value 读取。

有没有什么办法可以使用这个功能,把文件作为一个整体保存在内存中,以便重复使用?

【问题讨论】:

    标签: haskell lazy-evaluation bytestring


    【解决方案1】:

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

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

    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)
    

    【讨论】:

    • 谢谢,您能帮上忙!这正是我所需要的
    猜你喜欢
    • 2013-06-21
    • 2012-04-26
    • 2011-12-10
    • 1970-01-01
    • 2015-04-24
    • 2017-12-02
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多