Właśnie ukończyłem Wyniki testu, które zapewniają testy wydajności dla wielu odpowiedzi. Nic dziwnego, że wszystkie odpowiedzi oparte na NIO działają najlepiej. Odpowiedź commons-io jest wyraźnie najgorsza z ponad dwukrotną długością przebiegu.
Brett Ryan,
2
Java8: Files.walk?
Benj
Odpowiedzi:
327
Java 8 zapewnia przyjemny strumień do przetwarzania wszystkich plików w drzewie.
Zapewnia to naturalny sposób przeglądania plików. Ponieważ jest to strumień, możesz wykonywać wszystkie fajne operacje na strumieniu, takie jak limit, grupowanie, mapowanie, wcześniejsze wyjście itp.
AKTUALIZACJA : Mogę wskazać, że istnieje także plik Files.find, który pobiera BiPredicate, który może być bardziej wydajny, jeśli chcesz sprawdzić atrybuty pliku.
Zauważ, że chociaż JavaDoc wymyka się temu, że ta metoda może być bardziej wydajna niż Files.walk , jest ona faktycznie identyczna, różnicę w wydajności można zaobserwować, jeśli również pobierasz atrybuty plików w swoim filtrze. Na koniec, jeśli chcesz filtrować według atrybutów, użyj Files.find , w przeciwnym razie użyj Files.walk , głównie dlatego, że występują przeciążenia i jest to wygodniejsze.
Jeden z tych przykładów, który może pokazać magię programowania funkcjonalnego nawet dla początkujących.
Johnny
2
Jak wypada to w porównaniu z metodami sprzed java 8? Moje bieżące przechodzenie do katalogu jest zbyt wolne i szukam czegoś, co je przyspieszy.
Sridhar Sarnobat
1
Piszę kilka testów zawierających większość wariantów w podanych odpowiedziach. Jak dotąd wydaje się, że najlepszym rozwiązaniem jest użycie Files.walkstrumienia równoległego, a tuż za nim Files.walkFileTree- tylko nieznacznie wolniej. Akceptowana odpowiedź przy użyciu commons-io jest zdecydowanie najwolniejsza w moich testach i jest 4 razy wolniejsza.
Brett Ryan
1
@BrettRyan, wypróbowałem twoje rozwiązanie, ale dostaję wyjątek Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException. Jak mogę to naprawić
Edycja: tutaj możesz sprawdzić wyniki różnych podejść. Wydaje się, że podejście commons-IO jest powolny, więc wybrać tylko niektóre z nich szybciej stąd (jeśli ma to znaczenie)
FYI / TLDR: jeśli chcesz po prostu rekursywnie wyświetlić wszystkie pliki bez filtrowania, zrób FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE), gdzie dirjest obiekt File wskazujący katalog podstawowy.
andronikus
2
Możesz rozważyć użycie listFilesAndDirs(), ponieważ listFiles()nie zwraca pustych folderów.
schnatterer
1
@MikeFHay Patrząc na kod FileUtils, myślę, że tak powinno być FileUtils.listFiles(dir, true, true). użycie FileUtils.listFiles(dir, null, true)spowoduje zgłoszenie wyjątku, a FileUtils.listFiles(dir, true, null)wyświetli listę wszystkich plików bez zaglądania do podkatalogów.
ocramot
Co powiesz na rodzimą bibliotekę JDK? Mogę to łatwo wdrożyć, ale po prostu byłbym C&P z innych miejsc
Christian Bongiorno,
1
Łączę kilka testów, ale jak dotąd wydaje się, że działa 4 razy wolniej niż przy użyciu alternatyw JDK8 lub JDK7. Symlinks również okazują się problematyczne z tym podejściem, szczególnie tam, gdzie prowadzą do katalogów znajdujących się wyżej w drzewie, powoduje to, że metoda nigdy nie powraca, można tego uniknąć poprzez obsługę filtra, ale niestety same dowiązania symboliczne nie są odwiedzane, nawet gdy plik.
Brett Ryan
138
// Gotowy do biegu
import java.io.File;publicclassFilewalker{publicvoid walk(String path ){File root =newFile( path );File[] list = root.listFiles();if(list ==null)return;for(File f : list ){if( f.isDirectory()){
walk( f.getAbsolutePath());System.out.println("Dir:"+ f.getAbsoluteFile());}else{System.out.println("File:"+ f.getAbsoluteFile());}}}publicstaticvoid main(String[] args){Filewalker fw =newFilewalker();
fw.walk("c:\\");}}
Uważaj tylko, że w przypadku dowiązań symbolicznych wskazujących ścieżkę wyżej w hierarchii ścieżek metoda nigdy się nie kończy. Rozważ ścieżkę z dowiązaniem symbolicznym, który wskazuje -> ..
Brett Ryan
2
Jest to po prostu zła implementacja Files.walkFileTree. Polecam, aby ludzie patrzyli na FIles.walkFileTree zamiast próbować samemu go rzucić ... Ma dokładnie taki problem, jak wskazał @BrettRyan.
Tyler Nichols,
Dziękujemy za dołączenie importu java.io.File ;. Tak wiele przykładów zapomina o dołączeniu przestrzeni nazw, a nawet danych typu danych, czyniąc ten przykład punktem wyjścia w podróż odkrywczą. Tutaj ten przykład jest gotowy do uruchomienia. Dzięki.
barrypicker
Ścieżka może się różnić w zależności od tego, gdzie znajduje się plik Filewalker. Stosowanie "/", "./"lub "../"do katalogu, bieżący katalog roboczy i katalogu nadrzędnego, odpowiednio
Jeśli podasz punkt początkowy i gościa pliku, będzie on wywoływał różne metody na gościu pliku podczas przeglądania pliku w drzewie plików. Oczekujemy, że ludzie będą tego używać, jeśli opracowują kopię rekurencyjną, ruch rekurencyjny, rekursywne usuwanie lub operację rekurencyjną, która ustawia uprawnienia lub wykonuje inną operację na każdym z plików.
publicvoid list(File file){System.out.println(file.getName());File[] children = file.listFiles();for(File child : children){
list(child);}}
Plik System.out.println jest po to, aby wskazać, że należy coś zrobić z plikiem. nie ma potrzeby rozróżniania plików i katalogów, ponieważ normalny plik będzie po prostu miał zero elementów potomnych.
Proszę! pozwól programowi wywołującemu zainicjować listę plików, aby nie musiał za każdym razem sprawdzać jego nieważności. Jeśli chcesz utworzyć drugą (publiczną) metodę, która tworzy listę, wywołuje tę metodę wewnętrzną i zwraca pełną listę.
helios
1
cokolwiek. czek zerowy nie jest bardzo drogi, oprócz wygody + osobistych preferencji, myślę, że on zrozumie.
pstanton
Czy możesz wyjaśnić nieco bardziej szczegółowo?
uday
8
Myślę, że to powinno wystarczyć:
File dir =newFile(dirname);String[] files = dir.list();
W ten sposób masz pliki i katalogi. Teraz użyj rekurencji i zrób to samo dla katalogów ( Fileklasa ma isDirectory()metodę).
Odpowiedź akceptowana jest wielka, jednak załamuje, gdy chcesz zrobić IO wewnątrz lambda.
Oto, co możesz zrobić, jeśli Twoje działanie deklaruje wyjątki IO.
Możesz traktować filtrowany strumień jako Iterable, a następnie wykonywać swoje czynności w regularnej pętli dla każdego. W ten sposób nie musisz radzić sobie z wyjątkami wewnątrz lambda.
try(Stream<Path> pathStream =Files.walk(Paths.get(path)).filter(Files::isRegularFile)){for(Path file :(Iterable<Path>) pathStream::iterator){// something that throws IOExceptionFiles.copy(file,System.out);}}
Publikując ten przykład, ponieważ miałem problem ze zrozumieniem, jak przekazać parametr filename w przykładzie nr 1 podanym przez Bryana, używając foreach na Stream-result -
Utworzy listę tekstową wszystkich plików innych niż katalogi w danym katalogu głównym, po jednym pliku w wierszu ze ścieżką względem katalogu głównego i długością.
Na podstawie odpowiedzi układacza. Oto rozwiązanie działające w JSP bez żadnych zewnętrznych bibliotek, dzięki czemu możesz umieścić je prawie w dowolnym miejscu na serwerze:
<!DOCTYPE html><%@ page session="false"%><%@ page import="java.util.*"%><%@ page import="java.io.*"%><%@ page contentType="text/html; charset=UTF-8"%><%!publicList<String> files =newArrayList<String>();/**
Fills files array with all sub-files.
*/publicvoid walk(File root ){File[] list = root.listFiles();if(list ==null)return;for(File f : list ){if( f.isDirectory()){
walk( f );}else{
files.add(f.getAbsolutePath());}}}%><%
files.clear();File jsp =newFile(request.getRealPath(request.getServletPath()));File dir = jsp.getParentFile();
walk(dir);String prefixPath = dir.getAbsolutePath()+"/";%>
Chociaż prawdopodobnie działa, pytanie dotyczy przeglądania plików, a nie renderowania przeglądanych plików. Lepiej ujawnij swój algorytm jako taki, nie jest zalecaną praktyką osadzanie logiki biznesowej w JSP.
Samuel Kerrien,
To zależy od tego, co robisz. W aplikacji dla przedsiębiorstw masz absolutną rację. Jeśli potrzebujesz tego tylko jako wpisu do prostej, samodzielnej listy, to jest w porządku.
Odpowiedzi:
Java 8 zapewnia przyjemny strumień do przetwarzania wszystkich plików w drzewie.
Zapewnia to naturalny sposób przeglądania plików. Ponieważ jest to strumień, możesz wykonywać wszystkie fajne operacje na strumieniu, takie jak limit, grupowanie, mapowanie, wcześniejsze wyjście itp.
AKTUALIZACJA : Mogę wskazać, że istnieje także plik Files.find, który pobiera BiPredicate, który może być bardziej wydajny, jeśli chcesz sprawdzić atrybuty pliku.
Zauważ, że chociaż JavaDoc wymyka się temu, że ta metoda może być bardziej wydajna niż Files.walk , jest ona faktycznie identyczna, różnicę w wydajności można zaobserwować, jeśli również pobierasz atrybuty plików w swoim filtrze. Na koniec, jeśli chcesz filtrować według atrybutów, użyj Files.find , w przeciwnym razie użyj Files.walk , głównie dlatego, że występują przeciążenia i jest to wygodniejsze.
TESTY : Zgodnie z życzeniem przedstawiłem porównanie wydajności wielu odpowiedzi. Sprawdź projekt Github, który zawiera wyniki i przypadek testowy .
źródło
Files.walk
strumienia równoległego, a tuż za nimFiles.walkFileTree
- tylko nieznacznie wolniej. Akceptowana odpowiedź przy użyciu commons-io jest zdecydowanie najwolniejsza w moich testach i jest 4 razy wolniejsza.Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException
. Jak mogę to naprawićFileUtils mają
iterateFiles
ilistFiles
metody. Wypróbuj je. (z commons-io )Edycja: tutaj możesz sprawdzić wyniki różnych podejść. Wydaje się, że podejście commons-IO jest powolny, więc wybrać tylko niektóre z nich szybciej stąd (jeśli ma to znaczenie)
źródło
FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)
, gdziedir
jest obiekt File wskazujący katalog podstawowy.listFilesAndDirs()
, ponieważlistFiles()
nie zwraca pustych folderów.FileUtils.listFiles(dir, true, true)
. użycieFileUtils.listFiles(dir, null, true)
spowoduje zgłoszenie wyjątku, aFileUtils.listFiles(dir, true, null)
wyświetli listę wszystkich plików bez zaglądania do podkatalogów.// Gotowy do biegu
źródło
-> .
."/"
,"./"
lub"../"
do katalogu, bieżący katalog roboczy i katalogu nadrzędnego, odpowiednioJava 7
będzie miałma Files.walkFileTree :Jest teraz cały samouczek Oracle dotyczący tego pytania .
źródło
Nie są potrzebne biblioteki zewnętrzne.
Zwraca kolekcję, dzięki czemu możesz robić, co chcesz z nią po rozmowie.
źródło
Wybrałbym coś takiego:
Plik System.out.println jest po to, aby wskazać, że należy coś zrobić z plikiem. nie ma potrzeby rozróżniania plików i katalogów, ponieważ normalny plik będzie po prostu miał zero elementów potomnych.
źródło
listFiles()
: „Jeśli ta abstrakcyjna nazwa ścieżki nie oznacza katalogu, wówczas ta metoda zwracanull
.”Wolę używać kolejki niż rekurencji do tego rodzaju prostej podróży:
źródło
po prostu napisz to sam, używając prostej rekurencji:
źródło
Myślę, że to powinno wystarczyć:
W ten sposób masz pliki i katalogi. Teraz użyj rekurencji i zrób to samo dla katalogów (
File
klasa maisDirectory()
metodę).źródło
W Javie 7 możesz użyć następującej klasy:
źródło
W Javie 8 możemy teraz użyć narzędzia Pliki do przejścia po drzewie plików. Bardzo prosty.
źródło
Ten kod jest gotowy do uruchomienia
źródło
Oprócz przejścia rekurencyjnego można również zastosować podejście oparte na odwiedzających.
Poniższy kod używa podejścia opartego na odwiedzających do przejścia. Oczekuje się, że dane wejściowe do programu to katalog główny do przejścia.
źródło
Możesz użyć poniższego kodu, aby rekursywnie uzyskać listę plików określonego folderu lub katalogu.
źródło
Odpowiedź akceptowana jest wielka, jednak załamuje, gdy chcesz zrobić IO wewnątrz lambda.
Oto, co możesz zrobić, jeśli Twoje działanie deklaruje wyjątki IO.
Możesz traktować filtrowany strumień jako
Iterable
, a następnie wykonywać swoje czynności w regularnej pętli dla każdego. W ten sposób nie musisz radzić sobie z wyjątkami wewnątrz lambda.Znalazłem tę sztuczkę tutaj: https://stackoverflow.com/a/32668807/1207791
źródło
Nierekurencyjny BFS z pojedynczą listą (szczególnym przykładem jest wyszukiwanie plików * .eml):
źródło
Moja wersja (oczywiście mogłem skorzystać z wbudowanego przejścia w Javie 8 ;-)):
źródło
Oto proste, ale doskonale działające rozwiązanie wykorzystujące
recursion
:źródło
źródło
Wymyśliłem to, aby rekursywnie drukować wszystkie pliki / nazwy plików.
źródło
Przykładowe dane wyjściowe * .csv w katalogu przeszukiwanie cykliczne podkatalogów za pomocą Files.find () z java.nio:
Publikując ten przykład, ponieważ miałem problem ze zrozumieniem, jak przekazać parametr filename w przykładzie nr 1 podanym przez Bryana, używając foreach na Stream-result -
Mam nadzieję że to pomoże.
źródło
Kotlin ma
FileTreeWalk
do tego celu. Na przykład:Utworzy listę tekstową wszystkich plików innych niż katalogi w danym katalogu głównym, po jednym pliku w wierszu ze ścieżką względem katalogu głównego i długością.
źródło
Innym sposobem, który możesz zrobić, nawet jeśli ktoś już udostępnia spacer Java 8.
Ten zapewni Ci rekursywnie wszystkie pliki
źródło
Na podstawie odpowiedzi układacza. Oto rozwiązanie działające w JSP bez żadnych zewnętrznych bibliotek, dzięki czemu możesz umieścić je prawie w dowolnym miejscu na serwerze:
Następnie po prostu robisz coś takiego:
źródło