2013-10-19 23 views
6

Başlık, her şeyi açıklıyor. StringBuilder'dan ortadaki bir String kullanmadan byte [] dönüştürmek için herhangi bir yolu var mı? Sorun şu ki, GERÇEKTEN büyük dizeleri (milyonlarca chars) yönetiyorum, ve sonunda bir char ekleyen ve byte [] elde eden bir döngüye sahibim. StringBuffer'ı String'e dönüştürme işlemi bu döngüyü çok çok yavaş bir şekilde yapar.Java: StringBuffer toto [byString] olmaksızın

Bunu gerçekleştirmenin bir yolu var mı? Şimdiden teşekkürler!

+0

En yakın alabileceğiniz bir 'char []' dizisi elde etmektir. StringBuffer # getChars (int, int, char [], int) –

+2

neden [CharBuffer] (http://docs.oracle.com/javase/7/docs/api/java/nio/CharBuffer.html) kullanmıyorsunuz? Ve sonra "charBuffer.array()"? – tolitius

+2

Tüm bu büyük dizeleri neden bellekte saklamanız gerektiğini açıklayabilir misiniz? Bu bir kullanıcının beklediği bir şey mi? Bunun yerine bir MapReduce veya Spark işi olabilir mi? Merak ediyorum, belki bu soru bir mimari tasarım kokusunun bir belirtisidir. – Vidya

cevap

1

StringBuffer, genellikle gereksiz olan bir eşitleme ek yüküne sahip olduğundan, yeni başlayanlar için muhtemelen StringBuilder kullanıyor olmalısınız.

Maalesef byte s doğrudan gitmek için yolu yoktur, ancak bir diziye char s kopyalamak veya 0 den length() için yineleme ve her charAt() okuyabilir.

+0

+1 Ve StringBuffer için Javadoc, yaklaşık on yıldır StringBuilder kullanmanız gerektiğini söylüyor. Karakter kodlamasını doğru şekilde uygulayan doğru yanıt için –

0

"Milyonlarca" ile neyi başarmaya çalışıyorsunuz? Ayrıştırılması gereken bu günlükler mi? Sadece bayt olarak okuyabilir ve bir ByteBuffer'a yapışabilir misin? Sonra yapabilirsiniz:

buffer.array() 

bir byte[]

o yapıyorsun ne bağlıdır almak için, ayrıca sadece bir char[] veya CharBuffer kullanabilirsiniz: Sonra

CharBuffer cb = CharBuffer.allocate(4242); 
cb.put("Depends on what it is you need to do"); 
... 

yapabilirsiniz olsun bir char[] olarak:

cp.array() 

REPL şeyleri her zaman güzeldir, eğlenceli ve kanıtı ispat eder. Java REPL akıcı Java konuşan günü kurtarmak için Clojure var, hey alışık olduğumuz bir şey değil, ama:

user=> (import java.nio.CharBuffer) 
java.nio.CharBuffer 

user=> (def cb (CharBuffer/allocate 4242)) 
#'user/cb 

user=> (-> (.put cb "There Be") (.array)) 
#<char[] [[email protected]> 

user=> (-> (.put cb " Dragons") (.array) (String.)) 
"There Be Dragons" 
11

zaten sen CharBuffer sınıfını kullanın, ancak yeni bir CharBuffer tahsis edebilir önerdi gibi birçok sadece probleminizi daha da kötüleştirebilir. StringBuilder CharSequence uygulayan beri

Bunun yerine, direkt olarak, bir CharBuffer daki StringBuilder kaydırılabilir:

Charset charset = StandardCharsets.UTF_8; 
CharsetEncoder encoder = charset.newEncoder(); 

// No allocation performed, just wraps the StringBuilder. 
CharBuffer buffer = CharBuffer.wrap(stringBuilder); 

ByteBuffer bytes = encoder.encode(buffer); 

DÜZENLEME: Duarte doğru CharsetEncoder.encode yöntem, destek dizisi daha büyük olan bir tampon döndürebilir işaret gerçek veriler — anlam, kapasitesi kendi sınırından daha büyüktür. ByteBuffer'ın kendisinden okumak ya da ByteBuffer'dan doğru boyutta olması garanti edilen bir bayt dizisini okumak gerekir. Eğer performansı istiyorsanız

ByteBuffer byteBuffer = encoder.encode(buffer); 

byte[] array; 
int arrayLen = byteBuffer.limit(); 
if (arrayLen == byteBuffer.capacity()) { 
    array = byteBuffer.array(); 
} else { 
    // This will place two copies of the byte sequence in memory, 
    // until byteBuffer gets garbage-collected (which should happen 
    // pretty quickly once the reference to it is null'd). 

    array = new byte[arrayLen]; 
    byteBuffer.get(array); 
} 

byteBuffer = null; 
+0

+1. –

+1

Dikkat: ByteBuffer.array(), büyük olasılıkla fazladan bayt içerecek olan tüm destek dizisini döndürür! –

0

, ben StringBuilder kullanın veya bir byte [] yaratmaz: İkinci durumda, hiçbir kısaca da olsa, bellekte bayt iki kopyasını içeren kaçınarak var. Bunun yerine, verileri ilk sırada alacak olan akışa aşamalı olarak yazabilirsiniz. Bunu yapamazsanız, verileri StringBuilder'dan Writer'e kopyalayabilirsiniz, ancak StringBuilder'ı ilk etapta oluşturmamak çok daha hızlıdır.

+0

Akışa kademeli olarak yazmaktan nasıl bahsederdik? Bayt alma işlevim var [] – CyberMew

+0

Şu ana kadar okuduğunuz bayt [] ile arayabileceğiniz işlevlere ihtiyacınız var. https://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html#write(byte[],%20int,%20int) Bu işlev, aynı baytı [] kullanmanızı sağlar. Bu sayede işlenen verilerin büyüklüğüne bakılmaksızın bellek tüketimi ve çöp değişkeni sabit kalır. –

2

Eğer başka bir şeyle StringBuilder yerine istekli, henüz başka olasılık ByteArrayOutputStream tarafından desteklenen bir Writer olurdu:

ByteArrayOutputStream bout = new ByteArrayOutputStream(); 
Writer writer = new OutputStreamWriter(bout); 
try { 
    writer.write("String A"); 
    writer.write("String B"); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
System.out.println(bout.toByteArray()); 

try { 
    writer.write("String C"); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
System.out.println(bout.toByteArray()); 

Her zaman olduğu gibi, kilometre durumunuz değişebilir.