“Java.nio.charset.MalformedInputException: Giriş uzunluğu = 1” ten kaçınmak için her şey dahil Karakter Kümesi?


97

Java'da bir dizinin metin tabanlı dosyalarını okuyan basit bir wordcount programı oluşturuyorum.

Ancak, şu hatayı almaya devam ediyorum:

java.nio.charset.MalformedInputException: Input length = 1

bu kod satırından:

BufferedReader reader = Files.newBufferedReader(file,Charset.forName("UTF-8"));

Muhtemelen bunu anladığımı biliyorum çünkü Charsetmetin dosyalarındaki bazı karakterleri içermeyen, bazıları diğer dillerin karakterlerini içeriyordu. Ama bu karakterleri dahil etmek istiyorum.

Daha sonra JavaDocs'ta bunun Charsetisteğe bağlı olduğunu ve yalnızca dosyaların daha verimli okunması için kullanıldığını öğrendim , bu yüzden kodu şu şekilde değiştirdim:

BufferedReader reader = Files.newBufferedReader(file);

Ancak bazı dosyalar hala MalformedInputException. Neden bilmiyorum

Her şey dahil olup olmadığını merak ediyorum Charsetbeni karakterlerin birçok farklı türde metin dosyalarını okumak sağlayacak ?

Teşekkürler.

Yanıtlar:


82

Muhtemelen desteklenen kodlamaların bir listesine sahip olmak istersiniz. Her dosya için, sırayla her kodlamayı deneyin, belki UTF-8 ile başlayarak. Her yakaladığınızda MalformedInputException, sonraki kodlamayı deneyin.


45
Denedim ISO-8859-1ve iyi çalışıyor. Bence Avrupalı ​​karakterler için, ki bu iyi. Yine de neden UTF-16işe yaramadığını hala bilmiyorum .
Jonathan Lam

1
Notepad ++ kullanıyorsanız, metin dosyasını açmayı deneyebilirsiniz ve bu size Menü'de dosyanın kodlanmasını söyleyecektir. Her zaman aynı kaynaktan dosya alırsanız, kodu doğru bir şekilde uyarlayabilirsiniz.
JGFMK

@JonathanLam Eh, çünkü kodlanmışsa ISO-8859-1, o zaman değil UTF-16 . Bu kodlamalar tamamen farklıdır. Bir dosya ikisi birden olamaz.
Dawood ibn Kareem

@DawoodsaysreinstateMonica Sanırım UTF-16'nın ISO-8859-1 gibi Avrupa karakterleri için bir bütün olarak işe yaramadığına şaşırdığımı söyledim. Ama bilgi için teşekkürler (altı yıl sonra bile): P
Jonathan Lam

Elbette. UTF-16, içinde tüm Avrupa karakterlerine sahiptir. Ancak ISO-8859-1'den farklı şekilde temsil edilirler. ISO-8859-1'de, tüm karakterler yalnızca 8 bit ile temsil edilir, bu nedenle 256 olası karakterle sınırlandırılırsınız. UTF-16'da çoğu karakter 16 bit ile temsil edilir ve bazı karakterler 32 bit ile temsil edilir. Bu nedenle, UTF-16'da çok daha fazla olası karakter vardır, ancak bir ISO-8859-1 dosyası, UTF-16'da kullanılan aynı verilerin yalnızca yarısı kadar alan gerektirir.
Dawood ibn Kareem

41

Files.newBufferedReader'dan BufferedReader Oluşturma

Files.newBufferedReader(Paths.get("a.txt"), StandardCharsets.UTF_8);

uygulamayı çalıştırırken aşağıdaki istisnayı atabilir:

java.nio.charset.MalformedInputException: Input length = 1

Fakat

new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"),"utf-8"));

iyi çalışıyor.

Farklı olan, birincisinin CharsetDecoder varsayılan eylemini kullanmasıdır.

Hatalı biçimlendirilmiş girdi ve eşlenemeyen karakter hataları için varsayılan eylem, bunları bildirmektir .

ikincisi DEĞİŞTİR eylemini kullanırken.

cs.newDecoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE)

29

ISO-8859-1, MalformedInputException oluşturmamasının garanti edilmesi anlamında her şeyi kapsayan bir karakter kümesidir. Dolayısıyla, girdiniz bu karakter kümesinde olmasa bile hata ayıklama için iyidir. Yani:-

req.setCharacterEncoding("ISO-8859-1");

Girişimde bazı çift sağ tırnak / çift sol tırnak karakterleri vardı ve hem US-ASCII hem de UTF-8 bunlara MalformedInputException attı, ancak ISO-8859-1 işe yaradı.


7

Bu istisnayla da hata mesajı ile karşılaştım,

java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(Unknown Source)
at sun.nio.cs.StreamEncoder.implWrite(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at java.io.OutputStreamWriter.write(Unknown Source)
at java.io.BufferedWriter.flushBuffer(Unknown Source)
at java.io.BufferedWriter.write(Unknown Source)
at java.io.Writer.write(Unknown Source)

ve kullanmaya çalışırken tuhaf bir hata oluştuğunu tespit etti

BufferedWriter writer = Files.newBufferedWriter(Paths.get(filePath));

bir sınıfta genel bir türden bir String "orazg 54" dökümü yazmak için.

//key is of generic type <Key extends Comparable<Key>>
writer.write(item.getKey() + "\t" + item.getValue() + "\n");

Bu String, aşağıdaki kod noktalarına sahip karakterleri içeren 9 uzunluğundadır:

111114 97122103 9 53 52 10

Ancak, sınıftaki BufferedWriter şu şekilde değiştirilirse:

FileOutputStream outputStream = new FileOutputStream(filePath);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));

bu String'i istisnasız başarıyla yazabilir. Ek olarak, karakterlerden aynı String oluşturmayı yazarsam hala çalışıyor.

String string = new String(new char[] {111, 114, 97, 122, 103, 9, 53, 52, 10});
BufferedWriter writer = Files.newBufferedWriter(Paths.get("a.txt"));
writer.write(string);
writer.close();

Daha önce herhangi bir Dizeyi yazmak için ilk BufferedWriter'ı kullanırken herhangi bir İstisna ile karşılaşmamıştım. Bu, java.nio.file.Files.newBufferedWriter'den (yol, seçenekler) oluşturulan BufferedWriter'da meydana gelen garip bir hatadır.


1
OP yazmaktan ziyade okumaktan bahsettiği için bu biraz konu dışı. Benzer bir sorunu BufferedWriter.write (int) nedeniyle yaşadım - bu int bir karakter olarak ele alınır ve doğrudan akışa yazar. Çözüm, el ile dizeye dönüştürmek ve sonra yazmaktır.
malaverdiere

Bu maalesef oylanmayan bir cevap, Gerçekten güzel iş Tom. Bunun Java'nın sonraki sürümlerinde çözülüp çözülmediğini merak ediyorum.
Ryboflavin


4

bunu deneyin .. aynı sorunu yaşadım, aşağıdaki uygulama benim için çalıştı

Reader reader = Files.newBufferedReader(Paths.get(<yourfilewithpath>), StandardCharsets.ISO_8859_1);

ardından Reader'ı istediğiniz yerde kullanın.

foreg:

CsvToBean<anyPojo> csvToBean = null;
    try {
        Reader reader = Files.newBufferedReader(Paths.get(csvFilePath), 
                        StandardCharsets.ISO_8859_1);
        csvToBean = new CsvToBeanBuilder(reader)
                .withType(anyPojo.class)
                .withIgnoreLeadingWhiteSpace(true)
                .withSkipLines(1)
                .build();

    } catch (IOException e) {
        e.printStackTrace();
    }

3

Mevcut karakter kümelerine göre standart hale getirilecek sonuçların bir listesini yazdırmak için aşağıdakileri yazdım. Ayrıca, hangi karakterin sorunlara neden olduğunu gidermeniz durumunda, 0 tabanlı bir satır numarasından hangi satırın başarısız olduğunu da söyler.

public static void testCharset(String fileName) {
    SortedMap<String, Charset> charsets = Charset.availableCharsets();
    for (String k : charsets.keySet()) {
        int line = 0;
        boolean success = true;
        try (BufferedReader b = Files.newBufferedReader(Paths.get(fileName),charsets.get(k))) {
            while (b.ready()) {
                b.readLine();
                line++;
            }
        } catch (IOException e) {
            success = false;
            System.out.println(k+" failed on line "+line);
        }
        if (success) 
            System.out.println("*************************  Successs "+k);
    }
}

0

Sorun şu ki Files.newBufferedReader(Path path)şu şekilde uygulanıyor:

public static BufferedReader newBufferedReader(Path path) throws IOException {
    return newBufferedReader(path, StandardCharsets.UTF_8);
}

Bu nedenle UTF-8, kodunuzda açıklayıcı olmak istemediğiniz sürece , temelde belirtmenin bir anlamı yoktur . "Daha geniş" bir karakter seti denemek istiyorsanız, deneyebilirsiniz StandardCharsets.UTF_16, ancak yine de olası her karakteri alacağınızdan% 100 emin olamazsınız.


-1

bunun gibi bir şey deneyebilir veya sadece aşağıdaki parçayı kopyalayıp yapıştırabilirsiniz.

boolean exception = true;
Charset charset = Charset.defaultCharset(); //Try the default one first.        
int index = 0;

while(exception) {
    try {
        lines = Files.readAllLines(f.toPath(),charset);
          for (String line: lines) {
              line= line.trim();
              if(line.contains(keyword))
                  values.add(line);
              }           
        //No exception, just returns
        exception = false; 
    } catch (IOException e) {
        exception = true;
        //Try the next charset
        if(index<Charset.availableCharsets().values().size())
            charset = (Charset) Charset.availableCharsets().values().toArray()[index];
        index ++;
    }
}

İstisna işleyici while(exception), dizide çalışan bir karakter kümesi bulamazsa , potansiyel olarak döngüyü sonsuza kadar sürebilir . Dizinin sonuna ulaşılırsa ve çalışan karakter kümesi bulunmazsa istisna işleyicisi yeniden atmalıdır. Ayrıca, bu cevabın yazıldığı tarih itibariyle "-2" oy almıştı. "-1" olarak yükselttim. Bence olumsuz oy almasının sebebi açıklamanın yetersiz olmasından kaynaklanıyor. Kodun ne yaptığını anlasam da, başkaları anlayamayabilir. Bu nedenle, "böyle bir şey deneyebilirsiniz" gibi bir yorum, bazı kişiler tarafından beğenilmeyebilir.
mvanle

-1

UTF-8, Lehçe karakterlerle benim için çalışıyor

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.