HaskellでreadFileで日本語の書かれたテキストファイルを読み込むと、「hGetContents: invalid argument (invalid byte sequence)」と言われて失敗する(ことがある)のでどうしたらいいのか調べました。
OSはWindows 7でghcとかのヴァージョンはHaskell Platform 2014.2.0.0でインストールされるやつです。
System.IOモジュールのドキュメントによるとデフォルトのencodingはシステムのデフォルトのencodingと同じだそうです。
なので、システムのデフォルトのencodingと違うファイルを開こうとするとうまく開けないことがある、ということみたい。
ならencodingを指定して開けばいいじゃないか!
System.IOモジュールの mkTextEncoding関数を使ってファイルのハンドラの文字コードを指定してあげればよいです。
文字コードとファイル名を指定してファイルの中身を表示するプログラムはこんなふうに書けます。
-- readfile.hs
module Main where
import System.Environment (getArgs)
import System.IO (IOMode (..), hGetContents, hSetEncoding, openFile, hClose, mkTextEncoding)
main :: IO ()
main = do
[cp, file_name] <- getArgs
h <- openFile file_name ReadMode
encoding <- mkTextEncoding cp
hSetEncoding h encoding
contents <- hGetContents h
mapM_ putStrLn $ lines contents
hClose h
コンパルして、euc-jpで保存したテキストファイルを開いてみましょう。
文字コードはコードページで指定するのが確実ぽいです。
euc-jpのコードページは20932です。コードページの数字の前にはcpを付ける必要があります。
$ ./readfile.exe cp20932 euc-jp.txt
こんにちは、世界
日本語で書かれたテキストファイルです
すばらしい!
素敵なHaskellライフを(-_-)/