你可以这样做:
outputStream.write(stringBuilder.toString().getBytes());
但对于非常长的文件来说,这是否高效?
有更好的方法吗?
outputStream.write(stringBuilder.toString().getBytes());
但对于非常长的文件来说,这是否高效?
有更好的方法吗?
writer.write(stringBuilder.toString());
,而是只需调用writer.append(stringBuilder);
。它不接受java.nio.Charset
。不好。您应该始终明确指定Charset。
它仍然让您遭受stringBuilder.toString()
。如果您真的想要简单性,请尝试来自Guava项目的以下内容:
您应该使用BufferedWriter来优化写入操作(始终使用Writer而不是OutputStream来写入字符数据)。如果您不是在写字符数据,则应使用BufferedOutputStream。
File file = new File("path/to/file.txt");
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(file));
writer.append(stringBuilder);
} 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.append(stringBuilder);
}
由于你最终要写入文件,一个更好的方法是在处理过程中更频繁地向BufferedWriter中写入,而不是在内存中创建一个巨大的StringBuilder并在最后一次性写入所有内容(根据你的使用情况,甚至可以完全消除 StringBuilder)。在处理期间逐步写入将节省内存,并更好地利用有限的I/O带宽,除非另一个线程正在尝试从磁盘读取大量数据时你正在写入。
你可以使用Apache Commons IO库,它给你FileUtils:
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); <i>// Create no new buffer</i>
final CharArrayReader aCARead = new CharArrayReader(aChars); <i>// Create no new buffer</i>
<i>// This may be slow but it will not create any more buffer (for bytes)</i>
int aByte;
while((aByte = aCARead.read()) != -1)
outputStream.write(aByte);
}
希望这能帮到你。
write(byte)
。Java现在是开源的,所以你可以看到代码,我记得append和write的实现总是相关的。 - NawaMan对于字符数据,最好使用 Reader/Writer
,在您的情况下,请使用 BufferedWriter
。如果可能,一开始就使用 BufferedWriter
而不是 StringBuilder
以节省内存。
请注意,您调用非参数 getBytes()
方法的方式将使用平台默认字符编码来解码字符。如果平台默认编码为例如 ISO-8859-1
而您的字符串数据包含 ISO-8859-1
字符集之外的字符,则可能失败。最好使用 getBytes(charset)
,其中您可以自己指定字符集,例如 UTF-8
。
stringBuilder.toString()
。而您的答案并没有帮助到这个问题。 - Eric Duminil这里提供大多数答案的基准测试和改进实现: 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();
}
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);
}
}
}
如果字符串本身很长,那么一定要避免使用toString(),因为它会制作另一个字符串副本。最高效的写入流方法应该像这样:
OutputStreamWriter writer = new OutputStreamWriter(
new BufferedOutputStream(outputStream), "utf-8");
for (int i = 0; i < sb.length(); i++) {
writer.write(sb.charAt(i));
}