Подтвердить что ты не робот

Сбрасывание Java StringBuilder в файл

Каков наиболее эффективный/элегантный способ сброса StringBuilder в текстовый файл?

Вы можете сделать:

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

Но эффективен ли он для очень длинного файла?

Есть ли лучший способ?

4b9b3361

Ответ 1

Как указывалось другими, используйте Writer и используйте BufferedWriter, но затем не вызывайте writer.write(stringBuilder.toString());, а просто writer.append(stringBuilder);.

EDIT: Но я вижу, что вы приняли другой ответ, потому что это был один лайнер. Но это решение имеет две проблемы:

  • он не принимает java.nio.Charset. ПЛОХО. Вы всегда должны явно указывать Charset.

  • он все еще заставляет вас страдать stringBuilder.toString(). Если простота в том, что вам нужно, попробуйте следующее из проекта Guava:

Files.write(stringBuilder, файл, Charsets.UTF_8)

Ответ 2

Вы должны использовать 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). Запись поэтапно во время обработки будет экономить память и будет лучше использовать вашу ограниченную пропускную способность ввода-вывода, если другой поток не пытается прочитать много данных с диска одновременно с тем, что вы пишете.

Ответ 3

Ну, если строка огромна, 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);
}

Надеюсь, что это поможет.

Ответ 4

Вы можете использовать библиотеку Apache Commons IO, которая дает вам FileUtils:

FileUtils.writeStringToFile(file, stringBuilder.toString(), Charset.forName("UTF-8"))

Ответ 5

Для символьных данных лучше использовать Reader/Writer. В вашем случае используйте BufferedWriter. Если возможно, используйте BufferedWriter с начала вместо StringBuilder для сохранения памяти.

Обратите внимание, что ваш способ вызова метода non-arg getBytes() будет использовать кодировку символов по умолчанию для декодирования символов. Это может привести к сбою, если кодировка по умолчанию платформы, например, ISO-8859-1, в то время как ваши данные String содержат символы вне ISO-8859-1 charset. Лучше используйте getBytes(charset), где вы можете указать кодировку самостоятельно, например UTF-8.

Ответ 6

Если сама строка длинна, вам определенно следует избегать toString(), которая создает другую копию строки. Самый эффективный способ записи в поток должен быть примерно таким,

OutputStreamWriter writer = new OutputStreamWriter(
        new BufferedOutputStream(outputStream), "utf-8");

for (int i = 0; i < sb.length(); i++) {
    writer.write(sb.charAt(i));
}

Ответ 7

Начиная с Java 8 вам нужно только сделать это:

Files.write(Paths.get("/path/to/file/file_name.extension"), stringbuilder.toString().getBytes());

Вам не нужны сторонние библиотеки для этого.

Ответ 8

На основе fooobar.com/questions/178031/...

Я создаю эту функцию, которая использует 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);
        }
    }
}

Ответ 9

Контрольные показатели для большинства ответов здесь + улучшенная реализация: 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();
}