2012-11-11 22 views
8

Mam plik 132 kb (nie można tak naprawdę powiedzieć, że jest duży) i próbuję go odczytać z REPL Scala, ale nie mogę odczytać po 2048 char, ponieważ daje mi java.nio.charset.MalformedInputException wyjątekWykryto wyjątek MalformedInputException podczas odczytu całego pliku

są to kroki biorę:

val it = scala.io.Source.fromFile("docs/categorizer/usig_calles.json") // this is ok 
it.take(2048).mkString // this is ok too 
it.take(1).mkString // BANG! 

java.nio.charset.MalformedInputException: Input length = 1 
at java.nio.charset.CoderResult.throwException(CoderResult.java:277) 
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:338) 
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177) 
at java.io.InputStreamReader.read(InputStreamReader.java:184) 

Każdy pomysł co może być nie tak?

-

Najwyraźniej problemem było to, że plik nie został zakodowany w UTF

Uratowałem go jako UTF i wszystko działa, po prostu wydać mkString na iteracyjnej i pobiera całą zawartość pliku

Najdziwniejsze jest to, że tylko błąd wzbudził przejściu pierwszych 2048 znaków ...

Odpowiedz

4

nie może być pewny, bez pliku, ale dokumentacja wskazuje na wyjątek jest rzucony „gdy seque bajt wejściowy nce nie jest legalne dla danego zestawu znaków lub wprowadzana sekwencja znaków nie jest legalną szesnastobitową sekwencją Unicode. " (MalformedInputException javadoc)

Podejrzewam, że w 2049 jest pierwszym napotkanym znakiem, który nie jest prawidłowy, niezależnie od domyślnego kodowania znaków JVM w twoim środowisku. Rozważmy jednoznaczne określenie kodowania znaków pliku za pomocą jednego z przeciążeń w przypadku aplikacji wieloplatformowej, powinieneś wiedzieć, że domyślne kodowanie znaków w JVM różni się w zależności od platformy, więc jeśli używasz określone kodowanie, które chcesz jawnie ustawić jako parametr wiersza poleceń podczas uruchamiania aplikacji, lub określić go przy każdym wywołaniu przy użyciu odpowiedniego przeciążenia.

+2

Jest to łatwy sposób, aby przetestować to: spróbuj przy 2049 elementów po raz pierwszy. Z pewnością nie jest to jednak prawdziwy problem - samo trafienie w pierwszą nielegalną sekwencję bajtów z dokładnie 2 + 11 + 1 znakami w pliku byłoby fantastycznym zbiegiem okoliczności. –

+1

To pierwsza rzecz, którą wypróbowałem, mintString na całym iteratorze. Potem wyśledziłem to do 2048 ... – opensas

4

Za każdym razem, gdy dwa razy wywołasz take w tym samym iteratorze, wszystkie zakłady są wyłączone. Iteratory są z natury konieczne, a ich łączenie z funkcjonalnymi idiomami jest w najlepszym wypadku ryzykowne. Większość iteratorów, z którymi spotykasz się w standardowej bibliotece, wydaje się być dość dobrze zachowana pod tym względem, ale gdy użyjesz take lub drop lub filter itd., Jesteś w stanie nieokreślonego zachowania, zasadą wszystko może się zdarzyć.

Od the docs:

Jest to szczególnie ważne, aby pamiętać, że o ile nie zaznaczono inaczej, nigdy nie należy używać iterator po wywołaniu metody na nim. Dwie najważniejsze wyjątki są również jedynymi abstrakcyjne metody: next i hasNext ...

def take(n: Int): Iterator[A] ...

Reuse: Po wywołaniu tej metody, należy odrzucić iterator to padł na, i używaj tylko iteratora, który został zwrócony. Używanie starego iteratora jest niezdefiniowane, może ulec zmianie i może spowodować zmiany w nowym iteratorze.

Prawdopodobnie nie warto próbować wyśledzić dokładnie, co poszło nie tak.

+0

Sugerowałbym zrobienie 'it.toList' od początku. W ten sposób będzie mógł mieć wszystkie dane. – pedrofurla

+0

@pedrofurla: W prawo, lub 'toStream', jeśli on (lub ona? Obraz pingwina jest skromnie przycięty, więc nie mogę powiedzieć) niekoniecznie musi przeczytać cały plik. –

+0

To prawda, Travis. – pedrofurla

2

Jeśli tylko chcesz przekonwertować bajty danych do zwykłego Łacińskiej:

// File: 
io.Source.fromFile(file)(io.Codec.ISO8859).mkString 

// InputStream: 
io.Source.fromInputStream(System.io)(io.Codec.ISO8859).mkString 
Powiązane problemy