将StringBuilder转移到文本文件的最有效/优雅的方法是什么?

你可以做:

outputStream.write(stringBuilder.toString().getBytes());

但是,这对于很长的文件有效吗?

有没有更好的办法?

有帮助吗?

解决方案

正如他人指出的那样,使用作家并使用缓冲作者,但请勿致电 writer.write(stringBuilder.toString()); 而是 writer.append(stringBuilder);.

编辑:但是,我看到您接受了不同的答案,因为它是单线。但是该解决方案有两个问题:

  1. 它不接受 java.nio.Charset. 。坏的。您应始终明确指定一个字符集。

  2. 它仍然让你受苦 stringBuilder.toString(). 。如果简单性确实是您所追求的,请尝试 瓜瓦 项目:

files.write(StringBuilder,File,charsets.utf_8)

其他提示

您应该使用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());
}

由于您最终将其写入文件,因此更好的方法是更频繁地写给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. 。在您的情况下,请使用 BufferedWriter. 。如果可能,请使用 BufferedWriter 从一开始而不是 StringBuilder 保存内存。

请注意,您致电非ARG的方式 getBytes() 方法将使用平台默认字符编码来解码字符。如果平台默认编码为例如,这可能会失败 ISO-8859-1 当您的字符串数据包含字符 ISO-8859-1 charset。更好地使用 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

我创建了使用的功能 OutputStreamWriterwrite(), ,这也是对内存的优化,不仅要使用 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();
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top