Haskell - 读取整个 Lazy ByteString
Haskell - Reading entire Lazy ByteString
上下文: 我在名为 toXlsx :: ByteString -> Xlsx
的库中定义了一个函数(该 ByteString 来自 Data.ByteString.Lazy)
现在要执行某些操作,我已经定义了对同一文件进行操作的某些函数,因此我想打开、读取文件并将其转换为 Xlsx 一次,并将其保存在内存中以对其进行操作。
现在我正在读取文件 bs <- Data.ByteString.Lazy.readfile file
并在最后做 Data.ByteString.Lazy.length bs 'seq' return value
.
有什么方法可以使用这个功能,将文件作为一个整体保存在内存中,以便重复使用吗?
请注意,惰性字节串的工作方式是,文件内容在 "used" 之前不会被读取,但一旦读取,它们将保留在内存中以供后续操作使用。它们将从内存中删除的唯一方法是它们被垃圾收集,因为您的程序不再有任何方法访问它们。
例如,如果您 运行 对大文件执行以下程序:
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 从每个计算的操作系统缓存,并在所有计算中将其保存在内存中。但是,如果您 运行 对此代码进行一些堆分析,您会发现第一个操作将整个文件加载到 "pinned" 字节串中,并且该分配在后续操作中保持不变。
如果您担心的是希望在开始时读取完整的文件,即使第一个操作不需要全部读取,这样就不会因为文件的其他部分而导致后续延迟阅读,那么您基于 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)
上下文: 我在名为 toXlsx :: ByteString -> Xlsx
的库中定义了一个函数(该 ByteString 来自 Data.ByteString.Lazy)
现在要执行某些操作,我已经定义了对同一文件进行操作的某些函数,因此我想打开、读取文件并将其转换为 Xlsx 一次,并将其保存在内存中以对其进行操作。
现在我正在读取文件 bs <- Data.ByteString.Lazy.readfile file
并在最后做 Data.ByteString.Lazy.length bs 'seq' return value
.
有什么方法可以使用这个功能,将文件作为一个整体保存在内存中,以便重复使用吗?
请注意,惰性字节串的工作方式是,文件内容在 "used" 之前不会被读取,但一旦读取,它们将保留在内存中以供后续操作使用。它们将从内存中删除的唯一方法是它们被垃圾收集,因为您的程序不再有任何方法访问它们。
例如,如果您 运行 对大文件执行以下程序:
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 从每个计算的操作系统缓存,并在所有计算中将其保存在内存中。但是,如果您 运行 对此代码进行一些堆分析,您会发现第一个操作将整个文件加载到 "pinned" 字节串中,并且该分配在后续操作中保持不变。
如果您担心的是希望在开始时读取完整的文件,即使第一个操作不需要全部读取,这样就不会因为文件的其他部分而导致后续延迟阅读,那么您基于 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)