考虑以下简单的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)
如果在我的程序中我使用 strict bytestrings而不是lazy bytestrings (将Data.ByteString.Lazy
替换为Data.ByteString
),不会再出现此问题
我想了解这一点。任何解释? (我特别想知道如何解决这个问题,但仍然使用延迟的字节串)
或许更精确一点,这个程序仍然会出现问题:
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
的懒惰。
答案 0 :(得分:0)
根据最新的Data.ByteString.Lazy docs:
<块引用>使用 readFile 或 hGetContents 等惰性 I/O 函数意味着关闭文件句柄等操作顺序由 RTS 自行决定。
使用离线网络驱动器给出的示例可能会导致 RTS 从 readFile 继续而不关闭文件。文档,其中有一个几乎相同的例子,说
<块引用>接下来执行 writeFile 时,[tmp.tmp] 仍然打开读取,RTS 注意避免同时打开它进行写入,而是返回错误。
据我所知,在 Data.ByteString.Lazy 中没有解决方案——文档中建议了您的解决方案(使用严格读取)和其他包。有时读写同一个文件是可以的,但你不能保证。