2012-10-15 12 views
10
readFile "file.html" 
"start of the file... *** Exception: file.html: hGetContents: invalid argument (invalid code page byte sequence) 

Jest to plik UTF-8 stworzony przy użyciu notatnika ++ ... jak mogę odczytać plik w haskell?haskell - niepoprawny kod bajtu strony kodowej

+0

Czy może umieścić zrzut szesnastkowy minimalnym pliku, który pokazuje ten błąd dla Ciebie? Nie mogę skopiować Twojego błędu. – ghoti

+1

Użyj tej litery: 'č' –

+0

Jaki jest twój język? Czy jest to utf-8 czy coś ucs2ish (notepad ++ sugeruje Windows)? –

Odpowiedz

12

Domyślnie pliki są odczytywane w narodowych systemu, więc jeśli masz plik przy użyciu niestandardowego kodowania, trzeba ustawić kodowanie pliku obsługiwać samemu.

foo = do 
    handle <- openFile "file.html" ReadMode 
    hSetEncoding handle utf8_bom 
    contents <- hGetContents handle 
    doSomethingWithContents 
    hClose handle 

powinien zacząć. Zauważ, że ten nie zawiera obsługi błędów, lepszy sposób byłoby zatem

import Control.Exception -- for bracket 

foo = bracket 
     (openFile "file.html" ReadMode >>= \h -> hSetEncoding h utf8_bom >> return h) 
     hClose 
     (\h -> hGetContents h >>= doSomething) 

lub

foo = withFile "file.html" ReadMode $ 
     \h -> do hSetEncoding h utf8_bom 
       contents <- hGetContents h 
       doSomethingWith contents 
+0

Wymyśliłem coś podobnego (jak na przykład" foo ", choć nie wiedziałem o' _bom' ..). Czy możliwe jest wykonywanie obliczeń na zewnątrz, tak jak robię to za pomocą 'readFile'? przykład 'foo' działa, jeśli nie używam linii' hClose' (i jest to w porządku dla mojego programu zabawkowego, ale chciałbym znać "właściwą drogę" ... czy muszę zwrócić coś w rodzaju 'IO (String, Handle) '?) –

+0

To jest trochę trudne, jeśli potrzebujesz leniwego odczytu pliku. 'HClose' zamyka plik, gdy powraca obliczenie, które może się zdarzyć, zanim cokolwiek z pliku zostanie odczytane. Więc jeśli możesz mieć cały plik w pamięci naraz, zrobienie prostej treści '' content content' seq' return'' wymusiłoby odczytanie całego pliku i możesz wykonać przetwarzanie na zewnątrz. W przeciwnym razie będzie to prawdopodobnie najlepiej odczytać pliku jako leniwe 'ByteString' i konwertować od tego (przy użyciu' 'Data.ByteString.Lazy.UTF8.toString' z pakietu utf8-string'). –

+0

Nie widzę, jak 'ByteString' pomaga/ułatwia rzeczy (choć jestem początkującym) ..' readFile' jest leniwy, prawda? Więc jak zamyka plik? Czy sprawdza, czy przeczytano ostatni znak? Czy w jakiś sposób mogę naśladować jego zachowanie? –

1

Według this site, swoje 6 bajtów dekodowania następująco:

EF BB BF -> ZERO WIDTH NO-BREAK SPACE (i.e. the BOM, although its not needed in UTF-8 
C4 8D -> LATIN SMALL LETTER C WITH CARON (what you said) 
0D  -> CARRIAGE RETURN (CR) 

więc jej legalna sekwencja UTF-8.

Jednak standardowe funkcje Prelude pierwotnie po prostu nie ASCII. Nie wiem, co teraz robią, ale zobacz to pytanie How does GHC/Haskell decide what character encoding it's going to decode/encode from/to? po więcej pomysłów. A następnie użyj http://hackage.haskell.org/package/utf8-string zamiast funkcji Prelude.