C'est la version la plus rapide que j'ai trouvée jusqu'à présent, environ 6 fois plus rapide que readLines. Sur un fichier journal de 150 Mo, cela prend 0,35 seconde, contre 2,40 secondes lors de l'utilisation de readLines (). Juste pour le plaisir, la commande wc -l de linux prend 0,15 seconde.
public static int countLinesOld(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
boolean empty = true;
while ((readChars = is.read(c)) != -1) {
empty = false;
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
}
return (count == 0 && !empty) ? 1 : count;
} finally {
is.close();
}
}
EDIT, 9 1/2 ans plus tard: je n'ai pratiquement aucune expérience java, mais de toute façon j'ai essayé de comparer ce code avec la LineNumberReader
solution ci-dessous car cela me dérangeait que personne ne le fasse. Il semble que, surtout pour les fichiers volumineux, ma solution est plus rapide. Bien que cela semble prendre quelques exécutions jusqu'à ce que l'optimiseur fasse un travail décent. J'ai joué un peu avec le code et j'ai produit une nouvelle version qui est toujours la plus rapide:
public static int countLinesNew(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int readChars = is.read(c);
if (readChars == -1) {
// bail out if nothing to read
return 0;
}
// make it easy for the optimizer to tune this loop
int count = 0;
while (readChars == 1024) {
for (int i=0; i<1024;) {
if (c[i++] == '\n') {
++count;
}
}
readChars = is.read(c);
}
// count remaining characters
while (readChars != -1) {
System.out.println(readChars);
for (int i=0; i<readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
readChars = is.read(c);
}
return count == 0 ? 1 : count;
} finally {
is.close();
}
}
Benchmark resuls pour un fichier texte de 1,3 Go, axe y en secondes. J'ai effectué 100 analyses avec le même fichier et mesuré chaque analyse avec System.nanoTime()
. Vous pouvez voir qu'il countLinesOld
a quelques valeurs aberrantes et countLinesNew
n'en a aucune et bien que ce soit seulement un peu plus rapide, la différence est statistiquement significative. LineNumberReader
est clairement plus lent.
J'ai implémenté une autre solution au problème, je l'ai trouvée plus efficace pour compter les lignes:
la source
LineNumberReader
LelineNumber
champ de est un entier ... Ne sera-t-il pas simplement encapsulé pour des fichiers plus longs que Integer.MAX_VALUE? Pourquoi prendre la peine de sauter longtemps ici?wc -l
compte le nombre de caractères de nouvelle ligne dans le fichier. Cela fonctionne car chaque ligne se termine par une nouvelle ligne, y compris la dernière ligne d'un fichier. Chaque ligne a un caractère de nouvelle ligne, y compris les lignes vides, d'où le nombre de caractères de nouvelle ligne == nombre de lignes dans un fichier. Maintenant, lalineNumber
variable dansFileNumberReader
représente également le nombre de caractères de nouvelle ligne vus. Il commence à zéro, avant que toute nouvelle ligne ait été trouvée, et est augmenté à chaque fois que la nouvelle ligne est vue. N'ajoutez donc pas un au numéro de ligne s'il vous plaît.wc -l
également ainsi que ce type de fichier est signalé. Voir aussi stackoverflow.com/questions/729692/…wc -l
retournerait 1. J'ai conclu que toutes les méthodes ont des défauts, et en ai implémenté une basée sur la façon dont je voudrais qu'elle se comporte, voir mon autre réponse ici.La réponse acceptée a une erreur de désactivation d'une pour les fichiers multi-lignes qui ne se terminent pas par un retour à la ligne. Un fichier d'une ligne se terminant sans une nouvelle ligne retournerait 1, mais un fichier de deux lignes se terminant sans une nouvelle ligne retournerait également 1. Voici une implémentation de la solution acceptée qui corrige cela. Les contrôles endsWithoutNewLine sont inutiles pour tout sauf la lecture finale, mais devraient être triviaux en termes de temps par rapport à la fonction globale.
la source
Avec java-8, vous pouvez utiliser des flux:
la source
La réponse avec la méthode count () ci-dessus m'a donné des erreurs de calcul si un fichier n'avait pas de nouvelle ligne à la fin du fichier - il n'a pas pu compter la dernière ligne du fichier.
Cette méthode fonctionne mieux pour moi:
la source
cnt
.Je sais que c'est une vieille question, mais la solution acceptée ne correspondait pas tout à fait à ce dont j'avais besoin. Donc, je l'ai affiné pour accepter divers terminateurs de ligne (plutôt que juste un saut de ligne) et pour utiliser un codage de caractères spécifié (plutôt que ISO-8859- n ). Méthode tout en un (refactoriser le cas échéant):
Cette solution est comparable en vitesse à la solution acceptée, environ 4% plus lente dans mes tests (bien que les tests de synchronisation en Java soient notoirement peu fiables).
la source
J'ai testé les méthodes de comptage des lignes ci-dessus et voici mes observations pour différentes méthodes testées sur mon système
Taille du fichier: 1,6 Go Méthodes:
De plus, l' approche Java8 semble assez pratique:
la source
Testé sur JDK8_u31. Mais en effet les performances sont lentes par rapport à cette méthode:
Testé et très rapide.
la source
Stream<String> - Time consumed: 122796351 Stream<String> - Num lines: 109808 Method - Time consumed: 12838000 Method - Num lines: 1
Et le nombre de lignes est même faux aussiBufferedInputStream
quand vous allez lire dans votre propre tampon. En outre, même si votre méthode peut avoir un léger avantage en termes de performances, elle perd de sa flexibilité, car elle ne prend plus en charge les\r
terminateurs de ligne unique (ancien MacOS) et ne prend pas en charge tous les encodages.Une manière simple d'utiliser Scanner
la source
J'ai conclu que
wc -l
: s la méthode de comptage des sauts de ligne est correcte mais renvoie des résultats non intuitifs sur les fichiers où la dernière ligne ne se termine pas par une nouvelle ligne.Et la solution @ er.vikas basée sur LineNumberReader mais en ajoutant un au nombre de lignes a renvoyé des résultats non intuitifs sur les fichiers où la dernière ligne se termine par un retour à la ligne.
J'ai donc fait un algo qui gère comme suit:
Et cela ressemble à ceci:
Si vous voulez des résultats intuitifs, vous pouvez l'utiliser. Si vous voulez juste de la
wc -l
compatibilité, utilisez simplement la solution @ er.vikas, mais n'en ajoutez pas une au résultat et réessayez de sauter:la source
Que diriez-vous d'utiliser la classe Process à partir du code Java? Et puis lire la sortie de la commande.
Besoin d'essayer cependant. Publiera les résultats.
la source
Si vous ne disposez d'aucune structure d'index, vous ne pourrez pas contourner la lecture du fichier complet. Mais vous pouvez l'optimiser en évitant de le lire ligne par ligne et d'utiliser une expression régulière pour faire correspondre tous les terminateurs de ligne.
la source
Cette solution amusante fonctionne vraiment bien en fait!
la source
Sur les systèmes basés sur Unix, utilisez la
wc
commande sur la ligne de commande.la source
Le seul moyen de savoir combien de lignes il y a dans le fichier est de les compter. Vous pouvez bien sûr créer une métrique à partir de vos données en vous donnant une longueur moyenne d'une ligne, puis obtenir la taille du fichier et la diviser avec avg. longueur mais ce ne sera pas précis.
la source
Meilleur code optimisé pour les fichiers multi-lignes n'ayant pas de caractère de nouvelle ligne ('\ n') à l'EOF.
la source
Scanner avec regex:
Je ne l'ai pas chronométré.
la source
si vous l'utilisez
vous ne pouvez pas exécuter de grandes lignes num, comme 100K lignes, car le retour de reader.getLineNumber est int. vous avez besoin d'un long type de données pour traiter un maximum de lignes.
la source
int
peut contenir des valeurs allant jusqu'à environ 2 milliards de dollars. Si vous chargez un fichier de plus de 2 milliards de lignes, vous avez un problème de débordement. Cela dit, si vous chargez un fichier texte non indexé de plus de deux milliards de lignes, vous avez probablement d'autres problèmes.