【发布时间】:2017-11-20 08:24:59
【问题描述】:
考虑以下简单的 Haskell 程序,它将文件作为字节串读取并从该字节串写入文件tmp.tmp:
module Main
where
import System.Environment
import qualified Data.ByteString.Lazy as B
main :: IO ()
main = do
[file] <- getArgs
bs <- B.readFile file
action <- B.writeFile "tmp.tmp" bs
putStrLn "done"
它被编译成一个名为tmptmp的可执行文件。
我的电脑上有两个硬盘驱动器:C 驱动器和 U 驱动器,这个是网络驱动器,这个网络驱动器处于脱机状态。
现在,让我们试试tmptmp。
当我从C 运行它时,没有问题;我在下面运行了两次,第一次使用C 上的文件,第二次使用U 上的文件:
C:\HaskellProjects\imagelength> tmptmp LICENSE
done
C:\HaskellProjects\imagelength> tmptmp U:\Data\ztemp\test.xlsx
done
现在我从U 运行它,在C 驱动器上有一个文件,没问题:
U:\Data\ztemp> tmptmp C:\HaskellProjects\imagelength\LICENSE
done
当我使用U 驱动器上的文件从U 运行它时会出现问题:
U:\Data\ztemp> tmptmp test.xlsx
tmptmp: tmp.tmp: openBinaryFile: resource busy (file is locked)
如果在我的程序中我使用严格字节串而不是惰性字节串(通过将Data.ByteString.Lazy 替换为Data.ByteString),这个问题不会再发生。 p>
我想明白这一点。有什么解释吗? (我特别想知道如何解决这个问题但仍然使用惰性字节串)
编辑
也许更准确地说,这个程序仍然存在问题:
import qualified Data.ByteString as SB
import qualified Data.ByteString.Lazy as LB
main :: IO ()
main = do
[file] <- getArgs
bs <- LB.readFile file
action <- SB.writeFile "tmp.tmp" (LB.toStrict bs)
putStrLn "done"
当问题消失时:
bs <- SB.readFile file
action <- LB.writeFile "tmp.tmp" (LB.fromStrict bs)
看起来问题的关键在于readFile的懒惰。
【问题讨论】:
-
1.如果你给它一个绝对路径(即
cd U:/ ; tmptmp U:/<..>/test.xlsx?(谁知道,这可能就是它。Windows 有时很奇怪)2。你的意思是“这个网络驱动器离线”是什么意思?我想尝试重现,但我不确定如何访问离线的网络驱动器(显然我在这里误解了“离线”的含义!)。3.为什么需要使用惰性BS?看来你已经发现Strict是适合这项工作的工具。4. 如果强制输入(即写入前的evaluate (length bs))是否有效? -
嗨@user2407038。 1) 没有。 2) 这是我工作的笔记本电脑,我没有连接到域。在 Windows 资源管理器中,您有一个“离线工作/在线工作”按钮。如果要复制,请单击“脱机工作”。 3)这只是一个最小的可重现示例。在现实生活中,我使用的是处理惰性字节串的
xlsx库。 4)我不知道evaluate函数,我试试。 -
2) 或者干脆断开您的计算机与 Internet 的连接。
-
我刚刚通过使用我编辑的最后一点的策略解决了我的现实问题,
LB.readFile然后fromStrict。但显然这并不能提供解释。 -
不幸的是,我无法重现(在 W7 上)。我认为这是因为我没有可以通过这种方式访问的实际远程位置,但 Windows 允许我使用本地(共享)文件夹“映射网络驱动器”。使用此设置,没有“脱机工作”按钮,它与惰性 ByteString 一起工作得很好。
标签: haskell lazy-evaluation network-drive