Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

РЕДАКТИРОВАТЬ:Но я вижу, что вы приняли другой ответ, потому что он был однострочным.Но у этого решения есть две проблемы:

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

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

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

Другие советы

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

Ну, если строка огромна, 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.writeStringToFile(file, stringBuilder.toString(), Charset.forName("UTF-8"))

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

Обратите внимание, что ваш способ вызова не-arg getBytes() метод будет использовать кодировку символов платформы по умолчанию для декодирования символов.Это может привести к сбою, если, например, кодировка платформы по умолчанию ISO-8859-1 в то время как ваши строковые данные содержат символы вне 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));
}

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

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

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

На основе 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);
        }
    }
}

Тесты для большинства ответов здесь + улучшенная реализация: 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