Comment la liste a de 2 millions de répertoire de fichiers en java sans avoir un “out of memory” exception
Je dois traiter avec un répertoire de près de 2 millions de xml à traiter.
J'ai déjà résolu le traitement de répartir les travaux entre les machines et les threads à l'aide de files d'attente et tout va bien.
Mais maintenant, le gros problème est le goulot d'étranglement de la lecture du répertoire, avec les 2 millions de fichiers afin de combler les files d'attente de manière incrémentale.
J'ai essayé d'utiliser le File.listFiles()
méthode, mais il me donne une java out of memory: heap space
exception. Des idées?
- Désolé, mais ce que l'OS ne supporte pas que? Vivant en 1950? Je Sais que de divers outils de soufflage, par exemple sur windows (explorer arriver AFFREUSEMENT lent), mais le système de fichiers prend en charge.
- FAT32 (vieux, mais en aucun cas 1950 époque, et encore assez commun) a une limite de fichiers par répertoire óf 65k.
- Mais en supposant que quelqu'un utilise qui est neglegient - à l'exception des appareils n'est pas soutenu, et puis le problème - devinez quoi - ne serait pas "problème d'inscription, les fichiers".
- J'adhère complètement, il a été un mauvais choix de ne pas les stocker dans un hiérarque façon. Le système de fichiers est NTFS. Ici vous pouvez lire les limites: technet.microsoft.com/en-us/library/cc781134(WS.10).aspx
- Salut @Fgblanch a u trouver la solution car j'ai le même problème, s'il vous Plaît aider.
- Salut, je suis confronté au même problème. Pourriez-vous nous expliquer comment vous avez résolu le problème s'il vous plaît?
- Car nous ne pouvions pas utiliser Java 7, nous avons trouvé un modèle dans les noms de fichiers et leur a écrit un script pour les stocker de manière hiérarchique (beaucoup plus efficace). Donc, ma suggestion utilisation de Java 7+ ou essayer de réorganiser les fichiers dans plusieurs dossiers sans interroger l'ensemble de la liste
- trouver la solution dans le commentaire ci-dessus
- si j'utilise FileNameFilter, cela aidera à éviter à la mémoire de l'exception? Je peux aussi utiliser Java7, quelle est la meilleure solution dans ce cas. Les fichiers que je serait la transformation pourrait être autour de 80 GO(chacun environ 1 mo ou moins). Pouvez-vous suggérer qui Java7 bibliothèque pourrait m'aider?
Vous devez vous connecter pour publier un commentaire.
Tout d'abord, avez-vous de la possibilité d'utiliser Java 7? Là, vous avez une
FileVisitor
et laFiles.walkFileTree
, qui doit probablement travailler au sein de votre mémoire contraintes.Sinon, la seule façon que je peux penser à est de l'utilisationFile.listFiles(FileFilter filter)
avec un filtre qui renvoie toujoursfalse
(veiller à ce que la gamme complète des fichiers n'est jamais gardé en mémoire), mais qui attire les fichiers à traiter, et peut-être les met dans une producteur/consommateur file d'attente ou écrit les noms de fichier sur le disque pour plus tard traversée.Alternativement, si vous contrôlez les noms des fichiers, ou s'ils sont nommés dans certains de bien belle façon, vous pouvez traiter les fichiers en morceaux à l'aide d'un filtre qui accepte les noms de fichiers sur la forme
file0000000
-filefile0001000
puisfile0001000
-filefile0002000
et ainsi de suite.Si les noms sont pas nommé dans une belle façon de ce genre, vous pouvez essayer de filtrage basé sur le hash-code de la nom de fichier, qui est censé être assez uniformément répartis sur l'ensemble des entiers.Mise À Jour: Soupir. Probablement ne fonctionne pas. Juste eu un coup d'oeil à la listFiles mise en œuvre:
donc il va probablement échouer à la première ligne de toute façon... décevant. Je crois que votre meilleure option est de placer les fichiers dans des répertoires différents.
Btw, pourriez-vous nous donner un exemple d'un nom de fichier? Sont-ils "deviner"? Comme
Si Java 7 n'est pas une option, ce hack fonctionne (pour UNIX):
Le paramètre-f accélérer (à partir de
man ls
):Utilisation
Fichier.liste()
au lieu deFile.listFiles()
- leString
objets qu'il retourne à consommer moins de mémoire que laFile
objets, et, plus important encore, en fonction de l'emplacement du répertoire) ils ne contiennent pas le nom de chemin complet.Ensuite, construisez
File
objets nécessaires lors du traitement du résultat.Toutefois, cela ne fonctionnera pas de manière arbitraire répertoires soit. C'est une meilleure idée d'organiser vos fichiers dans une hiérarchie de répertoires, de sorte que pas un seul répertoire a plus que quelques milliers d'entrées.
Dans le cas où vous pouvez utiliser Java 7, ce qui peut être fait de cette façon et vous n'aurez pas ceux de problèmes de mémoire.
Vous pouvez le faire avec Apache FileUtils de la bibliothèque. Pas de problème de mémoire. Je n'ai vérifier avec visualvm.
Espère que ça aide.
bye
Puisque vous êtes sur Windows, il me semble que vous devriez avoir tout simplement utilisé ProcessBuilder pour commencer quelque chose comme "cmd /k dir /b target_directory", la capture de la sortie de l', et de la route dans un fichier. Vous pouvez ensuite traiter ce fichier ligne à ligne, lire les noms de fichier et de traiter avec eux.
Mieux vaut tard que jamais? 😉
Pourquoi avez-vous stocker de 2 millions de fichiers dans le même répertoire de toute façon? Je peux imaginer qu'il ralentit l'accès terriblement sur le niveau de l'OS, déjà.
Que je voudrais vraiment les avoir divisés en sous-répertoires (par exemple par date/heure de création), déjà avant le traitement. Mais si il n'est pas possible pour une raison quelconque, pourrait-il être fait pendant le traitement? E. g. déplacer 1000 fichiers en file d'attente pour Process1 en Répertoire1, un autre de 1000 fichiers pour Process2 en Directory2 etc. Ensuite, chaque processus/thread ne voit que l' (nombre limité) des fichiers en portions pour elle.
Cela nécessite aussi de Java 7, mais c'est plus simple que la
Files.walkFileTree
réponse si vous voulez juste pour lister le contenu d'un répertoire et non à pied de l'arbre entier:La mise en œuvre de
DirectoryStream
est spécifique à la plateforme, et n'appelle jamaisFile.list
ou quelque chose comme ça, au lieu d'utiliser la Unix ou Windows appels système itérer sur un répertoire d'une entrée à la fois.Au poing, vous pouvez essayer d'augmenter la mémoire de votre JVM avec passant -Xmx1024m par exemple
Veuillez poster le full stack trace de l'OOM exception à identifier l'endroit où le goulot d'étranglement de l'est, ainsi que d'une courte, complète le programme Java montrant le comportement que vous voyez.
Il est plus probable parce que vous collectez tous les deux millions d'entrées dans la mémoire, et ils ne sont pas adaptés. Pouvez-vous augmenter la mémoire?
Si les noms de fichier de suivre certaines règles, vous pouvez utiliser
File.list(filter)
au lieu deFile.listFiles
pour obtenir des portions gérables de la liste des fichiers.J'ai fait face à un même problème quand j'ai développé des logiciels malveillants application de numérisation. Ma solution est d'exécuter la commande du shell à la liste de tous les fichiers. Il est plus rapide que de manière récursive méthodes pour parcourir dossier par dossier.
voir plus sur le shell de commande ici: http://adbshell.com/commands/adb-shell-ls
Vous pouvez utiliser listFiles avec un spécial FilenameFilter. La première fois que le FilenameFilter est envoyé à listFiles il accepte les 1000 premiers fichiers et les enregistre ensuite visité.
La prochaine fois FilenameFilter est envoyé à listFiles, il ignore les 1000 premiers fichiers visités et retourne la prochaine 1000, et ainsi de suite jusqu'à la fin.
Comme une première approche, vous pouvez essayer de peaufiner certains paramètres de la mémoire de la JVM, par exemple une augmentation de la taille du segment comme il a été suggéré ou même utiliser AggressiveHeap option.
En tenant compte de la grande quantité de fichiers, cela peut ne pas aider, alors je suggère pour contourner le problème. Créer plusieurs fichiers avec des noms de fichiers dans chaque, dire 500k noms de fichier par fichier et lire.
Essayer, ça fonctionne pour moi, mais je n'avais pas beaucoup de documents...