Lire les gros fichiers en Java
J'ai besoin de l'avis de quelqu'un qui sait Java très bien et les problèmes de mémoire.
J'ai un gros fichier (quelque chose comme 1.5 GO de ram) et j'ai besoin de couper ce fichier dans de nombreux (100 petits fichiers par exemple) des fichiers plus petits.
Je sais généralement comment le faire (à l'aide d'un BufferedReader
), mais je voudrais savoir si vous avez des conseils concernant la mémoire, ou des conseils sur la manière de le faire plus vite.
Mon fichier contient du texte, il n'est pas binaire et j'ai environ 20 caractères par ligne.
- L'utilisation d'octets Api (par exemple FileInputStream, ByteChannel), plutôt que de caractères Api (BufferedReader, etc.). Sinon, vous êtes d'encodage et de décodage inutilement.
- Fractionnement d'un fichier texte à l'aide d'octets serait une mauvaise idée.
Vous devez vous connecter pour publier un commentaire.
Tout d'abord, si votre fichier contient des données binaires, puis à l'aide
BufferedReader
serait une grosse erreur (parce que vous seriez en convertissant les données de Chaîne, ce qui est inutile et pourrait facilement endommager les données de l'); vous devez utiliser unBufferedInputStream
à la place. Si c'est des données de texte et vous avez besoin de diviser le long mais les sauts de ligne, puis à l'aideBufferedReader
est OK (en supposant que le fichier contient des lignes d'une longueur raisonnable).Concernant la mémoire, il ne devrait pas être un problème si vous utilisez un décemment de la taille de la mémoire tampon (j'avais utiliser au moins 1 mo à assurez-vous que la HD est principalement pour la lecture séquentielle et de l'écriture).
Si la vitesse s'avère être un problème, vous pourriez avoir un coup d'oeil à la
java.nio
paquets - ceux qui sont soi-disant plus rapide quejava.io
,Pour économiser de la mémoire, ne pas stocker inutilement/dupliquer les données dans la mémoire (c'est à dire ne pas les affecter à des variables en dehors de la boucle). Juste traiter la sortie immédiatement dès que l'entrée est en.
Il n'a vraiment pas d'importance si vous utilisez
BufferedReader
ou pas. Il ne sera pas considérablement beaucoup plus de mémoire que certains implicitement semblent le suggérer. Il sera plus seulement de frapper quelques % de rendement. La même chose s'applique sur l'utilisation de NIO. Il va seulement améliorer l'évolutivité, la non utilisation de la mémoire. Il ne devient intéressant lorsque vous avez des centaines de threads en cours d'exécution sur le même fichier.Juste une boucle dans le fichier, écrire chaque ligne immédiatement à d'autres fichiers que vous lisez, comptez le nombre de lignes et si elle atteint 100, puis de passer à côté de fichier, etc..
Kickoff exemple:
line.getBytes(encoding)
. Sinon, il va gâcher. L'octet longueur dépend de l'encodage de caractères utilisé. Si vous avez réellement ne vous inquiétez pas à propos de txt lignes, alors je préfère utiliserInputStream
/OutputStream
au lieu et à compter les octets transférés. Par ailleurs, il est difficile de savoir si vous dire que les fichiers sont stockés dans la base de données ou que le fichier split paramètres sont stockés dans la base de données. Si les fichiers sont également stockées dans la base de données, alors c'est peut-être la mémoire monopolisant comme wel. La solution exacte dépendra de la DB utilisé.Vous pouvez envisager d'utiliser des fichiers mappés en mémoire, via FileChannels .
Généralement beaucoup plus rapide pour les gros fichiers. Il y a les performances d'arbitrages qui pourrait le rendre plus lent, donc, YMMV.
Liées réponse: Java NIO FileChannel contre FileOutputstream performance /utilité
C'est un très bon article:
http://java.sun.com/developer/technicalArticles/Programming/PerfTuning/
En résumé, une excellente performance, vous devez:
Par exemple, pour réduire l'accès à disque, vous pouvez utiliser un grand tampon. L'article décrit les différentes approches.
- T-il fait en Java? I. e. est-il besoin d'être indépendant de la plateforme? Si pas, je vous suggère l'utilisation de la " split ' de la commande sous *nix. Si vous le voulez bien, vous pouvez exécuter cette commande par l'intermédiaire de votre programme java. Alors que je n'ai pas testé, j'imagine que c'est plus rapide que ce que Java IO de mise en œuvre vous pouvais venir.
Vous pouvez utiliser java.nio, qui est plus rapide que le classique Entrée/Sortie flux:
http://java.sun.com/javase/6/docs/technotes/guides/io/index.html
Oui.
Je pense aussi que l'utilisation de read() avec des arguments comme read(Char[], int init, int fin) est une meilleure façon de lire un fichier volumineux
(Par exemple : read(buffer,0,tampon.la longueur))
Et j'ai aussi eu le problème des valeurs manquantes de l'aide de l'BufferedReader au lieu de BufferedInputStreamReader un binaire des données du flux d'entrée. Donc, en utilisant le BufferedInputStreamReader est une bien meilleure dans ce cas.
HTML:
N'utilisez pas de lire sans arguments.
C'est très lent.
Mieux lire dans la zone tampon et le déplacer vers dossier rapidement.
Utilisation bufferedInputStream car il prend en charge binaire de lecture.
Et c'est tout.
Sauf si vous avez accidentellement lire dans l'ensemble du fichier d'entrée au lieu de le lire ligne par ligne, votre principale limitation est la vitesse du disque. Vous pouvez essayer de commencer avec un fichier contenant 100 lignes et de l'écrire à 100 différents fichiers d'une ligne dans chaque et de rendre le mécanisme de déclenchement du travail sur le nombre de lignes écrites dans le fichier actuel. Ce programme sera facilement adaptable à votre situation.