2016-02-05 32 views
6

Sto provando a scrivere un'API per sostituire tutte le righe contenenti una determinata sottostringa con una stringa diversa in un file di testo.Sostituire il testo in un file utilizzando Stream- Java 8

Sto utilizzando Java 8 stream per filtrare le linee che contengono il modello specificato. Sto avendo problemi con la parte di scrittura del file.

Files.lines(targetFile).filter(line -> line.contains(plainTextPattern)).parallel() 
     .map(line-> line.replaceAll(plainTextPattern, replaceWith)).parallel(); 

Sopra codice legge il file di line-saggio, filtri le linee che corrispondono al modello e sostituisce con la stringa di dare e dà indietro un flusso di stringhe che ha solo le linee sostituite.

Abbiamo bisogno di scrivere queste righe sul file. Dal momento che si perde nel flusso volta che la pipeline finisce, ho apposto il seguente alla pipeline:

.forEach(line -> { 
try { 
      Files.write(targetFile, line.toString().getBytes()); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 

Speravo che sarebbe scrivere nel file solo il modificato (dal momento che è in cantiere) di linea e tenere l'altra linee intoccate

Ma sembra troncare il file per ogni riga nel file e mantenere solo l'ultima riga elaborata ed eliminare tutte le righe che non erano state soddisfatte nella pipeline.

C'è qualcosa che mi manca nella gestione dei file utilizzando gli stream?

+3

Da [documentazione] (https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#write-java. nio.file.Path-byte: A-java.nio.file.OpenOption ...-): "Per impostazione predefinita, il metodo crea un nuovo file o sovrascrive un file esistente.". Per la soluzione leggere il resto della documentazione. Ricorda anche che non puoi semplicemente modificare il vecchio file di testo. È necessario crearne uno nuovo con le modifiche appropriate e quindi sostituirlo. – Pshemo

+0

Grazie! Ho pensato di usare StandardOpenOption.APPEND. Ma ho sentito che non ha senso perché non voglio che venga aggiunto alla fine del file. Deve sostituire la linea esistente. Mi sto perdendo qualcosa di nuovo? – AshwiniR

+0

Ho appena provato append. Aggiunge tutti i contenuti (comprese le righe che non corrispondono) alla fine del file. Almeno questo mi dice che le linee ineguagliate non sono completamente perse. Ma ho bisogno di capire come riscrivere il file con il nuovo contenuto. – AshwiniR

risposta

16

L'utilizzo di filter elimina tutto ciò che non corrisponde al filtro dal flusso. (Inoltre, per quello che vale, a) hai solo bisogno di usare parallel una volta, b) parallel non è così efficace su flussi provenienti da fonti I/O, c) non è quasi mai una buona idea usare parallel finché non hai in realtà l'ho provato non parallelo e l'ho trovato troppo lento.)

Detto questo: non è necessario filtrare le linee che corrispondono al modello se si sta per fare un replaceAll. Il codice dovrebbe essere simile a questa:

try (Stream<String> lines = Files.lines(targetFile)) { 
    List<String> replaced = lines 
     .map(line-> line.replaceAll(plainTextPattern, replaceWith)) 
     .collect(Collectors.toList()); 
    Files.write(targetFile, replaced); 
} 
+0

Tutti i commenti sono stati molto istruttivi! Grazie a tutti! – AshwiniR

6

Mi spiace dirvi che non è così che funzionano i file. Se vuoi scrivere nel mezzo di un file, devi avere RandomAccess; Ottieni uno FilePointer, cerca, quel puntatore e scrivi da lì.

Questo vale se la dimensione dei dati che si desidera scrivere è uguale alla dimensione dei dati che si desidera sovrascrivere. Se questo non è il caso, devi copiare la coda del file in un buffer temporaneo e aggiungerla al testo che desideri scrivere.

E btw, parallelStreams su IO attività associate è spesso una cattiva idea.