2012-08-07 14 views
7

में इनपुटस्ट्रीम की लैटिन -1 सामग्री को कनवर्ट करें मुझे इनपुट इनपुट को स्ट्रिंग में कनवर्ट करने की आवश्यकता है। यहां कठिनाई इनपुट एन्कोडिंग है, अर्थात् लैटिन -1। मैंने एन्कोडिंग को सीधे प्राप्त करने के लिए स्ट्रिंग, गेटबाइट्स, चार [] इत्यादि के साथ कई दृष्टिकोण और कोड स्निपेट की कोशिश की, लेकिन कुछ भी काम नहीं कर रहा था।यूटीएफ -8 स्ट्रिंग

अंत में, मैं नीचे काम कर रहे समाधान के साथ आया था। हालांकि, जावा के लिए भी, यह कोड मेरे लिए थोड़ा वर्बोज़ लगता है। तो यहां सवाल है:

क्या यहां क्या किया जाता है, यह हासिल करने के लिए एक सरल और अधिक सुरुचिपूर्ण दृष्टिकोण है?

private String convertStreamToStringLatin1(java.io.InputStream is) 
     throws IOException { 

    String text = ""; 

    // setup readers with Latin-1 (ISO 8859-1) encoding 
    BufferedReader i = new BufferedReader(new InputStreamReader(is, "8859_1")); 

    int numBytes; 
    CharBuffer buf = CharBuffer.allocate(512); 
    while ((numBytes = i.read(buf)) != -1) { 
     text += String.copyValueOf(buf.array(), 0, numBytes); 
     buf.clear(); 
    } 

    return text; 
} 

उत्तर

7

सबसे पहले, आपके द्वारा पहले से किए गए दृष्टिकोण की कुछ आलोचनाएं। जब आप केवल char[512] चाहते हैं तो आपको अनावश्यक रूप से एनआईओ CharBuffer का उपयोग नहीं करना चाहिए। आपको प्रत्येक पुनरावृत्ति बफर clear की आवश्यकता नहीं है।

int numBytes; 
final char[] buf = new char[512]; 
while ((numBytes = i.read(buf)) != -1) { 
    text += String.copyValueOf(buf, 0, numBytes); 
} 

तुम भी पता होना चाहिए कि सिर्फ constructing a String उन तर्कों के साथ वैसा ही प्रभाव पड़ेगा, निर्माता भी प्रतियां डेटा के रूप में।

उपरोक्त की सामग्री की प्रतिलिपि बनाई गई है; चरित्र सरणी के बाद में संशोधन नव निर्मित स्ट्रिंग को प्रभावित नहीं करता है।


आप एक गतिशील ByteArrayOutputStream जो सभी डेटा को समायोजित करने के लिए एक आंतरिक बफर बढ़ता उपयोग कर सकते हैं। इसके बाद आप में डीकोड करने के लिए toByteArray से पूरे byte[] का उपयोग कर सकते हैं।

लाभ यह है कि अंत तक डिकोडिंग को डीकोडिंग से बचाता है जब अंत अंत में खंडों को डीकोड करने से बचाता है; जबकि यह एएससीआईआई या आईएसओ -885 9 -1 जैसे सरल वर्णों के लिए काम कर सकता है, यह यूटीएफ -8 और यूटीएफ -16 जैसे बहु-बाइट योजनाओं पर काम करेगा। इसका अर्थ यह है कि भविष्य में वर्ण एन्कोडिंग बदलने के लिए आसान है, क्योंकि कोड को कोई संशोधन की आवश्यकता नहीं है।

private static final String DEFAULT_ENCODING = "ISO-8859-1"; 

public static final String convert(final InputStream in) throws IOException { 
    return convert(in, DEFAULT_ENCODING); 
} 

public static final String convert(final InputStream in, final String encoding) throws IOException { 
    final ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    final byte[] buf = new byte[2048]; 
    int rd; 
    while ((rd = in.read(buf, 0, 2048) >= 0) { 
    out.write(buf, 0, rd); 
    } 
    return new String(out.toByteArray(), 0, encoding); 
} 
+0

आपकी आलोचनात्मक टिप्पणी के लिए धन्यवाद। आपका पहला समाधान वह था जो मैं ढूंढ रहा था। हालांकि, मैं आपके दूसरे समाधान के साथ अपना बिंदु देख सकता हूं जो सामान्य मामले को बहुत अधिक संबोधित करता है। मुझे लगता है कि यह भी है कि आपके उदाहरण में बफर आकार 2048 बाइट क्यों है? – cyroxx

+0

2048-बाइट बफर सिर्फ व्यक्तिगत वरीयता थी; आप जो भी रन-टाइम और मेमोरी खपत के लिए उचित व्यापार-बंद प्रदान करते हैं उसका उपयोग कर सकते हैं। – oldrinb

1

मैं नहीं दिख रहा है कि यह कैसे बहुत सरल हो सकता है। मैंने किया था यह थोड़ा अलग एक बार .. यदि आप पहले से ही एक स्ट्रिंग है, तो आप ऐसा कर सकते हैं:

new String(originalString.getBytes(), "ISO-8859-1"); 

तो कुछ इस तरह भी काम कर सकता था:

BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 
StringBuilder sb = new StringBuilder(); 
String line = null; 
while ((line = reader.readLine()) != null) { 
    sb.append(line + "\n"); 
} 
is.close(); 
return new String(sb.toString().getBytes(), "ISO-8859-1"); 

संपादित करें: मैं जोड़ने चाहिए, इस वास्तव में आपके पहले से ही काम करने वाले समाधान का एक विकल्प है। जब जावा में स्ट्रीम को कनवर्ट करने की बात आती है तो यह अधिक आसान नहीं होगा, इसलिए इसके लिए जाएं। :)

+0

वहाँ कई सुधार यहाँ हैं। सबसे पहले, यह इस मामले में सटीक पाठ नहीं देगा कि 'reader.readLine' द्वारा कोई लाइन टर्मिनेटर नहीं मिला है; यह एक पिछला '\ n' जोड़ देगा जो मूल रूप से नहीं था। इसके अलावा, 'BufferedReader' स्वचालित रूप से डिफ़ॉल्ट सिस्टम एन्कोडिंग का उपयोग करेगा। 'StandardCharsets.ISO_8859_1' का उपयोग करने के रूप में बस [' इनपुटस्ट्रीम रीडर'] (http://goo.gl/mhzP1) बनाने के लिए एक बेहतर विचार है, इसलिए आप केवल एक चरण में 'StringBuilder.toString' का उपयोग कर सकते हैं। सही ढंग से डीकोडेड स्ट्रिंग। – oldrinb

+1

\ n: मैं उस सुधार को धन्यवाद देता हूं, मैं वास्तव में इनपुटस्ट्रीम-> स्ट्रिंग रूपांतरण पर ध्यान नहीं दे रहा था, यह सिर्फ उदाहरण को पूरा करने के लिए था। एन्कोडिंग को संभालने का अलग तरीका अभी भी ठीक है, रोम भी कई तरीके हैं। ;-) लेकिन जैसे मैंने कहा कि यह सिर्फ एक विकल्प है। कॉमोनियो जैसे किसी भी यूटिलिटीज कोड को साफ करते हैं, अनिवार्य रूप से वही करते हैं और अतिरिक्त लाइब्रेरी पर निर्भर करते हैं। अगर आप इसका अधिक इस्तेमाल करते हैं तो समझ में आता है .. व्यक्तिगत पसंद का मामला। – Blacklight

0

आप इसे अपने आप को साहुल नहीं करना चाहते हैं आप परियोजना, IOUtils.toString(InputStream input, String encoding) जो कि तुम क्या चाहते हो रहा है कब Apache Commons पर एक नज़र हो सकता था। मैंने खुद को उस विधि की कोशिश नहीं की है, लेकिन जावा दस्तावेज़ कहता है "निर्दिष्ट वर्ण एन्कोडिंग का उपयोग करके एक इनपुट स्ट्रिंग की सामग्री स्ट्रिंग के रूप में प्राप्त करें।"

0

Guava का आईओ पैकेज वास्तव में इस तरह से अच्छा है।

Files.toString(yourFile, CharSets.ISO_8859_1) 

या एक धारा

new String(ByteStreams.toByteArray(stream), CharSets.ISO_8859_1) 
0

मैं सिर्फ पता चला कि this answer सवाल Read/convert an InputStream to a String को अपनी समस्या के लिए लागू किया जा सकता से, कृपया नीचे दिए गए कोड को देखते हैं। वैसे भी, मैं अब तक दिए गए उत्तरों की बहुत सराहना करता हूं।

private String convertStreamToString(InputStream is, String charsetName) { 
    try { 
     return new java.util.Scanner(is, charsetName).useDelimiter("\\A").next(); 
    } catch (java.util.NoSuchElementException e) { 
     return ""; 
    } 
} 

तो आदेश लैटिन -1 से सांकेतिक शब्दों में बदलना करने के लिए, इस तरह इसे कहते:

String message = convertStreamToString(is, "8859_1"); 
+0

आपको पता होना चाहिए कि 'स्कैनर' आंतरिक रूप से डेलीमीटर के लिए एक रेगेक्स 'पैटर्न' संकलित करता है। यह विधि वास्तव में दिलचस्प और निफ्टी है, लेकिन संभवतः सलाह नहीं दी जाती है। – oldrinb

+0

मैं इस पर कुछ और जानकारी हासिल करना चाहता हूं: उस पैटर्न के साथ समस्या क्या है? क्या यह हल्का वजन नहीं होना चाहिए? – cyroxx

+0

यह सिर्फ एक दिलचस्प समाधान की तरह लगता है लेकिन 'स्कैनर' का दुरुपयोग। आपके द्वारा लिंक किए गए उत्तर में, उन्होंने इसे अच्छी तरह से रखा ... एक * बेवकूफ 'स्कैनर' चाल *। – oldrinb

संबंधित मुद्दे