Javaの文字列のバイト


179

JavaでStringがある場合x、その文字列のバイト数を計算するにはどうすればよいですか?


15
文字列を使用してHTTP応答の本文を表し、サイズを使用して "Content-Length"ヘッダーを設定することができます。これは、文字ではなくオクテット/バイトで指定されます。w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
iX3

4
データベース列には、バイト単位の長さ制限がある場合があります(OracleのVARCHAR2(4000 BYTE)など)。文字列が適合するかどうかを知るために、希望するエンコーディングで文字列のバイト数を知りたい場合があります。
Somu

@ iX3私がやろうとしたのとまったく同じです。
MC皇帝

1
この質問には、目的に応じて2つの解釈があると思います。1つは「文字列が使用するメモリの量」です。これに対する答えは、以下の@roozbehによって提供されます(多分、圧縮されたOOPSのようなVMの微妙なモジュロ)。もう1つは、「文字列をバイトに変換する場合、そのバイト配列はどのくらいのメモリを使用するのか」ということです。これは、アンジェイ・ドイルが回答する質問です。違いは大きくなる可能性があります。UTF8の「Hello World」は11バイトですが、(@ roozbehごとに)文字列は50バイトです(私の計算が正しい場合)。
L.ブラン

11バイトには、それらを保持するbyte []オブジェクトのオーバーヘッドが含まれていないため、比較は多少誤解を招く可能性があることを付け加えておきます。
L.ブラン、

回答:


289

文字列は、文字(コードポイント)のリストです。文字列を表すために使用されるバイト数は、文字列をバイトに変換するために使用するエンコーディングに完全に依存します

つまり、文字列をバイト配列に変換し、次のようにそのサイズを確認できます。

// 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"

ご覧のとおり、単純な「ASCII」文字列でも、使用するエンコーディングに応じて、その表現のバイト数が異なる場合があります。の引数として、目的に合った文字セットを使用してくださいgetBytes()。また、UTF-8がすべての文字を1バイトとして表すと仮定するという落とし穴に陥らないでください。

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 "????")

(文字セット引数を指定しない場合、プラットフォームのデフォルトの文字セットが使用されることに注意してください。これは一部のコンテキストでは役立つかもしれませんが、一般にデフォルトに依存することは避け、エンコード/デコードが必要です。)


1
もう一度getBytes()を使用すると、x.lengthと同じ長さが得られます。確信が持てないため間違っています
Green

4
@Green Ashバイト配列の長さ(getBytes())とx.lengthは等しくてもかまいませんが、そうであるとは限りません。すべての文字がそれぞれ1バイトで表されている場合は等しくなります。これは、ISO-8859-1のように、1文字(またはそれ以下)あたり1バイトを使用する文字エンコーディングに常に当てはまります。UTF-8は1バイトまたは2バイトを使用するため、文字列内の正確な文字に依存します。次に、文字ごとに常に2バイトを使用する文字エンコードがあります。
Kris

私はあなたの答えが好きです:)だから、彼らはどういうわけか同じかもしれませんが、いつも正しいとは限りませんか?それで私にエラーを引き起こしているので、パラメータなしでメソッドを使用しても大丈夫ですか?
Green

@Greenポイントは、バイト数は常に文字数と同じではないということです。バイト数は、使用される文字エンコーディングによって異なります。使用する文字エンコーディングを把握し、それを考慮に入れる必要があります。どのようなエラーが発生していますか?あなただけを使用する場合getBytes()、それはあなたのシステムのデフォルトの文字エンコーディングを使用します。
Jesper

1
@KorayTugayはい、多かれ少なかれ。ただし、原因と結果の順序について議論することもできます。charは2バイト幅として定義されたプリミティブデータ型であるため、charは常に2バイトであると述べたいと思います。(そして、UTF-16表現は、主にこれの結果であり、逆の方法ではなかった。)
Andrzej Doyle

63

64ビット参照で実行している場合:

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

言い換えると:

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

圧縮されたOOP(-XX:+ UseCompressedOops)を備えた32ビットVMまたは64ビットVMでは、参照は4バイトです。したがって、合計は次のようになります。

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

これは、文字列オブジェクトへの参照を考慮していません。


6
質問は、Stringオブジェクト用にメモリに割り当てられたバイト数に関するものだと思っていました。他の人が指摘したように、質問が文字列のシリアル化に必要なバイト数に関するものである場合、それは使用されるエンコーディングに依存します。
roozbeh 2013

2
あなたの答えの出典?ありがとう
mavis

1
注:sizeof8の倍数でなければなりません
ディーター・

19

考え抜かれた答え(結果をどのように処理するかによっては、必ずしも最も役立つとは限りません)は次のとおりです。

string.length() * 2

Java文字列は物理的にUTF-16BEエンコードに格納され、コード単位あたり2バイトを使用しString.length()、UTF-16コード単位で長さを測定するため、これは次と同等です。

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

これにより、内部char配列のサイズ(バイト単位)がわかります

注:"UTF-16"異なる結果が得られます"UTF-16BE"以前のエンコーディングが挿入されますよう BOMされ、配列の長さに2バイトが追加ます。


Roozbehの答えは、他のバイトも考慮に入れるため、より優れています。
Lodewijk Bogaards 2018年

@finnwエンコードがUTF-16ではなくUTF-16BEであることを確認しますか?StringクラスのJavadoc(docs.oracle.com/javase/6/docs/api/java/lang/String.html)によると、「文字列はUTF-16形式の文字列を表します...」。
entpnerd

17

Javaで文字列をUTF8バイト配列との間で変換する方法によると:

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

しかし、コードをコンパイルするとすみません、エラーが発生します。パラメータ「UTF-8」のため。空のパラメータを渡すと、x.lengthと同じ長さが得られます。私はその概念を誤解しています。助けてください
Green

@Green Ash、Javaのどのバージョンをお持ちですか?
ブハケシンディ

@グリーンアッシュ、どんな例外が出ていますか?
ブハケシンディ

2
明確にするために、これは出力です:test.java:11:unreported exception java.io.UnsupportedEncodingException; スローされるようにキャッチまたは宣言する必要があるbyte [] b = s.getBytes( "UTF-8"); ^ 1エラープロセスが完了しました。
緑の

3
@Green、試してみてくださいs.getBytes(Charset.forName("UTF-8"))
james.garriss 2014年

10

Stringインスタンスは、メモリ内のバイトの一定量を割り当てます。多分あなたはsizeof("Hello World")データ構造自体によって割り当てられたバイト数を返すようなものを見ていますか?

Javaではsizeof、データ構造を格納するためにメモリを割り当てることはないため、通常、関数は必要ありません。String.java大まかな見積もりの​​ためにファイルを見ることができ、いくつかの「int」、いくつかの参照、およびが表示されchar[]ます。Java言語仕様のことを定義し、char2つのバイトがメモリ内の単一の文字を保持するのに十分であるように、0から65535の範囲です。しかし、JVMは1バイトを2バイトで格納する必要はありません。それは、の実装がchar定義された範囲の値を保持できることを保証するだけです。

したがってsizeof、Javaではまったく意味がありません。ただし、大きな文字列があり、1 charつが2バイトを割り当てると仮定すると、Stringオブジェクトのメモリフットプリントは少なくとも2 * str.length()バイト単位になります。


7

getBytes()というメソッドがあります。賢く使ってください。


17
Wisely =文字セットパラメータのないものを使用しないでください。
Thilo

どうして?UTF8エンコーディングで実行するように環境を構成した場合、これは問題ですか?
ziggy 14

1
getBytesはバイトの配列も作成およびコピーするため、長い文字列を話している場合、この操作は高価になる可能性があります。
ticktock 2015年

@ticktock、あなたがまだそこにいるのであれば、はい、代わりは何ですか?必要なストレージを返すためにライブラリー関数がそれをより大きな割り当てに組み合わせることができることを期待してここに来ました。
SensorSmith

4

これを試して :

Bytes.toBytes(x).length

以前にxを宣言して初期化したと仮定します


3
これは標準Javaライブラリの一部ですか?Bytesクラスが見つかりません。
Kröw

0

キャッチを回避するには、以下を使用します。

String s = "some text here";
byte[] b = s.getBytes(StandardCharsets.UTF_8);
System.out.println(b.length);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.