2012-06-20 17 views
5

byte[] से StringBuilder बनाने का कोई तरीका है?बाइट से स्ट्रिंगबिल्डर बनाएं []

मैं StringBuilder का उपयोग कर स्मृति के उपयोग में सुधार करना चाहते हैं, लेकिन क्या मैं पहली बार एक byte[] है, इसलिए मैं byte[] से एक String बनाने और उसके बाद String से StringBuilder बनाने के लिए है और मैं इष्टतम के रूप में इस समस्या का समाधान नहीं दिख रहा है।

धन्यवाद

+6

मुझे हिम्मत है कि यह सैद्धांतिक रूप से इष्टतम नहीं है, लेकिन क्या यह वास्तव में एक * समस्या * है? क्या आपने यह दिखाने के लिए उचित परीक्षण किए हैं कि इसका क्या असर पड़ रहा है? –

+5

उस स्ट्रिंगबिल्डर के साथ आप क्या कर रहे हैं? – Thilo

+2

यदि आप डिकोडिंग प्रक्रिया पर अधिक नियंत्रण चाहते हैं और यह किस स्मृति का उपयोग करता है, तो आप सीधे ['CharsetDecoder'] (http://docs.oracle.com/javase/7/docs/api/java/nio/charset का उपयोग कर सकते हैं) /CharsetDecoder.html) और समर्पित 'CharBuffer' (' स्ट्रिंगबिल्डर 'का उपयोग करने के बजाय) में डीकोड करें। –

उत्तर

12

मूल रूप से, आपका सबसे अच्छा विकल्प सीधे CharsetDecoder का उपयोग किया जा रहा है।

byte[] srcBytes = getYourSrcBytes(); 

//Whatever charset your bytes are endoded in 
Charset charset = Charset.forName("UTF-8"); 
CharsetDecoder decoder = charset.newDecoder(); 

//ByteBuffer.wrap simply wraps the byte array, it does not allocate new memory for it 
ByteBuffer srcBuffer = ByteBuffer.wrap(srcBytes); 
//Now, we decode our srcBuffer into a new CharBuffer (yes, new memory allocated here, no can do) 
CharBuffer resBuffer = decoder.decode(srcBuffer); 

//CharBuffer implements CharSequence interface, which StringBuilder fully support in it's methods 
StringBuilder yourStringBuilder = new StringBuilder(resBuffer); 

जोड़ा:

कुछ परीक्षण करने के बाद ऐसा लगता है कि सरल new String(bytes) तेज हो गया है और ऐसा लगता है वहाँ यह तेजी से है कि तुलना में बनाने के लिए कोई आसान तरीका है

यहाँ कैसे।

import java.io.IOException; 
import java.io.UnsupportedEncodingException; 
import java.nio.ByteBuffer; 
import java.nio.CharBuffer; 
import java.nio.charset.CharacterCodingException; 
import java.nio.charset.Charset; 
import java.nio.charset.CharsetDecoder; 
import java.text.ParseException; 

public class ConsoleMain { 
    public static void main(String[] args) throws IOException, ParseException { 
     StringBuilder sb1 = new StringBuilder("abcdefghijklmnopqrstuvwxyz"); 
     for (int i=0;i<19;i++) { 
      sb1.append(sb1); 
     } 
     System.out.println("Size of buffer: "+sb1.length()); 
     byte[] src = sb1.toString().getBytes("UTF-8"); 
     StringBuilder res; 

     long startTime = System.currentTimeMillis(); 
     res = testStringConvert(src); 
     System.out.println("Conversion using String time (msec): "+(System.currentTimeMillis()-startTime)); 
     if (!res.toString().equals(sb1.toString())) { 
      System.err.println("Conversion error"); 
     } 

     startTime = System.currentTimeMillis(); 
     res = testCBConvert(src); 
     System.out.println("Conversion using CharBuffer time (msec): "+(System.currentTimeMillis()-startTime)); 
     if (!res.toString().equals(sb1.toString())) { 
      System.err.println("Conversion error"); 
     } 
    } 

    private static StringBuilder testStringConvert(byte[] src) throws UnsupportedEncodingException { 
     String s = new String(src, "UTF-8"); 
     StringBuilder b = new StringBuilder(s); 
     return b; 
    } 

    private static StringBuilder testCBConvert(byte[] src) throws CharacterCodingException { 
     Charset charset = Charset.forName("UTF-8"); 
     CharsetDecoder decoder = charset.newDecoder(); 
     ByteBuffer srcBuffer = ByteBuffer.wrap(src); 
     CharBuffer resBuffer = decoder.decode(srcBuffer); 
     StringBuilder b = new StringBuilder(resBuffer); 
     return b; 
    } 
} 

परिणाम::

Size of buffer: 13631488 
Conversion using String time (msec): 91 
Conversion using CharBuffer time (msec): 252 

और एक संशोधित (कम स्मृति लेने वाली) IDEONE संस्करण: Here यहाँ परीक्षण मैं भाग गया है।

+0

ऐसा लगता है कि स्ट्रिंग का उपयोग करने की तुलना में किसी भी स्मृति को सहेजने की प्रतीत नहीं होती है। इसे उपयोगी बनाने के लिए, उसे स्ट्रिंगबिल्डर के बजाय चारबफर का उपयोग जारी रखना होगा। – Thilo

+0

@ थिलो, एचएम, स्ट्रिंगबिल्डर स्रोतों की जांच करने जा रहा है, लेकिन आप सही हो सकते हैं। – bezmax

+0

@ थिलो, ऐसा लगता है कि आप गलत हैं। यदि अस्थायी स्ट्रिंग वेरिएबल (प्रश्न शरीर में ओपी समाधान) के साथ प्रयोग किया जाता है, तो CharBuffer स्ट्रिंग में परिवर्तित हो जाता है, जिसे स्ट्रिंगबिल्डर में आंतरिक चार सरणी में कॉपी किया जाता है। मेरे समाधान में, CharBuffer को CharSequence विधियों का उपयोग करके स्ट्रिंगबिल्डर में सीधे आंतरिक चार सरणी में कॉपी किया गया है। इसलिए, हमें स्मृति में 1 अस्थायी स्ट्रिंग ऑब्जेक्ट की आवश्यकता नहीं है। – bezmax

4

यदि यह छोटा कथन है जो आप चाहते हैं, तो स्ट्रिंग चरण के बीच में कोई रास्ता नहीं है। स्ट्रिंग कन्स्ट्रक्टर एक बहुत ही सामान्य मामले में सुविधा के लिए रूपांतरण और ऑब्जेक्ट निर्माण को मिश्रित करता है, लेकिन स्ट्रिंगबिल्डर के लिए ऐसा कोई सुविधा कन्स्ट्रक्टर नहीं है।

यदि यह प्रदर्शन आप में रुचि रखते हैं है, तो आप मध्यवर्ती स्ट्रिंग ऑब्जेक्ट कुछ इस तरह का उपयोग करके न करना चाहें:

new StringBuilder(Charset.forName(charsetName).decode(ByteBuffer.wrap(inBytes))) 

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

CharsetDecoder cd = Charset.forName(charsetName).newDecoder(); 
cd.onMalformedInput(CodingErrorAction.REPLACE); 
cd.onUnmappableCharacter(CodingErrorAction.REPLACE); 
int lengthEstimate = Math.ceil(cd.averageCharsPerByte()*inBytes.length) + 1; 
ByteBuffer inBuf = ByteBuffer.wrap(inBytes); 
CharBuffer outBuf = CharBuffer.allocate(lengthEstimate); 
StringBuilder out = new StringBuilder(lengthEstimate); 
CoderResult cr; 
while (true) { 
    cr = cd.decode(inBuf, outBuf, true); 
    out.append(outBuf); 
    outBuf.clear(); 
    if (cr.isUnderflow()) break; 
    if (!cr.isOverflow()) cr.throwException(); 
} 
cr = cd.flush(outBuf); 
if (!cr.isUnderflow()) cr.throwException(); 
out.append(outBuf); 

मुझे शक है कि इसके बाद के संस्करण कोड, हालांकि ज्यादातर अनुप्रयोगों में प्रयास के लायक हो जाएगा। यदि कोई एप्लिकेशन प्रदर्शन में रूचि रखता है, तो शायद इसे स्ट्रिंगबिल्डर से भी निपटना नहीं चाहिए, लेकिन बफर स्तर पर सब कुछ संभाल लें।

+0

"स्ट्रिंग कन्स्ट्रक्टर एक बहुत ही सामान्य मामले में सुविधा के लिए रूपांतरण और ऑब्जेक्ट निर्माण को मिश्रित करता है": केवल सुविधा नहीं - रूपांतरण और निर्माण वास्तव में जुड़े हुए हैं, स्ट्रिंग सीधे कनवर्टर द्वारा उपयोग की जाने वाली आंतरिक सरणी का उपयोग करती है, इसलिए एक प्रदर्शन लाभ होता है, भी। तो मुझे लगता है कि इसे प्रदर्शन के अनुसार मारना बहुत कठिन होगा (आपका दृष्टिकोण सबसे अच्छा समकक्ष प्रतीत होता है, @ मैक्स का जवाब भी देखें)। – Thilo

+0

ओपनजेडीके के कार्यान्वयन के बारे में बात करते हुए [स्ट्रिंगकोडिंग) [http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/classes/java/lang/StringCoding.java] के बारे में बात करना: हाँ, यह एक ही सरणी का उपयोग करता है, यदि निम्न स्थितियों में से सभी का पालन होता है: - डीकोडर को जेडीके के साथ भेज दिया गया था - आकार का अनुमान सही था उदाहरण के लिए यूटीएफ -8, यदि इनपुट में एक मल्टीबाइट अनुक्रम है, तो यहां एक सरणी प्रति भी आवश्यक होगी। जो संभवतः बराबर प्रदर्शन में परिणाम देगा, मेरे सुझावों से भी बदतर नहीं। – MvG

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