"Java.nio.charset.MalformedInputException: इनपुट लंबाई = 1" से बचने के लिए सभी समावेशी चारसेट?


96

मैं जावा में एक सरल वर्डकाउंट प्रोग्राम बना रहा हूं जो निर्देशिका की पाठ-आधारित फ़ाइलों के माध्यम से पढ़ता है।

हालाँकि, मैं त्रुटि प्राप्त करता रहता हूँ:

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

कोड की इस पंक्ति से:

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

मुझे पता है कि मुझे शायद यह मिल गया है क्योंकि मैंने एक का उपयोग किया है Charsetजिसमें पाठ फ़ाइलों में कुछ वर्ण शामिल नहीं थे, जिनमें से कुछ में अन्य भाषाओं के वर्ण शामिल थे। लेकिन मैं उन किरदारों को शामिल करना चाहता हूं।

मैंने बाद में JavaDocs में सीखा कि Charsetवैकल्पिक है और केवल फाइलों के अधिक कुशल पढ़ने के लिए उपयोग किया जाता है, इसलिए मैंने कोड बदल दिया:

BufferedReader reader = Files.newBufferedReader(file);

लेकिन कुछ फाइलें अभी भी फेंकती हैं MalformedInputException। मुझे पता नहीं क्यों।

मैं सोच रहा था कि क्या कोई सर्व-समावेशी है Charsetजो मुझे कई अलग-अलग प्रकार के पात्रों के साथ पाठ फ़ाइलों को पढ़ने की अनुमति देगा ?

धन्यवाद।

जवाबों:


81

आप शायद समर्थित एन्कोडिंग की एक सूची रखना चाहते हैं। प्रत्येक फ़ाइल के लिए, प्रत्येक एन्कोडिंग को ट्राई करें, शायद UTF-8 से शुरू हो। हर बार जब आप पकड़ते हैं MalformedInputException, तो अगले एन्कोडिंग का प्रयास करें।


44
मैंने कोशिश की ISO-8859-1और यह अच्छी तरह से काम करता है। मुझे लगता है कि यह यूरोपीय पात्रों के लिए है, जो ठीक है। मैं अभी भी नहीं जानता कि UTF-16काम क्यों नहीं करता है, हालांकि।
जोनाथन लैम

1
यदि आपके पास नोटपैड ++ है, तो आप टेक्स्ट फ़ाइल खोलने की कोशिश कर सकते हैं और यह आपको मेनू में फ़ाइल की एन्कोडिंग बताएगा। यदि आप हमेशा एक ही स्रोत से फ़ाइल प्राप्त करते हैं, तो आप कोड acorrdingly को अनुकूलित कर सकते हैं।
JGFMK

@JonathanLam खैर, क्योंकि अगर इसके साथ एनकोड किया गया है ISO-8859-1, तो यह नहीं है UTF-16 । ये एनकोडिंग पूरी तरह से अलग हैं। एक फाइल दोनों नहीं हो सकती।
दाऊद इब्न करीम

@DawoodsaysreinstateMonica मेरा मानना ​​है कि मेरा मतलब था कि मुझे आश्चर्य हुआ था कि UTF-16 ने काम नहीं किया और साथ ही ISO-8859-1 जैसे यूरोपीय पात्रों के लिए एक कैच-अप भी किया। लेकिन जानकारी के लिए धन्यवाद (भले ही छह साल बाद): पी
जोनाथन लैम

ज़रूर। UTF-16 में सभी यूरोपीय वर्ण हैं। लेकिन वे ISO-8859-1 से अलग प्रतिनिधित्व करते हैं। ISO-8859-1 में, सभी वर्णों का प्रतिनिधित्व केवल 8 बिट्स के साथ किया जाता है, इसलिए आप 256 संभावित वर्णों तक सीमित हैं। UTF-16 में, अधिकांश वर्णों को 16 बिट्स के साथ दर्शाया जाता है, और कुछ वर्णों को 32 बिट्स के साथ दर्शाया जाता है। यूटीएफ -16 में बहुत अधिक संभावित अक्षर हैं, लेकिन एक आईएसओ-8859-1 फ़ाइल को केवल आधे स्थान की आवश्यकता होगी, जितना डेटा यूटीएफ -16 में उपयोग किया जाएगा।
दाऊद इब्न करीम

39

Files.newBufferedReader से बफर बनाना

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

एप्लिकेशन को चलाते समय वह निम्न अपवाद को फेंक सकता है:

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

परंतु

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

अच्छा काम करता है।

अलग यह है कि, पूर्व चारसेटडेकोडर डिफ़ॉल्ट क्रिया का उपयोग करता है।

विकृत-इनपुट और अयोग्य-वर्ण त्रुटियों के लिए डिफ़ॉल्ट कार्रवाई उन्हें रिपोर्ट करना है।

जबकि बाद में उत्तर कार्रवाई का उपयोग करता है।

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

29

ISO-8859-1 एक सर्व-समावेशी चारसेट है, इस अर्थ में कि यह MalformedInputException को न फेंकने की गारंटी है। तो यह डिबगिंग के लिए अच्छा है, भले ही आपका इनपुट इस चारसेट में न हो। इसलिए:-

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

मेरे इनपुट में कुछ डबल-राइट-कोट / डबल-लेफ्ट-क्वैच कैरेक्टर थे, और US-ASCII और UTF-8 दोनों ने उन पर MalformedInputException फेंकी, लेकिन ISO-8859-1 ने काम किया।


6

मुझे भी त्रुटि संदेश के साथ इस अपवाद का सामना करना पड़ा,

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)

और पाया कि कुछ अजीब बग तब होता है जब उपयोग करने की कोशिश की जाती है

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

एक कक्षा में एक सामान्य प्रकार से एक स्ट्रिंग "orazg 54" कास्ट लिखने के लिए।

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

यह स्ट्रिंग लंबाई 9 की है जिसमें निम्नलिखित कोड बिंदुओं के साथ वर्ण हैं:

111 114 97 122 103 9 53 52 10

हालाँकि, यदि वर्ग में बफ़रड्राइवर को प्रतिस्थापित किया जाता है:

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

यह अपवाद के बिना इस स्ट्रिंग को सफलतापूर्वक लिख सकता है। इसके अलावा, अगर मैं एक ही स्ट्रिंग लिखता हूं तो यह अभी भी ठीक काम करने वाले पात्रों से बनाता है।

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();

पहले मैं किसी भी अपवाद का सामना नहीं किया है जब किसी भी स्ट्रिंग्स को लिखने के लिए पहले बफ़रविटर का उपयोग कर रहा हूं। यह एक अजीब बग है जो java.nio.file.Files.newBufferedWriter (पथ, विकल्प) से निर्मित बफ़रविटर को होता है।


1
यह कुछ हद तक विषय है, क्योंकि ओपी लिखने के बजाय पढ़ने के बारे में बात कर रहा था। मेरे पास बफ़रडाइट लेखक (इंट) के कारण एक समान मुद्दा था - जो उस इंट को एक चरित्र के रूप में मानता है और इसे सीधे धारा में लिखता है। वर्कअराउंड मैन्युअल रूप से इसे स्ट्रिंग में बदलने और फिर लिखने के लिए है।
मालावरडेरे

यह एक दुख की बात है वोट के जवाब के तहत, वास्तव में अच्छा काम टॉम। मैं सोच रहा था कि यह जावा के बाद के संस्करणों में हल हो गया है।
रयबोफ्लेविन


3

मैंने उपलब्ध वर्णों के आधार पर परिणामों की सूची प्रिंट करने के लिए निम्नलिखित लिखा है। ध्यान दें कि यह आपको यह भी बताता है कि किसी समस्या के कारण चरित्र किस समस्या का निवारण कर रहा है, यह 0 आधारित पंक्ति संख्या से पंक्ति विफल हो जाती है।

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);
    }
}

3

यह कोशिश करो .. मैं एक ही मुद्दा था, नीचे कार्यान्वयन मेरे लिए काम किया

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

फिर रीडर का उपयोग करें जहाँ आप कभी भी चाहते हैं।

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();
    }

0

खैर, समस्या यह है कि Files.newBufferedReader(Path path)इस तरह से लागू किया जाता है:

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

इसलिए मूल रूप से निर्दिष्ट करने का कोई मतलब नहीं है UTF-8जब तक आप अपने कोड में वर्णनात्मक नहीं होना चाहते। यदि आप एक "व्यापक" चारसेट की कोशिश करना चाहते हैं StandardCharsets.UTF_16, जिसके साथ आप कोशिश कर सकते हैं, लेकिन आप हर संभव चरित्र को वैसे भी प्राप्त करने के लिए 100% सुनिश्चित नहीं हो सकते।


-1

आप कुछ इस तरह की कोशिश कर सकते हैं, या बस नीचे और पिछले टुकड़े को कॉपी कर सकते हैं।

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 ++;
    }
}

अपवाद हैंडलर while(exception)लूप को हमेशा के लिए बना सकता है यदि यह सरणी में कभी भी कार्यशील चारसेट नहीं पाता है। अपवाद हैंडलर को फिर से उखाड़ फेंकना चाहिए यदि सरणी का अंत पहुंच गया है और कोई कार्यशील चार्ट नहीं मिला है। साथ ही, इस उत्तर को लिखने के समय तक "-2" वोट थे। मैंने इसे "-1" तक बढ़ा दिया है। मुझे लगता है कि इसका कारण यह है कि नकारात्मक वोट मिले क्योंकि अपर्याप्त व्याख्या है। जबकि मैं समझता हूं कि कोड क्या करता है, अन्य लोग नहीं कर सकते हैं। तो "आप कुछ इस तरह की कोशिश कर सकते हैं" जैसी टिप्पणी को कुछ लोगों द्वारा सराहा नहीं जा सकता है।
मेवेले

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.