Domanda

Qual è il / modo elegante più efficace per scaricare uno StringBuilder ad un file di testo?

Si può fare:

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

Ma questo è efficace per un periodo molto lungo di file?

C'è un modo migliore?

È stato utile?

Soluzione

Come sottolineato da altri, utilizzare uno scrittore, e utilizzare un BufferedWriter, ma poi non chiamare writer.write(stringBuilder.toString()); invece solo writer.append(stringBuilder);.

EDIT: Ma, vedo che avete accettato una risposta diversa, perché era una battuta. Ma questa soluzione ha due problemi:

  1. non accetta un java.nio.Charset. MALE. Si dovrebbe sempre specificare esplicitamente un set di caratteri.

  2. sta ancora facendo si soffre un stringBuilder.toString(). Se la semplicità è davvero quello che stai dopo, provare quanto segue dal href="http://guava-libraries.googlecode.com" rel="noreferrer"> Guava progetto

Files.write (StringBuilder, lima, Charsets.UTF_8)

Altri suggerimenti

È necessario utilizzare un BufferedWriter per ottimizzare le operazioni di scrittura (sempre scrivere i dati di caratteri utilizzando un Writer invece di un OutputStream). Se non si stesse scrivendo i dati di carattere, si può usare un 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();
}

o, utilizzando try-with-risorse (Java 7 e fino)

File file = new File("path/to/file.txt");
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
    writer.write(stringBuilder.toString());
}

Visto che siete in ultima analisi, la scrittura su un file, un approccio migliore sarebbe quello di scrivere al BufferedWriter più spesso invece di creare un enorme StringBuilder in-memory e scrivere tutto ciò che alla fine (a seconda del caso d'uso, si potrebbe anche essere in grado di eliminare lo StringBuilder interamente). Scrivendo in modo incrementale durante l'elaborazione farà risparmiare memoria e si avvarrà meglio la larghezza di banda di I / O limitato, a meno che un altro thread sta cercando di leggere un sacco di dati dal disco allo stesso tempo che si sta scrivendo.

Bene, se la stringa è enorme, toString().getBytes() creerà byte duplicati (2 o 3 volte). La dimensione della stringa.

Per evitare questo, è possibile estrarre pezzo di corda e scriverlo in parti separate.

Ecco come possono sguardi:

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);
}

Spero che questo aiuti.

Si potrebbe utilizzare Apache Commons IO la biblioteca, che vi dà fileutils :

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

Per i dati di carattere migliore utilizzo Reader/Writer. Nel tuo caso, utilizzare un BufferedWriter. Se possibile, utilizzare BufferedWriter dall'inizio sul posto di StringBuilder per risparmiare memoria.

Si noti che il vostro modo di chiamare il metodo getBytes() non-arg userebbe la codifica caratteri predefinita piattaforma per decodificare i caratteri. Questo può fallire se la codifica piattaforma predefinita è per esempio ISO-8859-1 mentre i dati String contiene i caratteri al di fuori del set di caratteri ISO-8859-1. Meglio utilizzare il getBytes(charset) dove è possibile specificare il set di caratteri da soli, come ad esempio UTF-8.

Se la stringa stessa è lunga, è sicuramente dovrebbe evitare di toString (), che fa un altro copia della stringa. Il modo più efficace di scrivere per lo streaming dovrebbe essere qualcosa di simile,

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

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

Dal momento che Java 8 avete solo bisogno di fare questo:

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

Non è necessario alcun librerie di terze parti per farlo.

In base a https://stackoverflow.com/a/1677317/980442

creo questa funzione che utilizzano OutputStreamWriter e la write(), questa è la memoria ottimizzata troppo, meglio di quanto basta usare 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);
        }
    }
}

parametri di riferimento per la maggior parte delle risposte qui + migliore attuazione: https: // www .genuitec.com / discarica-a-StringBuilder-to-file /

L'implementazione finale è lungo le linee di

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();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top