Question

J'ai un fichier de taille 2 Go qui contient des enregistrements d'étudiants. J'ai besoin de trouver des étudiants en fonction de certains attributs dans chaque enregistrement et de créer un nouveau fichier avec des résultats. L'ordre des étudiants filtrés doit être le même que dans le fichier d'origine. Quel est le moyen efficace et le plus rapide de le faire en utilisant l'API et les threads Java IO sans avoir de problèmes de mémoire? La taille MaxHeap pour JVM est définie sur 512 Mo.

Était-ce utile?

La solution

  1. 2 Go pour un fichier est énorme, vous devriez opter pour une base de données.
  2. Si vous voulez vraiment utiliser API Java I / o, puis essayez ceci: Gérer efficacement de grands fichiers de données avec Java et ça: Réglage des performances d'E / S Java

Autres conseils

Quel type de fichier? Texte, comme CSV?

Le moyen le plus simple serait de faire quelque chose comme le fait Grep: Lisez le fichier ligne par ligne, analysez la ligne, vérifiez votre critère de filtre, s'il est assorti, émettez une ligne de résultat, puis accédez à la ligne suivante, jusqu'à ce que le fichier soit terminé. Ceci est très efficace de mémoire, car vous ne disposez que de la ligne actuelle (ou d'un tampon un peu plus grand) chargé en même temps. Votre processus doit lire le fichier entier une seule fois.

Je ne pense pas que plusieurs threads vont beaucoup aider. Cela rendrait les choses beaucoup plus compliquées, et comme le processus semble être lié aux E / S, essayer de lire le même fichier avec plusieurs threads n'améliore probablement pas le débit.

Si vous constatez que vous devez le faire souvent et que le fichier à chaque fois est trop lent, vous devez créer une sorte d'index. La façon la plus simple de le faire serait d'importer le fichier dans une base de données (peut d'abord être une base de données intégrée comme SQLite ou HSQL).

Je ne compliquerais pas cela avant que vous constatiez que la manière ennuyeuse ne fonctionne pas pour ce dont vous avez besoin. Il vous suffit essentiellement de:

  • Ouvrez le flux d'entrée sur le fichier 2 Go, en se souvenant de tampon (par exemple en emballage avec BufferedInputStream)
  • Ouvrez le flux de sortie vers le fichier filtré que vous allez créer
  • Lisez le premier enregistrement à partir du flux d'entrée, regardez l'attribut pour décider si vous "avez" besoin "; Si vous le faites, écrivez-le dans le fichier de sortie
  • répéter pour les enregistrements restants

Sur l'un de mes systèmes de test avec du matériel extrêmement modeste, tamponnedInputStream autour d'un fichierInputStream Out of the Box Lire environ 500 Mo en 25 secondes, c'est-à-dire probablement en moins de 2 minutes pour traiter votre fichier de 2 Go, et la taille de tampon par défaut est fondamentalement aussi bonne qu'elle obtient qu'il obtient (voir le Timings de tampon J'ai fait pour plus de détails). J'imagine qu'avec le matériel de pointe, il est tout à fait possible que le temps soit divisé par deux.

Que vous ayez besoin d'aller à beaucoup d'efforts pour réduire les 2/3 minutes ou simplement aller pour un tout petit temps que vous attendez qu'il fonctionne est une décision que vous devrez prendre en fonction de vos besoins. Je pense que l'option de base de données ne vous achètera pas beaucoup à moins que vous ne deviez effectuer beaucoup de traitements différents d'exécution sur le même ensemble de données (et il existe d'autres solutions qui ne signifient pas automatiquement la base de données).

Je pense que tu devrais utiliser Mémoire mappé Files.Te vous aidera à cartographier le fichier plus grand dans une mémoire plus petite.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top