【问题标题】:Haskell: hSetFileSize: invalid argument (Invalid argument)Haskell:hSetFileSize:无效参数(无效参数)
【发布时间】:2016-07-07 13:58:13
【问题描述】:

有人能帮我看看我的程序出了什么问题吗?当我尝试运行以下程序时,我收到以下错误消息:

hSetFileSize: 无效参数(无效参数)

import System.IO

main = do
    putStrLn "Enter file name (Including full path) to read"
    fileName <- getLine

    handle <- openFile fileName ReadMode
    sizeBeforeTrunc <- hFileSize handle
    content <- readFile fileName 

    putStrLn $ "Size of the file Before truncation is " ++ (show sizeBeforeTrunc) ++ " bytes" 
    putStrLn $ "Content of the file is " ++ content

    putStrLn "**************************************"
    let n = sizeBeforeTrunc `div` 2
    putStrLn $ "Truncating file to " ++ (show n) ++ " bytes"

    info1 <- hSetFileSize handle (toInteger 10)
    putStrLn $ show info1
    sizeAfterTrunc <- hFileSize handle

    putStrLn $ "Size of the file After truncation is " ++ (show sizeAfterTrunc) ++ " bytes" 
    putStrLn $ "Content of the file is " ++ content        

    hClose handle

【问题讨论】:

    标签: file haskell io


    【解决方案1】:

    您正在以只读方式打开文件;但截断是一种写操作。

    你可以做的是类似

    main = do
        putStrLn "Enter file name (Including full path) to read"
        fileName <- getLine
    
        sizeBeforeTrunc <- withFile fileName ReadMode $ \h -> do
            sizeBeforeTrunc <- hFileSize h
            content <- hGetContents h
    
            putStrLn $ "Size of the file Before truncation is " ++ (show sizeBeforeTrunc) ++ " bytes" 
            putStrLn $ "Content of the file is " ++ content
    
        putStrLn "**************************************"
        let n = sizeBeforeTrunc `div` 2
        putStrLn $ "Truncating file to " ++ (show n) ++ " bytes"
    
        sizeAfterTrunc <- withFile fileName WriteMode $ \h -> do       
            info1 <- hSetFileSize h (toInteger 10)
            putStrLn $ show info1
            hFileSize h
    
        putStrLn $ "Size of the file After truncation is " ++ (show sizeAfterTrunc) ++ " bytes" 
        putStrLn $ "Content of the file is " ++ content            
    

    【讨论】:

    • 附加说明:使用openFile fileName WriteMode 将导致content &lt;- readFile fileName 出错,因为GHC 的运行时只允许多个读取器或单个写入器。打开文件两次(一次用于获取大小并读取内容;然后用于截断)似乎更合理。
    • @Zeta:好点子,我已经更新了答案以展示一个可能的解决方案,首先执行 ReadMode 操作,然后执行 WriteMode 操作。
    • 另外,我宁愿使用一些定制的严格 IO 函数(如these)在截断之前读取文件;不幸的是,标准 IO 函数是惰性的。
    • 您可以使用ReadWriteMode(我认为)打开文件,而不是两次打开文件。 +1 使用 withFile 而不是 open/close 组合。
    • @user2407038 Err, hGetContents 将使句柄处于半关闭状态。毕竟,my last poem 是有原因的。 *sigh* 虽然必须为此进行更改:Whoopsy daisy,懒惰 / 往往会使文件更改变得疯狂。 /手柄不见了/一直以来/你问自己“出了什么问题”? / 别哭 / 继续努力吧! / 所有的苦难很快就会过去.
    【解决方案2】:

    注意:这个答案是用 literate Haskell 写的。用.lhs作为扩展保存它,然后在GHCi中尝试或编译它。

    > import System.IO
    

    更改文件不是只读操作。您需要打开文件进行写入。但是,这会导致问题,因为您可能只有一个写入器或多个读取器。由于您使用readFile打开文件进行读取,因此您不能简单地更改打开模式。

    如果我们重构您的代码,它会变得更容易。我们可以立即看到不要重复自己的两个违规行为,即获取大小和告诉内容。所以让我们解决这个问题:

    > putAndCount :: FileName -> String -> IO Int
    > putAndCount fn msg = withFile fn ReadMode $ \handle -> do
    >     size    <- hFileSize handle
    >     content <- hGetContents handle
    >     putStrLn $ "Size of the file " ++ msg ++ " is " ++ show size ++ " bytes"
    >     putStrLn $ "Content of the file is " ++ content
    >     return size
    

    withFile 确保我们的手柄是关闭的,并且无法进一步操作。现在让我们编写另一个函数来改变文件的大小而不使用句柄:

    > setFileSize :: FileName -> Integer -> IO ()
    > setFileSize fn s = withFile fn ReadWriteMode $ \handle -> 
    >     hSetFileSize handle s
    

    在这里使用ReadWriteMode WriteMode 很重要,因为WriteMode 会将文件截断为零字节!顺便说一下,这与 C 的 fopen 中的行为相同。

    现在我们拥有完成任务所需的所有工具:

    > main :: IO ()
    > main = do
    >     putStrLn "Enter file name (Including full path) to read"
    >     fileName <- getLine
    >
    >     sizeBeforeTrunc <- putAndCount fileName "Before truncation"    
    >     putStrLn "**************************************"
    > 
    >     let n = sizeBeforeTrunc `div` 2
    >     putStrLn $ "Truncating file to " ++ (show n) ++ " bytes"    
    >     setFileSize fileName n
    >     putAndCount fileName "After truncation"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-02
      • 2011-02-03
      • 2011-05-16
      • 2013-02-16
      相关资源
      最近更新 更多