En recherchant sur Google, je vois que l'utilisation java.io.File#length()
peut être lente.
FileChannel
a unsize()
méthode qui est également disponible.
Existe-t-il un moyen efficace en java d'obtenir la taille du fichier?
En recherchant sur Google, je vois que l'utilisation java.io.File#length()
peut être lente.
FileChannel
a unsize()
méthode qui est également disponible.
Existe-t-il un moyen efficace en java d'obtenir la taille du fichier?
Réponses:
Eh bien, j'ai essayé de le mesurer avec le code ci-dessous:
Pour les exécutions = 1 et les itérations = 1, la méthode URL est la plus rapide la plupart du temps, suivie du canal. Je lance cela avec une pause fraîche environ 10 fois. Donc, pour un accès unique, utiliser l'URL est le moyen le plus rapide auquel je puisse penser:
Pour les courses = 5 et les itérations = 50, l'image est différente.
Le fichier doit mettre en cache les appels au système de fichiers, tandis que les canaux et l'URL ont une surcharge.
Code:
la source
stream.available()
ne renvoie pas la longueur du fichier. Il renvoie la quantité d'octets disponibles pour la lecture sans bloquer les autres flux. Ce n'est pas nécessairement la même quantité d'octets que la longueur du fichier. Pour obtenir la longueur réelle d'un flux, vous devez vraiment le lire (et compter les octets lus pendant ce temps).Le benchmark donné par GHad mesure beaucoup d'autres choses (comme la réflexion, l'instanciation d'objets, etc.) en plus d'obtenir la longueur. Si nous essayons de nous débarrasser de ces choses, pour un appel, j'obtiens les temps suivants en microsecondes:
Pour 100 exécutions et 10000 itérations, j'obtiens:
J'ai exécuté le code modifié suivant en donnant comme argument le nom d'un fichier de 100 Mo.
la source
Tous les cas de test de cet article sont imparfaits car ils accèdent au même fichier pour chaque méthode testée. Ainsi, la mise en cache du disque démarre dont les tests 2 et 3 bénéficient. Pour prouver mon point, j'ai pris le cas de test fourni par GHAD et changé l'ordre d'énumération et ci-dessous sont les résultats.
En regardant le résultat, je pense que File.length () est vraiment le gagnant.
L'ordre de test est l'ordre de sortie. Vous pouvez même voir le temps passé sur ma machine varié entre les exécutions, mais File.Length () lorsqu'il n'est pas le premier, et le premier accès au disque a gagné.
la source
Lorsque je modifie votre code pour utiliser un fichier accessible par un chemin absolu au lieu d'une ressource, j'obtiens un résultat différent (pour 1 exécution, 1 itération et un fichier de 100 000 octets - les temps pour un fichier de 10 octets sont identiques à 100 000 octets )
LONGUEUR somme: 33, par itération: 33,0
CHANNEL somme: 3626, par Itération: 3626.0
Somme d'URL: 294, par itération: 294,0
la source
En réponse au benchmark de rgrig, le temps nécessaire pour ouvrir / fermer les instances FileChannel & RandomAccessFile doit également être pris en compte, car ces classes ouvriront un flux pour lire le fichier.
Après avoir modifié le benchmark, j'ai obtenu ces résultats pour 1 itérations sur un fichier de 85 Mo:
Pour 10000 itérations sur le même fichier:
Si vous n'avez besoin que de la taille du fichier, file.length () est le moyen le plus rapide de le faire. Si vous prévoyez d'utiliser le fichier à d'autres fins comme la lecture / l'écriture, la RAF semble être un meilleur pari. N'oubliez pas de fermer la connexion de fichier :-)
la source
J'ai rencontré ce même problème. J'avais besoin d'obtenir la taille du fichier et la date de modification de 90 000 fichiers sur un partage réseau. Utiliser Java, et être aussi minimaliste que possible, cela prendrait beaucoup de temps. (J'avais besoin d'obtenir l'URL du fichier, ainsi que le chemin de l'objet. Donc, cela variait quelque peu, mais plus d'une heure.) J'ai ensuite utilisé un exécutable Win32 natif, et j'ai fait la même tâche, en vidant simplement le fichier chemin, modifié et taille vers la console, et exécuté à partir de Java. La vitesse était incroyable. Le processus natif et ma gestion des chaînes pour lire les données pourraient traiter plus de 1000 éléments par seconde.
Donc, même si les gens ont classé le commentaire ci-dessus, c'est une solution valable et a résolu mon problème. Dans mon cas, je connaissais à l'avance les dossiers dont j'avais besoin, et je pouvais les transmettre dans la ligne de commande à mon application win32. Je suis passé d'heures à traiter un annuaire en minutes.
Le problème semblait également être spécifique à Windows. OS X n'avait pas le même problème et pouvait accéder aux informations sur les fichiers réseau aussi rapidement que le système d'exploitation le pouvait.
La gestion des fichiers Java sous Windows est terrible. L'accès au disque local pour les fichiers est bien cependant. Ce ne sont que les partages réseau qui ont causé les performances terribles. Windows pourrait également obtenir des informations sur le partage réseau et calculer la taille totale en moins d'une minute.
--Ben
la source
Si vous voulez la taille de fichier de plusieurs fichiers dans un répertoire, utilisez
Files.walkFileTree
. Vous pouvez obtenir la taille duBasicFileAttributes
que vous recevrez.C'est beaucoup plus rapide que d'appeler
.length()
le résultat deFile.listFiles()
ou d'utiliserFiles.size()
le résultat deFiles.newDirectoryStream()
. Dans mes cas de test, c'était environ 100 fois plus rapide.la source
Files.walkFileTree
est disponible sur Android 26+.En fait, je pense que le "ls" peut être plus rapide. Il y a certainement des problèmes en Java concernant l'obtention d'informations sur les fichiers. Malheureusement, il n'existe pas de méthode sûre équivalente de ls récursif pour Windows. (Le DIR / S de cmd.exe peut devenir confus et générer des erreurs dans des boucles infinies)
Sur XP, en accédant à un serveur sur le LAN, il me faut 5 secondes sous Windows pour obtenir le nombre de fichiers dans un dossier (33 000), et la taille totale.
Lorsque j'itère récursivement à travers cela en Java, cela me prend plus de 5 minutes. J'ai commencé à mesurer le temps nécessaire pour faire file.length (), file.lastModified () et file.toURI () et ce que j'ai trouvé, c'est que 99% de mon temps est pris par ces 3 appels. Les 3 appels que j'ai réellement besoin de faire ...
La différence pour 1000 fichiers est de 15 ms en local par rapport à 1 800 ms sur le serveur. L'analyse du chemin du serveur en Java est ridiculement lente. Si le système d'exploitation natif peut analyser rapidement ce même dossier, pourquoi Java ne le peut-il pas?
Comme test plus complet, j'ai utilisé WineMerge sur XP pour comparer la date modifiée et la taille des fichiers sur le serveur par rapport aux fichiers localement. C'était itérer sur toute l'arborescence de répertoires de 33 000 fichiers dans chaque dossier. Temps total, 7 secondes. java: plus de 5 minutes.
Donc, la déclaration et la question originales du PO sont vraies et valides. C'est moins perceptible lorsqu'il s'agit d'un système de fichiers local. Faire une comparaison locale du dossier avec 33 000 éléments prend 3 secondes dans WinMerge et prend 32 secondes localement en Java. Encore une fois, java versus native est un ralentissement 10x dans ces tests rudimentaires.
Java 1.6.0_22 (dernier), Gigabit LAN et connexions réseau, le ping est inférieur à 1 ms (les deux dans le même commutateur)
Java est lent.
la source
À partir de la référence de GHad, il y a quelques problèmes que les gens ont mentionnés:
1> Comme BalusC l'a mentionné: stream.available () est déroulé dans ce cas.
Parce que available () renvoie une estimation du nombre d'octets qui peuvent être lus (ou ignorés) à partir de ce flux d'entrée sans blocage par le prochain appel d'une méthode pour ce flux d'entrée.
Donc, 1er pour supprimer l'URL cette approche.
2> Comme StuartH l'a mentionné - l'ordre d'exécution du test fait également la différence du cache, alors supprimez-le en exécutant le test séparément.
Maintenant, commencez le test:
Lorsque CHANNEL one fonctionne seul:
Lorsque LENGTH une course seule:
On dirait donc que le LENGTH est le gagnant ici:
la source