7
votes

Lignes de tri d'un fichier énorme.txt en Java

Je travaille avec un très gros fichier texte (755 Mo). J'ai besoin de trier les lignes (environ 1890000), puis écrivez-les dans un autre fichier.

J'ai déjà remarqué cette discussion qui a un dossier de départ vraiment similaire à celui de la mienne: Lignes de tri basées sur des mots en eux sous forme de clés < / p>

Le problème est que je ne peux pas stocker les lignes dans une collection en mémoire car je reçois une exception d'espace de tas Java (même si je l'étends au maximum) .. (déjà essayé!)

Je ne peux pas non plus l'ouvrir avec Excel et utiliser la fonction de tri car le fichier est trop grand et ne peut pas être complètement chargé.

J'ai pensé à utiliser un dB ..mais, je pense que j'écris toutes les lignes, utilisez la requête SELECT, elle est trop longue en termes de temps exécutant ..am I mal?

Toute astuce appréciée Merci d'avance


2 commentaires

Eh bien, "trop ​​long" dépend de vos attentes. Si vous espérez le faire en une demi-seconde, ce sera vraiment trop long. Si cela ne vous dérange pas d'attendre quelques secondes ou quelques minutes, cela ne devrait pas être un problème. Essayez-le et voyez si le temps est raisonnable.


Vous devriez être capable de stocker le fichier en mémoire avec environ 1 Go de tas en utilisant les dernières versions de Java. c'est-à-dire avec -xx: + USECompresseStrings


6 Réponses :


0
votes

Pourquoi n'essayez-vous pas de multithreading et d'augmenter la taille du tas du programme que vous utilisez? (Cela nécessite également que vous utilisiez une sorte de trieuse de troisième fusion à condition que vous ayez plus de mémoire que 755 Mo dans votre système.)


5 commentaires

Voir le commentaire à gauche pour Eric.sun ci-dessus.


Oui, votre raison est évidemment utile dans très très volumineuse. Mais la taille du fichier spécifié OP doit être de 755 Mo et la plupart des ordinateurs ont aujourd'hui plus de 755 Mo. Pourquoi utiliser un algorithme complexe si nous pouvons résoudre son problème avec seulement -xmx1024m?


Le tri de la fusion n'est pas un algorithme trop complexe. Je ne voulais pas faire des hypothèses sur le matériel utilisé par l'algorithme. En outre, le processus peut ne pas être le seul logiciel exécuté sur l'appareil. Dans mon humble avis, écriture de 50 lignes de code pour enregistrer plus d'un Go de mémoire (chaque ligne peut prendre plusieurs octets, si c'est une chaîne) vaut bien l'effort. (Aucune infraction prévue.)


Non, je suis d'accord avec vous quelle que soit. Si j'étais dans le scénario similaire, j'aurais juste essayé d'augmenter la taille du tas d'abord. Si cela n'a pas fonctionné, j'aurais probablement fait ce que vous avez suggéré. C'est parfait :)


Assez juste. Composons de compromis sur les deux solutions, c'est-à-dire essayer l'approche de la mémoire et connectez-vous un billet pour le remplacer par une approche plus efficace de la mémoire (avec des cas de test accompagné) à une étape ultérieure (+1).



16
votes

Je pense que la solution ici est de faire une sorte de fusion à l'aide de fichiers temporaires:

  1. lire les premiers n lignes du premier fichier, ( n étant le nombre de lignes que vous pouvez vous permettre de stocker et de trier la mémoire), de les trier et écrivez-les au fichier 1.tmp (ou aussi vous l'appelez). Faites la même chose avec les lignes suivantes n et stockez-la dans 2.tmp . Répéter jusqu'à ce que toutes les lignes du fichier d'origine aient été traitées.

  2. Lisez la première ligne de chaque fichier temporaire. Déterminez le plus petit (selon votre ordre de tri), écrivez-le au fichier de destination et lisez la ligne suivante à partir du fichier temporaire correspondant. Répéter jusqu'à ce que toutes les lignes aient été traitées.

  3. Supprimez tous les fichiers temporaires.

    Cela fonctionne avec des fichiers volumineux arbitraires, tant que vous avez suffisamment d'espace disque.


1 commentaires

Je suis complètement d'accord. Il peut être fait en utilisant l'algorithme 'Mergesort'



0
votes

Diviser et conquérir est la meilleure solution :)

Divisez votre fichier en plus petits, triez chaque fichier séparément, puis regroupez.

Liens:

Triez un fichier avec un énorme volume de Données données contrainte de mémoire

http://hackerne.ws/item?id=1603381


0 commentaires

1
votes

algorithme:

Combien de mémoire avons-nous disponible? Supposons que nous avons x mb de mémoire disponible.

  1. Divisez le fichier en k morceaux, où x * k = 2 gb . Apportez chaque morceau dans la mémoire et triez les lignes comme d'habitude en utilisant n'importe quel O (n journal n) algorithme. Enregistrez les lignes dans le fichier.

  2. amène maintenant le prochain morceau en mémoire et triez.

  3. Une fois que nous avons fini, fusionnez un par un.

    L'algorithme ci-dessus est également connu sous le nom de tri externe. L'étape 3 est connue sous le nom de N-Way fusion


0 commentaires

-2
votes

Peut-être que vous pouvez utiliser Perl pour formater le fichier. Et charge dans la base de données comme MySQL. C'est si vite. et utilisez l'index pour interroger les données. et écrire dans un autre fichier.

u peut définir une taille de tas JVM comme '-XMS256M -XMX1024M' .Je espère vous aider à vous aider


1 commentaires

L'utilisation d'une tresse de fusion basée sur un fichier est bien meilleure que de simplement attribuer davantage de mémoire. Que se passe-t-il si le fichier devient encore plus grand, c'est-à-dire 10gigs?



2
votes

Vous pouvez exécuter ce qui suit avec

Creating file to load
... Created file to load
Reading file
... Read file.
Sorting file
... Sorted file
Took 4.886 second to read, sort and write to a file


4 commentaires

Pouvez-vous répéter le test à l'aide de JDK7U2 pour voir combien de mémoire et de temps il faut?


Malheureusement, Java 7 ne prend pas en charge cette option Stackoverflow.com/Questtions/8833385/...


Oui, mais aimerait toujours voir la quantité de mémoire qu'il utilise sans l'option. Peut-être qu'ils ont apporté des améliorations telles que cette option n'est plus nécessaire.


@Dogbane Une question raisonnable, Java 7 a besoin de 200 Mo de plus que Java 6 avec des chaînes comprimées. :]