Java StringBuilderをファイルにダンプします
-
16-09-2019 - |
質問
StringBuilderをテキストファイルにダンプする最も効率的でエレガントな方法は何ですか?
できるよ:
outputStream.write(stringBuilder.toString().getBytes());
しかし、これは非常に長いファイルに効率的ですか?
より良い方法はありますか?
解決
他の人が指摘したように、ライターを使用して、bufferedwriterを使用しますが、電話しないでください writer.write(stringBuilder.toString());
代わりにただ writer.append(stringBuilder);
.
編集:しかし、それはワンライナーだったので、あなたは別の答えを受け入れたことがわかります。しかし、そのソリューションには2つの問題があります。
それは受け入れません
java.nio.Charset
. 。悪い。常にcharsetを明示的に指定する必要があります。それはまだあなたを苦しめています
stringBuilder.toString()
. 。シンプルさが本当にあなたが求めているものである場合は、以下を試してみてください グアバ 事業:
他のヒント
bufferedwriterを使用して、書き込みを最適化する必要があります(出力ストリームの代わりにライターを使用して常に文字データを書き込みます)。文字データを書いていない場合は、BufferedOutputStreamを使用します。
File file = new File("path/to/file.txt");
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(file));
writer.write(stringBuilder.toString());
} finally {
if (writer != null) writer.close();
}
または、リソースと一緒にtry-with-resources(Java 7以降)を使用する
File file = new File("path/to/file.txt");
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
writer.write(stringBuilder.toString());
}
最終的にファイルに書いているので、より良いアプローチは、巨大なStringBuilder InMemoryを作成し、最後にすべてを書く代わりに、より頻繁にBufferedWriterに手紙を書くことです(ユースケースに応じて、あなたもできるかもしれませんStringBuilderを完全に排除するため)。処理中に段階的に書くことはメモリを保存し、他のスレッドがあなたが書いていると同時にディスクから多くのデータを読み取ろうとしない限り、限られたI/O帯域幅をよりよく利用します。
まあ、文字列が巨大な場合、 toString().getBytes()
重複したバイト(2〜3回)が作成されます。文字列のサイズ。
これを避けるために、文字列の塊を抽出し、別々の部分に書き込むことができます。
これがどのように見えるかです:
final StringBuilder aSB = ...;
final int aLength = aSB.length();
final int aChunk = 1024;
final char[] aChars = new char[aChunk];
for(int aPosStart = 0; aPosStart < aLength; aPosStart += aChunk) {
final int aPosEnd = Math.min(aPosStart + aChunk, aLength);
aSB.getChars(aPosStart, aPosEnd, aChars, 0); //新しいバッファーを作成しません
final CharArrayReader aCARead = new CharArrayReader(aChars); //新しいバッファーを作成しません
//これは遅いかもしれませんが、それ以上のバッファを作成しません(バイト用)
int aByte;
while((aByte = aCARead.read()) != -1)
outputStream.write(aByte);
}
お役に立てれば。
使用できます Apache Commons IO ライブラリ、それはあなたに与えます fileutils:
FileUtils.writeStringToFile(file, stringBuilder.toString(), Charset.forName("UTF-8"))
キャラクターデータのためにより良い使用 Reader/Writer
. 。あなたの場合、aを使用します BufferedWriter
. 。可能であれば、使用してください BufferedWriter
代わりに最初から StringBuilder
メモリを保存するため。
非ARGを呼び出す方法に注意してください getBytes()
メソッドは、プラットフォームのデフォルト文字エンコードを使用して文字をデコードします。プラットフォームのデフォルトエンコードがたとえばある場合、これは失敗する可能性があります ISO-8859-1
文字列データには外側の文字が含まれています ISO-8859-1
文字コード。より良い使用 getBytes(charset)
どこであなた自身が自分で憲章を指定できるか、 UTF-8
.
文字列自体が長い場合は、間違いなくtoString()を避ける必要があります。これにより、文字列の別のコピーが作成されます。ストリームに書き込む最も効率的な方法は、このようなものでなければなりません、
OutputStreamWriter writer = new OutputStreamWriter(
new BufferedOutputStream(outputStream), "utf-8");
for (int i = 0; i < sb.length(); i++) {
writer.write(sb.charAt(i));
}
Java 8以来、これを行う必要があります。
Files.write(Paths.get("/path/to/file/file_name.extension"), stringBuilder.toString().getBytes());
それを行うためにサードパーティの図書館は必要ありません。
に基づく https://stackoverflow.com/a/1677317/980442
使用するこの関数を作成します OutputStreamWriter
そしてその write()
, 、これはメモリも最適化されており、使用するよりも優れています StringBuilder.toString()
.
public static void stringBuilderToOutputStream(
StringBuilder sb, OutputStream out, String charsetName, int buffer)
throws IOException {
char[] chars = new char[buffer];
try (OutputStreamWriter writer = new OutputStreamWriter(out, charsetName)) {
for (int aPosStart = 0; aPosStart < sb.length(); aPosStart += buffer) {
buffer = Math.min(buffer, sb.length() - aPosStart);
sb.getChars(aPosStart, aPosStart + buffer, chars, 0);
writer.write(chars, 0, buffer);
}
}
}
ここでのほとんどの回答のベンチマーク +実装の改善: https://www.genuitec.com/dump-a-stringbuilder-to-file/
最終的な実装は、のラインに沿っています
try {
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(file, append), charset), BUFFER_SIZE);
try {
final int length = sb.length();
final char[] chars = new char[BUFFER_SIZE];
int idxEnd;
for ( int idxStart=0; idxStart<length; idxStart=idxEnd ) {
idxEnd = Math.min(idxStart + BUFFER_SIZE, length);
sb.getChars(idxStart, idxEnd, chars, 0);
bw.write(chars, 0, idxEnd - idxStart);
}
bw.flush();
} finally {
bw.close();
}
} catch ( IOException ex ) {
ex.printStackTrace();
}