Podczas wyszukiwania w Google widzę, że używanie java.io.File#length()
może być powolne.
FileChannel
ma również size()
dostępną metodę.
Czy w Javie istnieje skuteczny sposób na uzyskanie rozmiaru pliku?
Podczas wyszukiwania w Google widzę, że używanie java.io.File#length()
może być powolne.
FileChannel
ma również size()
dostępną metodę.
Czy w Javie istnieje skuteczny sposób na uzyskanie rozmiaru pliku?
Odpowiedzi:
Cóż, próbowałem to zmierzyć za pomocą poniższego kodu:
Dla uruchomień = 1 i iteracji = 1 metoda adresu URL jest najszybsza w większości przypadków, po której następuje kanał. Uruchamiam to z pewną przerwą około 10 razy. Tak więc przy jednorazowym dostępie użycie adresu URL to najszybszy sposób, jaki mogę sobie wyobrazić:
Dla przebiegów = 5 i iteracji = 50 obraz rysuje się inaczej.
Plik musi buforować wywołania systemu plików, podczas gdy kanały i URL mają trochę narzutu.
Kod:
źródło
stream.available()
nie zwraca długości pliku. Zwraca liczbę bajtów, które są dostępne do odczytu bez blokowania innych strumieni. Niekoniecznie jest to ta sama liczba bajtów, co długość pliku. Aby uzyskać rzeczywistą długość strumienia, naprawdę musisz go przeczytać (i w międzyczasie policzyć odczytane bajty).Wzorzec podany przez GHad mierzy wiele innych rzeczy (takich jak odbicie, tworzenie instancji obiektów itp.) Oprócz określenia długości. Jeśli spróbujemy się tego pozbyć, to dla jednego połączenia otrzymam następujące czasy w mikrosekundach:
Za 100 przebiegów i 10000 iteracji otrzymuję:
Uruchomiłem następujący zmodyfikowany kod, podając jako argument nazwę pliku 100 MB.
źródło
Wszystkie przypadki testowe w tym poście są wadliwe, ponieważ mają dostęp do tego samego pliku dla każdej testowanej metody. Więc buforowanie dysku zaczyna działać, w którym testy 2 i 3 odnoszą korzyści. Aby udowodnić swoją rację, wziąłem testowy przypadek dostarczony przez GHAD i zmieniłem kolejność wyliczania i poniżej są wyniki.
Patrząc na wynik, myślę, że File.length () jest naprawdę zwycięzcą.
Kolejność testu to kolejność wyników. Możesz nawet zobaczyć, jak czas potrzebny na moim komputerze różnił się między wykonaniami, ale File.Length (), gdy nie był pierwszy, i wygrał pierwszy dostęp do dysku.
źródło
Kiedy zmodyfikuję twój kod, aby używał pliku dostępnego przez ścieżkę bezwzględną zamiast zasobu, otrzymuję inny wynik (dla 1 uruchomienia, 1 iteracji i pliku 100 000 bajtów - czasy dla pliku 10-bajtowego są identyczne jak 100 000 bajtów )
Suma DŁUGOŚĆ: 33, na Iterację: 33,0
Suma KANAŁÓW: 3626, na Iterację: 3626,0
Suma adresów URL: 294, na iterację: 294,0
źródło
W odpowiedzi na test porównawczy rgriga, należy również wziąć pod uwagę czas potrzebny do otwarcia / zamknięcia instancji FileChannel i RandomAccessFile, ponieważ te klasy będą otwierać strumień do odczytu pliku.
Po zmodyfikowaniu testu porównawczego otrzymałem następujące wyniki dla 1 iteracji na pliku 85 MB:
Dla 10000 iteracji tego samego pliku:
Jeśli potrzebujesz tylko rozmiaru pliku, najszybszym sposobem jest file.length (). Jeśli planujesz użyć pliku do innych celów, takich jak czytanie / pisanie, wówczas RAF wydaje się być lepszym rozwiązaniem. Tylko nie zapomnij zamknąć połączenia pliku :-)
źródło
Napotkałem ten sam problem. Musiałem uzyskać rozmiar pliku i datę modyfikacji 90 000 plików w udziale sieciowym. Używanie Java i bycie tak minimalistycznym, jak to tylko możliwe, zajęłoby bardzo dużo czasu. (Musiałem uzyskać adres URL z pliku, a także ścieżkę do obiektu. Więc było to nieco zróżnicowane, ale ponad godzinę). Następnie użyłem natywnego pliku wykonywalnego Win32 i wykonałem to samo zadanie, po prostu zrzucając plik ścieżka, zmodyfikowana i rozmiar do konsoli i wykonane z Java. Prędkość była niesamowita. Proces natywny i moja obsługa ciągów w celu odczytania danych mogą przetwarzać ponad 1000 elementów na sekundę.
Więc chociaż ludzie niżej ocenili powyższy komentarz, jest to poprawne rozwiązanie i rozwiązało mój problem. W moim przypadku z wyprzedzeniem znałem foldery, których potrzebowałem, i mogłem przekazać to w wierszu poleceń do mojej aplikacji win32. Przetwarzanie katalogu zajęło mi kilka minut.
Wydawało się, że problem dotyczy również systemu Windows. OS X nie miał tego samego problemu i mógł uzyskać dostęp do informacji o plikach sieciowych tak szybko, jak mógł to zrobić system operacyjny.
Obsługa plików Java w systemie Windows jest okropna. Dostęp do plików na dysku lokalnym jest jednak w porządku. To właśnie udziały sieciowe spowodowały straszną wydajność. Windows może uzyskać informacje o udziale sieciowym i obliczyć całkowity rozmiar w mniej niż minutę.
- Ben
źródło
Jeśli chcesz, aby rozmiar pliku obejmował wiele plików w katalogu, użyj
Files.walkFileTree
. Możesz uzyskać rozmiar z tegoBasicFileAttributes
, który otrzymasz.Jest to znacznie szybsze niż wywołanie
.length()
wynikuFile.listFiles()
lub użycieFiles.size()
wynikuFiles.newDirectoryStream()
. W moich przypadkach testowych było około 100 razy szybciej.źródło
Files.walkFileTree
jest dostępny na Androida 26+.Właściwie myślę, że „ls” może być szybsze. Zdecydowanie w Javie występują problemy z pobieraniem informacji o pliku. Niestety nie ma równoważnej bezpiecznej metody rekursywnego ls dla Windows. (DIR / S cmd.exe może się mylić i generować błędy w nieskończonych pętlach)
W XP, uzyskując dostęp do serwera w sieci LAN, w systemie Windows potrzebuję 5 sekund, aby uzyskać liczbę plików w folderze (33 000) i całkowity rozmiar.
Kiedy powtarzam to w Javie, zajmie mi to ponad 5 minut. Zacząłem mierzyć czas potrzebny na wykonanie file.length (), file.lastModified () i file.toURI () i odkryłem, że 99% mojego czasu zajmuje te 3 wywołania. 3 rozmowy, które faktycznie muszę wykonać ...
Różnica dla 1000 plików to 15 ms lokalnie w porównaniu z 1800 ms na serwerze. Skanowanie ścieżek serwera w Javie jest absurdalnie wolne. Jeśli natywny system operacyjny może szybko skanować ten sam folder, dlaczego nie może Java?
Jako pełniejszy test użyłem WineMerge na XP, aby porównać datę modyfikacji i rozmiar plików na serwerze z plikami lokalnie. To było iteracyjne w całym drzewie katalogów 33 000 plików w każdym folderze. Całkowity czas 7 sekund. java: ponad 5 minut.
Zatem oryginalne oświadczenie i pytanie z PO są prawdziwe i ważne. Jest mniej zauważalny w przypadku lokalnego systemu plików. Wykonanie lokalnego porównania folderu zawierającego 33 000 elementów zajmuje 3 sekundy w WinMerge i 32 sekundy lokalnie w Javie. Więc znowu, java versus natywna to 10-krotne spowolnienie w tych podstawowych testach.
Java 1.6.0_22 (najnowsza), Gigabit LAN i połączenia sieciowe, ping jest mniejszy niż 1 ms (oba w tym samym przełączniku)
Java jest powolna.
źródło
Z testu porównawczego GHad wynika kilka problemów, o których wspomnieli ludzie:
1> Jak wspomniano BalusC: stream.available () jest przepływana w tym przypadku.
Ponieważ available () zwraca szacunkową liczbę bajtów, które można odczytać (lub pominąć) z tego strumienia wejściowego bez blokowania przez następne wywołanie metody dla tego strumienia wejściowego.
Więc po pierwsze, aby usunąć adres URL to podejście.
2> Jak wspomniał StuartH - kolejność uruchomienia testu również powoduje różnicę w pamięci podręcznej, więc usuń to, uruchamiając test osobno.
Teraz rozpocznij test:
Kiedy CHANNEL one działa sam:
Gdy DŁUGOŚĆ jeden biegnie sam:
Wygląda więc na to, że LENGTH jest tutaj zwycięzcą:
źródło