Haskell: hSetFileSize: invalid argument (Invalid argument)



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

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

您打开的文件仅用于读取;但截断是一种写入操作。

相反,您可以做的是类似

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            

注意:这个答案是用识字的哈斯克尔写的。使用.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"

相关内容

最新更新