StringBuilder をテキスト ファイルにダンプする最も効率的でエレガントな方法は何ですか?
できるよ:
outputStream.write(stringBuilder.toString().getBytes());
しかし、これは非常に長いファイルに対して効率的ですか?
より良い方法はありますか?
StringBuilder をテキスト ファイルにダンプする最も効率的でエレガントな方法は何ですか?
できるよ:
outputStream.write(stringBuilder.toString().getBytes());
しかし、これは非常に長いファイルに対して効率的ですか?
より良い方法はありますか?
他の人が指摘しているように、Writerを使用し、BufferedWriterを使用しますが、writer.write(stringBuilder.toString());
代わりに。だけを呼び出さないでくださいwriter.append(stringBuilder);
。
編集:しかし、それはワンライナーだったので、あなたは別の答えを受け入れたようです。しかし、その解決策には2つの問題があります。
を受け入れませんjava.nio.Charset
。悪い。常に文字セットを明示的に指定する必要があります。
それはまだあなたを苦しめていstringBuilder.toString()
ます。シンプルさが本当にあなたが求めているものである場合は、Guavaプロジェクトから次のことを試してください。
BufferedWriter を使用して書き込みを最適化する必要があります (常に OutputStream の代わりに Writer を使用して文字データを書き込みます)。文字データを書き込んでいない場合は、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 を作成して最後にすべてを書き込むのではなく、より頻繁に BufferedWriter に書き込むことをお勧めします (ユースケースによっては、 StringBuilder を完全に排除します)。書き込み中に別のスレッドがディスクから大量のデータを読み取ろうとしない限り、処理中にインクリメンタルに書き込むとメモリが節約され、限られた I/O 帯域幅を有効に活用できます。
FileUtilsを提供するApache Commons IOライブラリを使用できます。
FileUtils.writeStringToFile(file, stringBuilder.toString(), Charset.forName("UTF-8"))
文字列が巨大な場合は、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); // Create no new buffer
final CharArrayReader aCARead = new CharArrayReader(aChars); // Create no new buffer
// This may be slow but it will not create any more buffer (for bytes)
int aByte;
while((aByte = aCARead.read()) != -1)
outputStream.write(aByte);
}
お役に立てれば。
文字データの場合は、 を使用することをお勧めしますReader/Writer
。あなたの場合、を使用してくださいBufferedWriter
。可能であれば、メモリを節約するBufferedWriter
代わりに最初から使用してください。StringBuilder
非引数getBytes()
メソッドを呼び出す方法は、プラットフォームのデフォルトの文字エンコーディングを使用して文字をデコードすることに注意してください。たとえば、プラットフォームのデフォルトのエンコーディングがISO-8859-1
String データに文字セット外の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));
}
ここでのほとんどの回答のベンチマーク + 改善された実装: 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();
}