gpt4 book ai didi

file - 如何读取(和解析)文件然后附加到同一个文件而不出现异常?

转载 作者:行者123 更新时间:2023-12-02 02:54:51 25 4
gpt4 key购买 nike

我正在尝试在 Haskell 中正确读取文件,但我似乎收到此错误。

*** 异常(exception):neo.txt:openFile:资源繁忙(文件被锁定)
这是我的代码。

import Data.Char
import Prelude
import Data.List
import Text.Printf
import Data.Tuple
import Data.Ord
import Control.Monad
import Control.Applicative((<*))

import Text.Parsec
( Parsec, ParseError, parse -- Types and parser
, between, noneOf, sepBy, many1 -- Combinators
, char, spaces, digit, newline -- Simple parsers
)

这些是电影领域。
type Title = String
type Director = String
type Year = Int
type UserRatings = (String,Int)
type Film = (Title, Director, Year , [UserRatings])
type Period = (Year, Year)
type Database = [Film]

这是所有类型的解析,以便从文件中正确读取
-- Parse a string to a string
stringLit :: Parsec String u String
stringLit = between (char '"') (char '"') $ many1 $ noneOf "\"\n"

-- Parse a string to a list of strings
listOfStrings :: Parsec String u [String]
listOfStrings = stringLit `sepBy` (char ',' >> spaces)

-- Parse a string to an int
intLit :: Parsec String u Int
intLit = fmap read $ many1 digit
-- Or `read <$> many1 digit` with Control.Applicative
stringIntTuple :: Parsec String u (String , Int)
stringIntTuple = liftM2 (,) stringLit intLit

film :: Parsec String u Film
film = do
-- alternatively `title <- stringLit <* newline` with Control.Applicative
title <- stringLit
newline
director <- stringLit
newline
year <- intLit
newline
userRatings <- stringIntTuple
newline
return (title, director, year, [userRatings])

films :: Parsec String u [Film]
films = film `sepBy` newline

这是主程序(在winghci中写“main”来启动程序)
-- The Main
main :: IO ()
main = do
putStr "Enter your Username: "
name <- getLine
filmsDatabase <- loadFile "neo.txt"
appendFile "neo.txt" (show filmsDatabase)
putStrLn "Your changes to the database have been successfully saved."

这是 loadFile 函数
loadFile :: FilePath -> IO (Either ParseError [Film])
loadFile filename = do
database <- readFile filename
return $ parse films "Films" database

另一个txt文件名是neo,包括一些这样的电影
"Blade Runner"
"Ridley Scott"
1982
("Amy",5), ("Bill",8), ("Ian",7), ("Kevin",9), ("Emma",4), ("Sam",7), ("Megan",4)

"The Fly"
"David Cronenberg"
1986
("Megan",4), ("Fred",7), ("Chris",5), ("Ian",0), ("Amy",6)

只需复制粘贴所有内容,包括同一目录中的 txt 文件并测试它以查看我描述的错误。

最佳答案

哎呀雏菊,懒惰
趋于to make file changes crazy .
文件 not closed , as supposed
因此 the error被强加。
这个小技巧,作者 loadFile是你必须调和的。
但不要担心,至少现在还没有,
我给你看,让我们开始吧。

IO 一起使用的许多其他功能在 System.IO , readFile实际上不消耗任何输入。它很懒。因此,文件 doesn't get closed , 除非它的所有内容都被消耗掉了(然后它是半封闭的):

The file is read lazily, on demand, as with getContents.



我们可以用一个较短的例子来证明这一点:
main = do
let filename = "/tmp/example"
writeFile filename "Hello "
contents <- readFile filename
appendFile filename "world!" -- error here

这将失败,因为我们从未真正检查过 contents (完全)。如果您获得所有内容(例如打印、 length 或类似内容),它将不再失败:
main = do
let filename = "/tmp/example2"
writeFile filename "Hello "
content <- readFile filename
putStrLn content
appendFile filename "world!" -- no error

因此,我们需要 真的关闭文件,或者我们需要确保在尝试追加到文件之前我们已经阅读了所有内容。

例如,您可以使用 withFile 连同一些“魔法”功能 force这可以确保内容真正得到评估:
readFile' filename = withFile filename ReadMode $ \handle -> do
theContent <- hGetContents handle
force theContent

然而, force很难实现。您可以使用 bang patterns ,但这只会将列表评估为 WHNF(基本上只是第一个字符)。您可以通过 deepseq 使用这些功能,但这会增加另一个依赖性,并且可能不允许在您的作业/练习中使用。

或者您可以使用任何以某种方式确保所有元素都被评估或排序的函数。在这种情况下,我们可以使用一个小技巧和 mapM return :
readFile' filename = withFile filename ReadMode $ \handle -> do
theContent <- hGetContents handle
mapM return theContent

这已经足够了,但你会使用类似 pipes 的东西或 conduit而是在生产中。

另一种方法是确保我们真的使用了所有内容。这可以通过使用另一种解析器方法来完成,即 runParserT .我们可以将此与我们的 withFile 结合起来从上面的方法:
parseFile :: ParsecT String () IO a -> FilePath -> IO (Either ParseError a) 
parseFile p filename = withFile filename ReadMode $ \handle ->
hGetContents handle >>= runParserT p () filename

再次, withFile确保我们关闭文件。我们现在可以在您的 loadFilm 中使用它:
loadFile :: FilePath -> IO (Either ParseError [Film])
loadFile filename = parseFile films filename

此版本 loadFile将不再保持文件锁定。

关于file - 如何读取(和解析)文件然后附加到同一个文件而不出现异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35840685/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com