Dado InputStream reemplazar carácter y producir OutputStream

Tengo muchos archivos masivos que necesito convertir a CSV reemplazando ciertos caracteres.

Estoy buscando un enfoque confiable dado que InputStream devuelve OutputStream y reemplaza todos los caracteres c1 a c2 .

El truco aquí es leer y escribir en paralelo, no puedo guardar todo el archivo en la memoria.

¿Necesito ejecutarlo en un hilo separado si quiero leer y escribir al mismo tiempo?

Muchas gracias por tus consejos.

Para copiar datos de un flujo de entrada a un flujo de salida, usted escribe datos mientras lo lee, ya sea un byte (o carácter) o una línea a la vez.

Aquí hay un ejemplo que lee un archivo que convierte todos los caracteres ‘x’ a ‘y’.

 BufferedInputStream in = new BufferedInputStream(new FileInputStream("input.dat")); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("output.dat")); int ch; while((ch = in.read()) != -1) { if (ch == 'x') ch = 'y'; out.write(ch); } out.close(); in.close(); 

O si puede usar un Reader y procesar una línea a la vez, puede usar este enfoque:

 BufferedReader reader = new BufferedReader(new FileReader("input.dat")); PrintWriter writer = new PrintWriter( new BufferedOutputStream(new FileOutputStream("output.dat"))); String str; while ((str = reader.readLine()) != null) { str = str.replace('x', 'y'); // replace character at a time str = str.replace("abc", "ABC"); // replace string sequence writer.println(str); } writer.close(); reader.close(); 

BufferedInputStream y BufferedReader leen por adelantado y mantienen 8K de caracteres en un búfer para el rendimiento. Los archivos muy grandes se pueden procesar manteniendo solo 8K de caracteres en la memoria a la vez.

  FileWriter writer = new FileWriter("Report.csv"); BufferedReader reader = new BufferedReader(new InputStreamReader(YOURSOURCE, Charsets.UTF_8)); String line; while ((line = reader.readLine()) != null) { line.replace('c1', 'c2'); writer.append(line); writer.append('\n'); } writer.flush(); writer.close(); 

Puede encontrar una respuesta relacionada aquí: Filtrar (buscar y reemplazar) una matriz de bytes en un InputStream

Tomé la respuesta de @ aioobe en ese hilo y construí el módulo de flujo de entrada de reemplazo en Java, que puede encontrar en mi lista de GitHub: https://gist.github.com/lhr0909/e6ac2d6dd6752871eb57c4b083799947

Poniendo el código fuente aquí también:

 import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.LinkedList; import java.util.Queue; /** * Created by simon on 8/29/17. */ public class ReplacingInputStream extends FilterInputStream { private Queue inQueue, outQueue; private final byte[] search, replacement; public ReplacingInputStream(InputStream in, String search, String replacement) { super(in); this.inQueue = new LinkedList<>(); this.outQueue = new LinkedList<>(); this.search = search.getBytes(); this.replacement = replacement.getBytes(); } private boolean isMatchFound() { Iterator iterator = inQueue.iterator(); for (byte b : search) { if (!iterator.hasNext() || b != iterator.next()) { return false; } } return true; } private void readAhead() throws IOException { // Work up some look-ahead. while (inQueue.size() < search.length) { int next = super.read(); inQueue.offer(next); if (next == -1) { break; } } } @Override public int read() throws IOException { // Next byte already determined. while (outQueue.isEmpty()) { readAhead(); if (isMatchFound()) { for (byte a : search) { inQueue.remove(); } for (byte b : replacement) { outQueue.offer((int) b); } } else { outQueue.add(inQueue.remove()); } } return outQueue.remove(); } @Override public int read(byte b[]) throws IOException { return read(b, 0, b.length); } // copied straight from InputStream inplementation, just needed to to use `read()` from this class @Override public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int c = read(); if (c == -1) { return -1; } b[off] = (byte)c; int i = 1; try { for (; i < len ; i++) { c = read(); if (c == -1) { break; } b[off + i] = (byte)c; } } catch (IOException ee) { } return i; } }