将StringBuilder转储到文本文件的最有效/优雅的方法是什么?
你可以这样做:
outputStream.write(stringBuilder.toString().getBytes());
但这对于一个很长的文件有效吗?
有更好的方法吗?
答案 0 :(得分:39)
正如其他人所指出的,使用Writer并使用BufferedWriter,但不要只调用writer.write(stringBuilder.toString());
而只是writer.append(stringBuilder);
。
编辑:但是,我看到你接受了一个不同的答案,因为它是一个单行。但该解决方案有两个问题:
它不接受java.nio.Charset
。坏。您应该始终明确指定Charset。
它仍然让你受到stringBuilder.toString()
的影响。如果简单就是您所追求的,请从Guava项目中尝试以下内容:
答案 1 :(得分:23)
您应该使用BufferedWriter来优化写入(始终使用Writer而不是OutputStream来写入字符数据)。如果您没有编写字符数据,则可以使用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());
}
由于你最终写入文件,更好的方法是更频繁地写入BufferedWriter而不是在内存中创建一个巨大的StringBuilder并在最后编写所有内容(取决于你的用例,你可能会甚至可以完全消除StringBuilder)。在处理过程中逐步写入将节省内存并更好地利用有限的I / O带宽,除非另一个线程在您编写的同时尝试从磁盘读取大量数据。
答案 2 :(得分:15)
好吧,如果字符串很大,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);
}
希望这有帮助。
答案 3 :(得分:14)
您可以使用Apache Commons IO库,它会为您提供FileUtils:
FileUtils.writeStringToFile(file, stringBuilder.toString(), Charset.forName("UTF-8"))
答案 4 :(得分:3)
对于角色数据,最好使用Reader/Writer
。在您的情况下,请使用BufferedWriter
。如果可能,请从头开始使用BufferedWriter
而不是StringBuilder
来节省内存。
请注意,调用非arg getBytes()
方法的方法是使用平台默认字符编码来解码字符。如果平台默认编码是例如ISO-8859-1
,而您的String数据包含ISO-8859-1
字符集之外的字符,则可能会失败。更好地使用getBytes(charset)
您可以自己指定字符集,例如UTF-8
。
答案 5 :(得分:1)
如果字符串本身很长,你绝对应该避免使用toString(),它会生成字符串的另一个副本。写入流的最有效方法应该是这样的,
OutputStreamWriter writer = new OutputStreamWriter(
new BufferedOutputStream(outputStream), "utf-8");
for (int i = 0; i < sb.length(); i++) {
writer.write(sb.charAt(i));
}
答案 6 :(得分:1)
从Java 8开始,您只需要这样做:
Files.write(Paths.get("/path/to/file/file_name.extension"), stringBuilder.toString().getBytes());
您不需要任何第三方库即可。
答案 7 :(得分:0)
基于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);
}
}
}
答案 8 :(得分:0)
此处大多数答案的基准+改进实施: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();
}