Java'da bir dizenin baytı


179

Java'da, bir Dize'im varsa x, o dizedeki bayt sayısını nasıl hesaplayabilirim?


15
Bir HTTP yanıtının gövdesini temsil etmek için bir Dize kullanmak ve karakterleri değil sekizli / bayt olarak belirtilen "Content-Length" üstbilgisini ayarlamak için boyutu kullanmak isteyebilirsiniz. w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
iX3

4
Bir veritabanı sütununun bayt cinsinden uzunluk kısıtlaması olabilir, örneğin Oracle'daki VARCHAR2 (4000 BYTE). Dize uygun olup olmadığını bilmek için istenen kodlamada bir Dize bayt sayısını bilmek isteyebilirsiniz.
Somu

@ iX3 Yapmaya çalıştığımın aynısı.
MC İmparatoru

1
Ben niyetine bağlı olarak, bu sorunun iki olası yorum olduğuna inanıyorum: biri "ne kadar bellek benim String kullanır?" Dır. Bunun cevabı aşağıda @roozbeh tarafından sağlanmıştır (belki sıkıştırılmış OOPS gibi modulo VM incelikleri). Diğeri ise, "dizgiyi bir bayta [] dönüştürürsem, o bayt dizisinin ne kadar bellek kullanır?". Bu Andrzej Doyle'un cevapladığı soru. Fark büyük olabilir: UTF8'deki "Merhaba Dünya" 11 bayttır, ancak String (@roozbeh başına) 50 bayttır (eğer benim matematik doğru ise).
L. Blanc

11 baytın onları tutan byte [] nesnesinin ek yükünü içermediğini eklemeliydim, bu yüzden karşılaştırma biraz yanıltıcıdır.
L. Blanc

Yanıtlar:


289

Dize, karakterlerin listesidir (yani kod noktaları). Dizeyi temsil etmek için alınan bayt sayısı tamamen baytı dönüştürmek için hangi kodlamayı kullandığınıza bağlıdır .

Bununla birlikte, dizeyi bir bayt dizisine dönüştürebilir ve ardından boyutuna aşağıdaki gibi bakabilirsiniz:

// The input string for this test
final String string = "Hello World";

// Check length, in characters
System.out.println(string.length()); // prints "11"

// Check encoded sizes
final byte[] utf8Bytes = string.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "11"

final byte[] utf16Bytes= string.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "24"

final byte[] utf32Bytes = string.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "44"

final byte[] isoBytes = string.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "11"

final byte[] winBytes = string.getBytes("CP1252");
System.out.println(winBytes.length); // prints "11"

Gördüğünüz gibi, basit bir "ASCII" dizesi bile, hangi kodlamanın kullanıldığına bağlı olarak, temsilinde farklı sayıda bayt içerebilir. Davanız için ilgilendiğiniz karakter kümesini bağımsız değişken olarak kullanın getBytes(). UTF-8'in her karakteri tek bir bayt olarak temsil ettiğini varsaymak tuzağına düşmeyin , çünkü bu da doğru değil:

final String interesting = "\uF93D\uF936\uF949\uF942"; // Chinese ideograms

// Check length, in characters
System.out.println(interesting.length()); // prints "4"

// Check encoded sizes
final byte[] utf8Bytes = interesting.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "12"

final byte[] utf16Bytes= interesting.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "10"

final byte[] utf32Bytes = interesting.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "16"

final byte[] isoBytes = interesting.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "4" (probably encoded "????")

final byte[] winBytes = interesting.getBytes("CP1252");
System.out.println(winBytes.length); // prints "4" (probably encoded "????")

(Bir karakter kümesi bağımsız değişkeni sağlamazsanız, platformun varsayılan karakter kümesinin kullanıldığını unutmayın. Bu, bazı bağlamlarda yararlı olabilir, ancak genel olarak varsayılanlara bağlı olarak kaçınmanız ve / kod çözme gereklidir.)


1
eğer tekrar getBytes () kullanırsanız, bu yüzden bana emin değilim çünkü x.length aynı uzunluğunu ben yanlış değilim
Green

4
@Green Ash Bayt dizisinin uzunluğu - getBytes () - ve x.length eşit olabilir, ancak böyle olacağı garanti edilmez. Tüm karakterlerin her biri tek bir baytla temsil edilmesi eşit olacaktır. Bu, ISO-8859-1 gibi karakter başına tek bir bayt (veya daha az) kullanan karakter kodlamaları için her zaman geçerlidir. UTF-8, 1 veya 2 bayt kullanır, bu nedenle dizedeki kesin karakterlere bağlıdır. Sonra her karakter için iki bayt kullanan karakter kodlamaları vardır.
Kris

Cevabınızı seviyorum :), bu yüzden bir şekilde aynı olabilirler ama her zaman doğru değil miyim? Tamam o zaman bana bir hata neden çünkü parametresiz yöntemi kullanmak için sorun yok!
Yeşil

@Yeşil nokta, bayt sayısının her zaman karakter sayısıyla aynı olmamasıdır . Bayt sayısı kullanılan karakter kodlamasına bağlıdır. Hangi karakter kodlamasını kullanacağınızı bilmeniz ve bunu dikkate almanız gerekir. Ne hatası alıyorsunuz? Sadece kullanırsanız getBytes(), sisteminizin varsayılan karakter kodlamasını kullanır.
Jesper

1
@KorayTugay Evet, az çok. Yine de neden ve sonuçların sırası hakkında tartışabilirsiniz. Ben bir karakter her zaman 2 bayt olduğunu belirtmek için daha eğilimli çünkü 2 bayt genişliğinde tanımlanmış ilkel bir veri türüdür . (Ve UTF-16 temsilinin, bunun tersi değil, esas olarak bunun bir sonucu olduğunu.)
Andrzej Doyle

63

64 bit referanslarla çalışıyorsanız:

sizeof(string) = 
8 + // object header used by the VM
8 + // 64-bit reference to char array (value)
8 + string.length() * 2 + // character array itself (object header + 16-bit chars)
4 + // offset integer
4 + // count integer
4 + // cached hash code

Diğer bir deyişle:

sizeof(string) = 36 + string.length() * 2

32-bit VM veya sıkıştırılmış OOP'lara sahip bir 64-bit VM'de (-XX: + UseCompressedOops) başvurular 4 bayttır. Yani toplam:

sizeof(string) = 32 + string.length() * 2

Bu, string nesnesine yapılan referansları dikkate almaz.


6
Soru bir String nesnesi için bellekte ayrılan bayt sayısı hakkında olduğunu varsayıyordu. Soru, Dizinin serileştirilmesi için gerekli bayt sayısı ile ilgiliyse, diğerlerinin de belirttiği gibi, kullanılan kodlamaya bağlıdır.
roozbeh

2
Cevabınız için kaynak? Thanks
mavis

1
Not: sizeof8. çoklu olmalıdır
dieter

19

Bilgiçliksel cevap (sonuçla ne yapmak istediğinize bağlı olarak mutlaka en yararlı olanı değildir):

string.length() * 2

Java dizeleri, UTF-16BEkod birimi başına 2 bayt kullanan ve String.length()UTF-16 kod birimlerindeki uzunluğu ölçen fiziksel olarak kodlamada saklanır , bu nedenle:

final byte[] utf16Bytes= string.getBytes("UTF-16BE");
System.out.println(utf16Bytes.length);

Bu size dahili chardizinin boyutunu bayt cinsinden söyleyecektir .

Not: eski kodlamanın bir ürün ağacı ekleyeceği ve dizinin uzunluğuna 2 bayt eklediğinden "UTF-16"farklı bir sonuç verecektir ."UTF-16BE"


Roozbeh'in cevabı daha iyidir, çünkü diğer baytları da dikkate alır.
Lodewijk Bogaards

@finnw Kodlamanın UTF-16 değil, UTF-16BE olduğundan emin misiniz? String sınıf Javadoc'a göre ( docs.oracle.com/javase/6/docs/api/java/lang/String.html ), "Bir String UTF-16 biçiminde bir dizeyi temsil eder ...".
entpnerd

17

Göre ve Java UTF8 bayt dizileri dizeleri dönüştürmek için nasıl :

String s = "some text here";
byte[] b = s.getBytes("UTF-8");
System.out.println(b.length);

ama kodunu derlediğimde bana bir hata verir; "UTF-8" parametresi nedeniyle. boş bir parametre ilettiğimde bana x.length ile aynı uzunluğu verir. kavramı yanlış anlıyorum. yardım lütfen
Yeşil

@Green Ash, hangi Java sürümüne sahipsiniz?
Buhake Sindi

@Yeşil Ash, ne istisnası var?
Buhake Sindi

2
açık olmak gerekirse bu çıktı: test.java:11: bildirilmemiş istisna java.io.UnsupportedEncodingException; atılmalı veya atılmış bayt olduğu bildirilmelidir [] b = s.getBytes ("UTF-8"); ^ 1 hatası İşlem tamamlandı.
Yeşil

3
@Green, deneyin: s.getBytes(Charset.forName("UTF-8")).
james.garriss

10

Bir Stringörnek, bellekte belirli bir bayt ayırır. Belki de sizeof("Hello World")veri yapısı tarafından tahsis edilen bayt sayısını döndürecek bir şeye bakıyorsunuz ?

Java'da genellikle bir sizeofişleve gerek yoktur , çünkü asla bir veri yapısını saklamak için bellek ayırmayız. String.javaKaba bir tahmin için dosyaya bakabiliriz ve bazı 'int', bazı referanslar ve a char[]. Java dili özellikleri tanımlar, bir o char0 ile 65535 aralıkları, bu nedenle iki bayt belleğindeki tek kömürü tutmak için yeterlidir. Ancak bir JVM'nin bir karakteri 2 baytta saklaması gerekmez, sadece uygulamanın chartanımlanan aralığın değerlerini tutabileceğini garanti etmesi gerekir .

Yani sizeofJava'da gerçekten bir anlam ifade etmiyor. Ancak, büyük bir Dize ve bir tane chariki bayt ayırdığımızı varsayarsak , bir Stringnesnenin bellek ayak izi en azından 2 * str.length()bayt cinsindendir.


7

GetBytes () adında bir yöntem var . Akıllıca kullanın .


17
Wisely = karakter seti parametresi olmadan kullanmayın.
Thilo

Neden? Ortamımı UTF8 kodlamasıyla çalışacak şekilde yapılandırırsam bu sorun olur mu?
ziggy

1
getBytes ayrıca bayt dizisini oluşturur ve kopyalar, böylece uzun dizelerden bahsediyorsanız, bu işlem pahalı olabilir.
ticktock

@ticktock, hala etraftaysanız, evet ama alternatifi nedir? Ben burada daha büyük bir tahsis birleştirmek böylece gerekli depolama dönmek için bir kütüphane işlevi için umut var.
SensorSmith

4

Bunu dene :

Bytes.toBytes(x).length

X i daha önce bildirdiğinizi ve başlattığınızı varsayarsak


3
Bu standart Java kütüphanesinin bir parçası mı? BytesSınıfı bulamıyorum .
Kröw

0

Yakalamayı denemek için şunu kullanın:

String s = "some text here";
byte[] b = s.getBytes(StandardCharsets.UTF_8);
System.out.println(b.length);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.