2016-03-21 13 views
1

私のプログラムで何が問題になっているのか、何かが助けてくれますか?Haskell:hSetFileSize:無効な引数(無効な引数)

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 

答えて

3

を。切り捨ては書き込み操作です。あなたの代わりに何ができるか

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    
+1

追加発言:

は、今、私たちは、タスクを完了するために必要なすべてのツールを持っています複数の読者または単一のライター。ファイルを2回開く(サイズを取得して内容を読むために、次に切り詰めるために1回)はより合理的です。 – Zeta

+0

@ Zeta:良い点、答えを更新して、最初に 'ReadMode'操作を行い、次に' WriteMode'操作を行う可能性のある解決策を示しました。 – Cactus

+2

また、前もってファイルを読むために、いくつかの厳密なIO機能([これら](https://hackage.haskell.org/package/strict/docs/System-IO-Strict.html)など)切り捨てる;標準IO機能は、残念ながら、怠惰です。 – Cactus

2

のようなものです。注:この答えは文芸Haskellで書かれています。 .lhsで保存し、GHCiで試してみるかコンパイルしてください。

> import System.IO 

ファイルの変更は読み取り専用ではありません。あなたは書き込みのためにファイルを開く必要があります。しかし、これは問題につながります。なぜなら、1人のライターか複数のリーダーしかいないからです。 readFileを使用してファイルを開くので、オープンモードを変更することはできません。

コードをリファクタリングすると簡単になります。私たちは即座に、あなたが繰り返さない、つまりサイズを取得し、内容を伝えるという2つの違反を見ることができます。それでは、これを修正しましょう:

> 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 

WriteModeがゼロバイトにファイルが切り捨てられますので、それは、ここReadWriteModeないWriteModeを使用することが重要です!ところで、Cのfopenと同じ動作です。 readFileのfileName`は、GHCのランタイムは、いずれか一方のみができますので、 - <のOpenFile fileNameにWriteMode`はコンテンツ `でエラーにつながる`使用:

> 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"