2016-12-23 2 views
1

J'ai beaucoup de fichiers volumineux dont j'ai besoin de convertir au format CSV en remplaçant certains caractères.Étant donné que InputStream remplace le caractère et produit OutputStream

Je recherche une approche fiable étant donné que InputStream renvoie OutputStream et remplace tous les caractères c1 par c2. Astuce ici est de lire et d'écrire en parallèle, je ne peux pas adapter le fichier entier en mémoire. Dois-je l'exécuter dans un thread séparé si je veux lire et écrire en même temps?

Merci beaucoup pour vos conseils.

+1

Un InputStream vous donne octets. Si vous connaissez votre encodage, vous pouvez utiliser un lecteur pour obtenir des caractères. Vous pouvez ensuite regarder chaque personnage au passage et le remplacer au besoin. –

+0

Oui. Je vous remercie. Je pensais s'il y a déjà une solution de pré-construction disponible? –

+0

Peut-être. Qu'avez-vous cherché jusqu'à présent? –

Répondre

1

Pour copier des données d'un flux d'entrée dans un flux de sortie, vous écrivez des données pendant que vous le lisez, soit un octet (ou un caractère), soit une ligne à la fois.

Voici un exemple qui lit dans un fichier convertissant tous les caractères 'x' en '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(); 

Ou si peut utiliser un lecteur et traiter une ligne à la fois peut alors utiliser cette aproche:

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 et BufferedReader lire l'avant et garder 8K de caractères dans un tampon pour la performance. Les fichiers très volumineux peuvent être traités en ne conservant que 8 Ko de caractères en mémoire à la fois.

+0

Ok, super, merci! Mais comment lire et écrire en parallèle? Je ne peux pas tenir tout ce fichier en mémoire. –

+0

Si le traitement de fichier un octet à la fois ou une ligne à la fois, Java ne mettra pas le fichier entier en mémoire. BufferedInputStream et BufferedReader ci-dessus gardent un petit cache en mémoire pendant qu'il lit donc seulement 8K du fichier est stocké pendant la lecture. Vous n'avez pas besoin de paralléliser l'approche sauf si le fichier a plusieurs terraoctets en taille et que vous voulez diviser le fichier en morceaux. – JasonM1

+0

Vous pouvez créer une classe de travaux de lecture/écriture pour gérer un fichier particulier et créer n threads dans lesquels chaque thread traite un fichier à la fois et répète jusqu'à ce qu'il soit terminé. – JasonM1

1
  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(); 
0

Vous pouvez trouver réponse concernant ici: Filter (search and replace) array of bytes in an InputStream

Je pris la réponse de @ aioobe dans ce fil, et construit le module de flux d'entrée remplaçant en Java, que vous pouvez le trouver dans mon essentiel GitHub: https://gist.github.com/lhr0909/e6ac2d6dd6752871eb57c4b083799947

Mettre le code source ici aussi:

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