fugafuga.write

日々のログ



すごいH本 part61

ファイルの読み書き

ファイルから読んで端末に表示する

baabaa.txt

Baa, baa, black sheep,
Have you any wool?
Yes, sir, yes, syr,
Three bags full;

実装

import System.IO

main = do
    handle <- openFile "baabaa.txt" ReadMode
    contents <- hGetContents handle
    putStr contents
    hClose handle

ビルド・実行する

> stack ghc -- --make baabaa.hs
[1 of 1] Compiling Main             ( baabaa.hs, baabaa.o )
Linking baabaa ...
> ./baabaa
Baa, baa, black sheep,
Have you any wool?
Yes, sir, yes, syr,
Three bags full;

openFileはファイルパスとIOModeを受け取ってファイルのハンドルを返すI/Oアクションを返す。 FilePathはStringの型シノニム。

withFile関数

*Main Lib System.IO> :t withFile
withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r

ファイルパスとIOModeと"ハンドルを受け取ってI/Oアクションを返す"関数を受けっとって、 そのファイルを開いて何かして閉じるというI/Oアクションを返す。 withFileはファイルの操作中におかしなことになった場合にもファイルのハンドルを 確実に閉じてくれる。

withFile を使って書き換える

import System.IO

main = do
    withFile "baabaa.txt" ReadMode $ \handle -> do
        contents <- hGetContents handle
        putStr contents

ラムダ式の部分はハンドルを受け取ってI/Oアクションを返す。

ブラケット

何らかのリソースを獲得し、何かを行い、そのリソースが確実に解法されることを保証する。 というシナリオはよく使われるため、bracketという関数が用意されている。

*Main Lib Control.Exception> :t bracket
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c

リソースの獲得をおこなうI/Oアクション、リソースを開放する関数(例外が投げられた時にも呼ばれる)、 リソースを受け取り、それを使って何かを行う関数をとる。

withFile を実装する

import Control.Exception
import System.IO

main = do
    withFile' "baabaa.txt" ReadMode $ \handle -> do
        contents <- hGetContents handle
        putStr contents

withFile' :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
withFile' name mode f = bracket (openFile name mode)
    (\handle -> hClose handle)
    (\handle -> f handle)

リソースを獲得し、それを使って何かする、そして確実にリソースを解放することがbracketのすべて。

ファイル操作関数

readFile

*Main Lib> :t readFile
readFile :: FilePath -> IO String

ファイルパスを受け取り、ファイルを読み込み(遅延)、その内容を表す文字列を返すI/Oアクションを返す。

import System.IO
import Data.Char

main = do
    contents <- readFile "baabaa.txt"
    putStr contents

readFile を使う場合、Haskell が自動的にハンドルを閉じる。

writeFile

*Main Lib> :t writeFile
writeFile :: FilePath -> String -> IO ()

ファイルパスと書き込みたい文字列を受け取ってその書き込みをするI/Oアクションを返す。

import System.IO
import Data.Char

main = do
    contents <- readFile "baabaa.txt"
    writeFile "baabaacaps.txt" (map toUpper contents)

入力されたファイルの内容を大文字にして新しいファイルに書き込む。

appendFileはファイルが存在していた場合、ファイルの末尾に追記する。

所感

ファイルの操作は他の言語とあまり変わらない気がする

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る