2009-02-06 27 views
6

भाग में जावा स्ट्रिंग को विभाजित करें जावा में 1024 बाइट्स के हिस्सों में स्ट्रिंग को विभाजित करने का एक प्रभावी तरीका क्या है? यदि एक से अधिक खंड हैं तो हेडर (निश्चित आकार स्ट्रिंग) को बाद के सभी हिस्सों में दोहराया जाना चाहिए।1024 बाइट्स

+0

बस जांच कर रहे हैं कि क्या आप जानते हैं जावा में टी, स्ट्रिंग्स वर्णों से बना है और बाइट नहीं हैं। एक चार एकाधिक बाइट हो सकता है। – mparaz

+0

धन्यवाद मैं इसके बारे में बहुत ज्यादा जानता हूं। हालांकि आप String.getBytes() का उपयोग कर स्ट्रिंग के संबंधित बाइट [] प्राप्त कर सकते हैं। यह एक आम समस्या है जब उदाहरण के लिए आप नेटवर्क पर स्ट्रिंग सामग्री भेजना चाहते हैं। – user54729

+0

आपको हेडर दोहराने की ज़रूरत क्यों है? –

उत्तर

5

स्ट्रिंग्स और बाइट्स दो पूरी तरह से अलग चीजें हैं, इसलिए एक स्ट्रिंग को बाइट्स में विभाजित करना चाहते हैं, जैसा कि पेंटिंग को छंदों में विभाजित करना चाहते हैं।

आप वास्तव में क्या करना चाहते हैं?

स्ट्रिंग्स और बाइट्स के बीच कनवर्ट करने के लिए, आपको एक एन्कोडिंग निर्दिष्ट करने की आवश्यकता है जो स्ट्रिंग में सभी वर्णों को एन्कोड कर सके। एन्कोडिंग और पात्रों के आधार पर, उनमें से कुछ एक से अधिक बाइट फैल सकते हैं।

आप या तो स्ट्रिंग को 1024 वर्णों के टुकड़ों में विभाजित कर सकते हैं और बाइट्स के रूप में एन्कोड कर सकते हैं, लेकिन फिर प्रत्येक खंड 1024 बाइट से अधिक हो सकता है।

या आप मूल स्ट्रिंग को बाइट्स में एन्कोड कर सकते हैं और फिर उन्हें 1024 के हिस्सों में विभाजित कर सकते हैं, लेकिन फिर आपको उन्हें एक स्ट्रिंग में फिर से डीकोड करने से पहले बाइट्स के रूप में जोड़ना होगा, या आप गलेदार अक्षर प्राप्त कर सकते हैं विभाजित बिंदु जब एक चरित्र 1 बाइट से अधिक फैलता है।

यदि स्ट्रिंग बहुत लंबा हो सकता है तो आप मेमोरी उपयोग के बारे में चिंतित हैं, तो आपको कई बार स्मृति में डेटा को रखने से बचने के लिए एन/डीकोडिंग और विभाजन में स्ट्रीम (java.io पैकेज) का उपयोग करना चाहिए प्रतियों के रूप में। आदर्श रूप से, आपको एक टुकड़े में मूल स्ट्रिंग होने से बचना चाहिए और इसके बजाय इसे जहां से आप इसे प्राप्त करते हैं, वहां से छोटे हिस्सों में इसे पढ़ने के लिए स्ट्रीम का उपयोग करें।

private static String chunk_split(String original, int length, String separator) throws IOException { 
    ByteArrayInputStream bis = new ByteArrayInputStream(original.getBytes()); 
    int n = 0; 
    byte[] buffer = new byte[length]; 
    String result = ""; 
    while ((n = bis.read(buffer)) > 0) { 
     for (byte b : buffer) { 
      result += (char) b; 
     } 
     Arrays.fill(buffer, (byte) 0); 
     result += separator; 
    } 
    return result; 
} 

उदाहरण:

public static void main(String[] args) throws IOException{ 
     String original = "abcdefghijklmnopqrstuvwxyz"; 
     System.out.println(chunk_split(original,5,"\n")); 
} 

आउटपुट:

7

आपके पास दो तरीके हैं, तेज़ और मेमोरी रूढ़िवादी तरीका है। लेकिन सबसे पहले, आपको यह जानने की जरूरत है कि स्ट्रिंग में कौन से वर्ण हैं। ASCII? क्या वहां umlauts (128 और 255 के बीच वर्ण) हैं या यहां तक ​​कि यूनिकोड (s.getChar() कुछ वापस लौटाता है> 256)। उस पर निर्भर करते हुए, आपको एक अलग एन्कोडिंग का उपयोग करने की आवश्यकता होगी। यदि आपके पास बाइनरी डेटा है, तो "iso-8859-1" आज़माएं क्योंकि यह स्ट्रिंग में डेटा को सुरक्षित रखेगा। यदि आपके पास यूनिकोड है, तो "utf-8" आज़माएं। मैं बाइनरी डेटा मान लेंगे:

String encoding = "iso-8859-1"; 

सबसे तेज़ तरीका:

ByteArrayInputStream in = new ByteArrayInputStream (string.getBytes(encoding)); 

ध्यान दें कि स्ट्रिंग यूनिकोड है, इसलिए हर चरित्र दो बाइट्स की जरूरत है। आपको एन्कोडिंग निर्दिष्ट करना होगा ("प्लेटफ़ॉर्म डिफ़ॉल्ट" पर भरोसा न करें। इससे केवल दर्द हो जाएगा)।

अब आप

byte[] buffer = new byte[1024]; 
int len; 
while ((len = in.read(buffer)) > 0) { ... } 

यह मूल स्ट्रिंग के रूप में के रूप में ज्यादा के बारे में तीन बार RAM की आवश्यकता का उपयोग कर 1024 मात्रा में यह पढ़ सकते हैं।

एक और मेमोरी रूढ़िवादी तरीका एक कनवर्टर लिखना है जो एक स्ट्रिंग रीडर और आउटपुटस्ट्रीमवाइटर (जो बाइटएरे ऑटपुटस्ट्रीम को लपेटता है) लेता है। कॉपी लेखक को पाठक से बाइट्स जब तक अंतर्निहित बफर डेटा में से एक हिस्सा शामिल हैं:

ऐसा होने पर, डेटा वास्तविक उत्पादन (हेडर prepending) करने के लिए, कॉपी अतिरिक्त बाइट्स कॉपी (जो Unicode-> बाइट रूपांतरण उत्पन्न हो सकता है) एक अस्थायी बफर में, buffer.reset() पर कॉल करें और बफर बफर को बफर में लिखें।

कोड इस (untested) की तरह दिखता है:

StringReader r = new StringReader (string); 
ByteArrayOutputStream buffer = new ByteArrayOutputStream (1024*2); // Twice as large as necessary 
OutputStreamWriter w = new OutputStreamWriter (buffer, encoding); 

char[] cbuf = new char[100]; 
byte[] tempBuf; 
int len; 
while ((len = r.read(cbuf, 0, cbuf.length)) > 0) { 
    w.write(cbuf, 0, len); 
    w.flush(); 
    if (buffer.size()) >= 1024) { 
     tempBuf = buffer.toByteArray(); 
     ... ready to process one chunk ... 
     buffer.reset(); 
     if (tempBuf.length > 1024) { 
      buffer.write(tempBuf, 1024, tempBuf.length - 1024); 
     } 
    } 
} 
... check if some data is left in buffer and process that, too ... 

यह केवल रैम किलोबाइट की एक जोड़ी की जरूरत है।

[संपादित करें] टिप्पणियों में स्ट्रिंग्स में बाइनरी डेटा के बारे में एक लंबी चर्चा हुई है। सबसे पहले, जब तक आप इसे बनाते समय सावधान रहें और इसे कहीं भी संग्रहीत करते हैं, तब तक बाइनरी डेटा को स्ट्रिंग में रखना सुरक्षित है। इस तरह के एक स्ट्रिंग बनाने के लिए, एक बाइट [] सरणी लेने के लिए और: 1 मानचित्रण:

String safe = new String (array, "iso-8859-1"); 

में जावा, ISO-8859-1 (आईएसओ-लेटिन 1 a.k.a) एक 1 है। इसका मतलब है कि सरणी में बाइट किसी भी तरह से व्याख्या नहीं किया जाएगा। अब आप डेटा पर सबस्ट्रिंग() और की तरह उपयोग करें या सूचकांक के साथ यह खोज सकते हैं, चलाने regexp उस पर की, आदि उदाहरण के लिए, एक 0-बाइट की स्थिति का पता लगाने:

int pos = safe.indexOf('\u0000'); 

यह विशेष रूप से उपयोगी है अगर आप डेटा के एन्कोडिंग को नहीं जानते हैं और इसके साथ कुछ कोडेक गड़बड़ से पहले इसे देखना चाहते हैं।

कहीं डेटा लिखने के लिए, रिवर्स ऑपरेशन है:

बाइट [] डेटा = सुरक्षित।getBytes ("ISO-8859-1");

कभी भी डिफ़ॉल्ट विधियों का उपयोग न करें new String(array) या String.getBytes()! एक दिन, आपका कोड एक अलग मंच पर निष्पादित किया जा रहा है और यह टूट जाएगा।

अब स्ट्रिंग में वर्णों की समस्या> 255 की समस्या। यदि आप इस विधि का उपयोग करते हैं, तो आपके पास कभी भी आपके स्ट्रिंग्स में ऐसा कोई चरित्र नहीं होगा। उस ने कहा, अगर किसी कारण से कोई था, तो GetBytes() एक अपवाद फेंक देगा क्योंकि आईएसओ-लैटिन 1 में सभी यूनिकोड वर्णों को व्यक्त करने का कोई तरीका नहीं है, इसलिए आप इस अर्थ में सुरक्षित हैं कि कोड चुपचाप विफल नहीं होगा।

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

एक्सएमएल के साथ भी, आपको मांस को डीकोड करने से पहले एन्कोडिंग निर्धारित करने के लिए फ़ाइल के शीर्षलेख को बाइट्स के रूप में पढ़ना होगा।

महत्वपूर्ण बात यह है कि यह निर्धारित करना है कि डेटा स्ट्रीम को उत्पन्न करने के लिए कौन सी एन्कोडिंग का उपयोग किया गया था। यदि आप ऐसा करते हैं, तो आप अच्छे हैं, अगर आप नहीं करते हैं, तो आप बर्बाद हो जाते हैं। भ्रम इस तथ्य से निकलता है कि ज्यादातर लोगों को पता नहीं है कि एक ही बाइट एन्कोडिंग के आधार पर अलग-अलग चीजों का मतलब हो सकता है या यहां तक ​​कि एक से अधिक एन्कोडिंग भी हो सकती है। इसके अलावा, अगर सूर्य ने "प्लेटफार्म डिफ़ॉल्ट एन्कोडिंग" की धारणा पेश नहीं की है तो इससे मदद मिलेगी।

शुरुआती के लिए महत्वपूर्ण अंक:

  • वहाँ एक से अधिक एन्कोडिंग (चारसेट) है।
  • अंग्रेजी भाषा के उपयोग से अधिक वर्ण हैं। यहां तक ​​कि sets of digits (ASCII, पूर्ण चौड़ाई, अरबी-इंडिक, बंगाली) भी हैं।
  • आपको पता होना चाहिए कि आपके द्वारा प्रसंस्करण किए जा रहे डेटा को उत्पन्न करने के लिए कौन सी एन्कोडिंग का उपयोग किया गया था।
  • आपको पता होना चाहिए कि आपके द्वारा प्रसंस्करण किए जा रहे डेटा को लिखने के लिए आपको किस एन्कोडिंग का उपयोग करना चाहिए।
  • आपको इस एन्कोडिंग जानकारी को निर्दिष्ट करने का सही तरीका पता होना चाहिए ताकि अगला प्रोग्राम आपके आउटपुट (एक्सएमएल हेडर, एचटीएमएल मेटा टैग, विशेष एन्कोडिंग टिप्पणी, जो भी हो) को डीकोड कर सके।

एएससीआईआई के दिन खत्म हो गए हैं।

+0

क्या यह उस समस्या से पीड़ित होगा जो kdgregory का उल्लेख कर रहा था? यह, आपके प्लेटफ़ॉर्म डिफ़ॉल्ट एन्कोडिंग के आधार पर, आप एक वर्ण को दो अर्थहीन टुकड़ों में विभाजित कर सकते हैं – user54729

+0

कृपया "आईएसओ -885 9 -1" का उपयोग न करें। "Utf8" का प्रयोग करें। यूटीएफ 8 एक ही बाइट में आईएसओ -885 9 -1 के बहुत सारे हैंडल करता है, लेकिन सभी पात्रों को संभालने के लिए स्केल कर सकता है। हां, अज्ञात, यह एक चरित्र को दो अर्थहीन टुकड़ों में विभाजित कर सकता है ... या उन्हें दूर फेंक दिया, जो आईएसओ -885 9 -1 होगा। –

+0

नहीं, क्योंकि मैं एन्कोडिंग "आईएसओ -885 9 -1" निर्दिष्ट कर रहा हूं (जो लैटिन -1 है, यानी एसीसीआईआई उमलॉट्स के साथ)। यदि आपके स्ट्रिंग में अन्य वर्ण हैं (कोडपॉइंट 256 से ऊपर), तो आपको यहां कुछ और उपयोग करना चाहिए लेकिन लैटिन -1 आमतौर पर अच्छा होता है क्योंकि यह कुछ भी नहीं बदलता है। –

2

मैं जानता हूँ कि मैं कर रहा हूँ देर से, लेकिन मैं एक समाधान के लिए अपने आप को देख रहा था और उसके बाद से सर्वोत्तम उत्तर मेरा उत्तर मिल गया

abced 
fghij 
klmno 
pqrst 
uvwxy 
z 
+0

यह बहुत उपयोगी उत्तर है ... धन्यवाद @ आलान दीप .. – Kushal

+1

मुझे खुशी है। @Kushal –

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