web-dev-qa-db-fra.com

Comment rechercher rapidement un fichier volumineux pour une chaîne en Java?

J'essaie de rechercher un fichier texte volumineux (400 Mo) à l'aide d'une des chaînes suivantes:

File file = new File("fileName.txt");
try {
    int count = 0;
    Scanner scanner = new Scanner(file);
    while(scanner.hasNextLine()) {
        if(scanner.nextLine().contains("particularString")) {
            count++;
            System.out.println("Number of instances of String: " + count);
        }
    }
} catch (FileNotFoundException e){
    System.out.println(e);
}

Cela fonctionne très bien pour les petits fichiers, mais pour ce fichier en particulier et les autres gros, cela prend beaucoup trop de temps (> 10 minutes).

Quel serait le moyen le plus rapide et le plus efficace de procéder?

J'ai maintenant changé à ce qui suit et il se termine en quelques secondes -

try {
        int count = 0;
        FileReader fileIn = new FileReader(file);
        BufferedReader reader = new BufferedReader(fileIn);
        String line;
        while((line = reader.readLine()) != null) {
            if((line.contains("particularString"))) {
                count++;
                System.out.println("Number of instances of String " + count);
            }
        }
    }catch (IOException e){
        System.out.println(e);
    }
8
Chief DMG

Premier chiffre sur le temps qu'il vous faut pour lire le contenu du fichier dans son intégralité par rapport au temps qu'il faut pour les analyser.

si vos résultats sont dominés par le temps de lecture (et en supposant que vous les lisiez correctement, donc les canaux ou au moins les lecteurs mis en mémoire tampon), il n'y a pas grand chose à faire.

si c’est le temps de balayage qui prédomine, vous pouvez lire toutes les lignes, puis expédier de petits lots de lignes à rechercher dans une file d’attente de travail, où vous pouvez avoir plusieurs threads qui ramassent des lots de lignes et les recherchent.

chiffres approximatifs

  • en supposant que la vitesse de lecture du disque dur est de 50 Mo/s (et que, selon les normes modernes, elle est lente), vous devriez pouvoir lire le fichier entier en mémoire en moins de 10 secondes.
  • en regardant les points de repère de la vitesse de hachage MD5 (exemple ici ), nous voyons que le taux de hachage peut être au moins aussi rapide (souvent plus rapide) que la vitesse de lecture du disque. de plus, la recherche de chaîne est plus rapide, plus simple et se parallélise mieux que le hachage.

Étant donné ces 2 estimations, je pense qu’une mise en œuvre appropriée peut facilement vous faire courir un temps d’exécution de l’ordre de 10 secondes (si vous commencez à lancer des travaux de recherche au fur et à mesure que vous lisez des lots de ligne), et que le temps de lecture de votre disque le domine largement.

6
radai

Le scanner n'est tout simplement pas utile dans ce cas. Sous le capot, il effectue toutes sortes d’analyses, vérifications, mises en cache, etc. Si votre cas est simplement "itérer sur toutes les lignes d'un fichier", utilisez quelque chose qui est basé sur un simple BufferedReader.

Dans votre cas particulier, je vous recommande d’utiliser Files.lines.

Exemple:

  long count = Files.lines(Paths.get("testfile.txt"))
     .filter(s -> s.contains("particularString"))
     .count();
  System.out.println(count);

(Notez que ce cas particulier d’API de diffusion en continu ne couvre probablement pas ce que vous essayez réellement d’atteindre. Malheureusement, votre question n’indique pas quel devrait être le résultat de la méthode.)

Sur mon système, je reçois environ 15% de l'exécution du scanner avec Files.lines () ou un lecteur en mémoire tampon.

0
mtj