Java : Lire les n dernières lignes d'un fichier ÉNORME
Je veux lire les n dernières lignes d'un fichier très volumineux sans avoir à lire tout le fichier dans une mémoire tampon/zone de mémoire à l'aide de Java.
J'ai regardé autour de l'Api du JDK et Apache Commons I/O et ne suis pas en mesure de localiser une qui est approprié à cette fin.
Je pensais à la façon de la queue ou moins fait dans UNIX. Je ne le pense pas charger tout le fichier, puis afficher les dernières lignes du fichier. Il devrait être similaire façon de faire la même chose en Java aussi.
Vous devez vous connecter pour publier un commentaire.
Si vous utilisez un
RandomAccessFile
, vous pouvez utiliserlength
etrechercher
pour se rendre à un point précis près de la fin du fichier, puis de le lire en avant à partir de là.Si vous trouvez qu'il n'y avait pas assez de lignes, de retour à partir de ce point et essayer de nouveau. Une fois que vous avez compris où le
N
th dernière ligne commence, vous pouvez chercher à là et il suffit de lire et imprimer.Un premier best-suppose que l'hypothèse peut être faite sur la base de données de vos propriétés. Par exemple, si c'est un fichier texte, il est possible que les longueurs de ligne à ne pas dépasser une moyenne de 132 donc, pour les cinq dernières lignes, début 660 caractères avant la fin. Alors, si vous vous êtes trompé, essayez de nouveau à 1320 (vous pouvez même utiliser ce que vous avez appris de la dernière 660 caractères à régler que - par exemple: si ceux 660 caractères étaient seulement trois lignes, la prochaine tentative peut être 660 /3 * 5, avec peut-être un peu plus au cas où).
J'ai trouvé la façon la plus simple de le faire en utilisant
ReversedLinesFileReader
de apache commons-io api.Cette méthode va vous donner la ligne de bas en haut d'un fichier et vous pouvez spécifier
n_lines
valeur pour spécifier le numéro de la ligne.readLine()
, le curseur avance. Donc, ce code devrait manquer tous les autres car la sortie dereadLine()
dans lewhile
déclaration n'est pas d'être capturé.RandomAccessFile est un bon endroit pour commencer, comme décrit par les autres réponses. Il est l'un mise en garde importante bien.
Si votre fichier n'est pas codé avec un un octet-par-encodage des caractères, la
readLine()
méthode n'est pas d'aller travailler pour vous. EtreadUTF()
ne fonctionne pas dans toutes les circonstances. (Il lit une chaîne de caractères précédée par un nombre de caractères ...)Au lieu de cela, vous devez vous assurer que vous regardez pour la fin de la ligne des marqueurs d'une manière qui respecte l'encodage de caractère limites. De longueur fixe encodages (par exemple, les saveurs de l'UTF-16 ou UTF-32) vous avez besoin d'extraire des caractères commençant à partir de l'octet positions qui sont divisibles par le caractère de la taille en octets. Longueur variable codages (par exemple UTF-8), vous devez rechercher un octet qui doit être le premier octet d'un caractère.
Dans le cas de l'UTF-8, le premier octet d'un caractère sera
0xxxxxxx
ou110xxxxx
ou1110xxxx
ou11110xxx
. Tout le reste est soit un deuxième /troisième octet, ou illégale d'un UTF-8 de la séquence. Voir Le Standard Unicode, Version 5.2, Chapitre 3.9, Le Tableau 3-7. Cela signifie, que de l'observation des points de discussion, que tout et 0x0D 0x0A octets dans un correctement encodé en UTF-8 flux représentera un LF ou CR de caractère. Ainsi, à compter simplement le nombre et 0x0D 0x0A octets est valable de mise en œuvre de la stratégie (UTF-8) si nous pouvons supposer que les autres types d'Unicode séparateur de ligne (0x2028, 0x2029 et 0x0085) ne sont pas utilisés. Vous ne pouvez pas supposer que, alors que le code va être plus compliqué.Avoir identifié un bon caractère de limite, vous pouvez simplement appeler
new String(...)
en passant le tableau d'octets, de décalage, de numération et codage, puis appeler à plusieurs reprisesString.lastIndexOf(...)
à compter de fin de lignes.0x0a
n'est pas un retour à la ligne (par exemple UTF-16), et 2) le fait qu'il existe d'autres Unicode séparateur de ligne de codepoints; par exemple,0x2028
,0x2029
et0x0085
J'ai trouvé
RandomAccessFile
et d'autres Tampon Lecteur de classes trop lent pour moi. Rien ne peut être plus rapide qu'unetail -<#lines>
. Donc, ce que c'était la meilleure solution pour moi.tail
peut être une activité très coûteuse en elle-même selon la quantité de mémoire dont vous disposez. Et il est également spécifiques à Unix.CircularFifoBuffer de apache commons . la réponse d'une question similaire à Comment lire les 5 dernières lignes d'un .txt fichier en java
Noter que dans Apache Commons Collections 4 cette classe semble avoir été renommé CircularFifoQueue
Un
RandomAccessFile
permet de chercher (http://download.oracle.com/javase/1.4.2/docs/api/java/io/RandomAccessFile.html). LeFile.length
méthode retourne la taille du fichier. Le problème est de déterminer le nombre de lignes. Pour cela, vous pouvez rechercher à la fin du fichier et le lire en arrière jusqu'à ce que vous avez atteint le bon nombre de lignes.J'ai eu le même problème, mais je n'ai pas compris à l'autre des solutions.
J'ai utilisé ce. J'espère que c'est plus simple à coder.
La
ReversedLinesFileReader
peut être trouvé dans la Apache Commons IO bibliothèque java.Ici est le meilleur moyen que j'ai trouvé pour le faire. Simple et assez rapide et efficace en terme de mémoire.
maxLines
lignes.Ici, c'est le travail pour cela.