답변:
Java 8은 트리의 모든 파일을 처리 할 수있는 멋진 스트림을 제공합니다.
Files.walk(Paths.get(path))
.filter(Files::isRegularFile)
.forEach(System.out::println);
이것은 파일을 순회하는 자연스러운 방법을 제공합니다. 스트림이므로 제한, 그룹화, 매핑, 조기 종료 등과 같은 결과에 대한 모든 멋진 스트림 작업을 수행 할 수 있습니다.
UPDATE : 나는 또한이 점을 지적 할 수 Files.find 소요 BiPredicate 당신은 파일 특성을 확인해야하는 경우 더 효율적이 될 수 있습니다.
Files.find(Paths.get(path),
Integer.MAX_VALUE,
(filePath, fileAttr) -> fileAttr.isRegularFile())
.forEach(System.out::println);
JavaDoc은이 방법이 Files.walk 보다 더 효율적일 수는 없지만 , 필터 내에서 파일 속성을 검색하는 경우 성능의 차이를 관찰 할 수는 없습니다. 결국 속성을 필터링 해야하는 경우 Files.find를 사용 하고 그렇지 않으면 Files.walk를 사용 하십시오 . 주로 과부하가 있고 더 편리하기 때문입니다.
테스트 : 요청에 따라 많은 답변의 성능 비교를 제공했습니다. 결과 및 테스트 사례가 포함 된 Github 프로젝트를 확인하십시오 .
Files.walk
병렬 스트림과 함께 사용 하는 것이 가장 좋으며 그 뒤에는 Files.walkFileTree
약간 느립니다. commons-io를 사용하여 허용되는 답변은 테스트에서 4 배 느리게 느립니다.
Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException
합니다. 내가 어떻게 고칠 수 있을까
Fileutils의는 이 iterateFiles
와 listFiles
방법. 그들에게 시도하십시오. ( commons-io에서 )
편집 : 당신은 할 수 있습니다 여기 에서 다양한 접근 방식의 벤치 마크를 확인할 . commons-io 접근 방식이 느리므로 여기 에서 더 빠른 것을 선택 하십시오 (중요한 경우)
FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)
. 여기서는 dir
기본 디렉토리를 가리키는 File 객체입니다.
listFilesAndDirs()
하는 listFiles()
것이 좋습니다.
FileUtils.listFiles(dir, true, true)
. 를 사용 FileUtils.listFiles(dir, null, true)
하면 예외가 발생하지만 FileUtils.listFiles(dir, true, null)
하위 디렉토리를 보지 않고 모든 파일을 나열합니다.
// 실행할 준비가되었습니다
import java.io.File;
public class Filewalker {
public void walk( String path ) {
File root = new File( 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() );
}
}
}
public static void main(String[] args) {
Filewalker fw = new Filewalker();
fw.walk("c:\\" );
}
}
-> .
.
"/"
, "./"
또는 "../"
각각의 루트 디렉토리, 현재 작업 디렉토리 및 상위 디렉토리에 대한
자바 7 것은 이 Files.walkFileTree를 :
시작점과 파일 방문자를 제공하면 파일 트리에서 파일을 탐색 할 때 파일 방문자에 대해 다양한 메소드를 호출합니다. 사람들이 재귀 복사, 재귀 이동, 재귀 삭제 또는 재귀 작업을 개발하는 경우 각 파일에 대해 권한을 설정하거나 다른 작업을 수행하는 경우이를 사용할 것을 기대합니다.
이 질문에 대한 전체 Oracle 튜토리얼이 있습니다.
외부 라이브러리가 필요하지 않습니다.
통화 후 원하는 작업을 수행 할 수 있도록 컬렉션을 반환합니다.
public static Collection<File> listFileTree(File dir) {
Set<File> fileTree = new HashSet<File>();
if(dir==null||dir.listFiles()==null){
return fileTree;
}
for (File entry : dir.listFiles()) {
if (entry.isFile()) fileTree.add(entry);
else fileTree.addAll(listFileTree(entry));
}
return fileTree;
}
나는 다음과 같이 갈 것이다.
public void list(File file) {
System.out.println(file.getName());
File[] children = file.listFiles();
for (File child : children) {
list(child);
}
}
System.out.println은 파일과 관련이 있음을 나타냅니다. 일반 파일에는 단순히 자식이 없기 때문에 파일과 디렉토리를 구분할 필요가 없습니다.
listFiles()
"이 추상 패스 디렉토리,이 메소드의 반환을 표시하지 않는 경우 null
."
이런 종류의 간단한 트래버스에는 재귀보다 큐를 사용하는 것이 좋습니다.
List<File> allFiles = new ArrayList<File>();
Queue<File> dirs = new LinkedList<File>();
dirs.add(new File("/start/dir/"));
while (!dirs.isEmpty()) {
for (File f : dirs.poll().listFiles()) {
if (f.isDirectory()) {
dirs.add(f);
} else if (f.isFile()) {
allFiles.add(f);
}
}
}
간단한 재귀를 사용하여 직접 작성하십시오.
public List<File> addFiles(List<File> files, File dir)
{
if (files == null)
files = new LinkedList<File>();
if (!dir.isDirectory())
{
files.add(dir);
return files;
}
for (File file : dir.listFiles())
addFiles(files, file);
return files;
}
Java 7에서는 다음 클래스를 사용할 수 있습니다.
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
public class MyFileIterator extends SimpleFileVisitor<Path>
{
public MyFileIterator(String path) throws Exception
{
Files.walkFileTree(Paths.get(path), this);
}
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attributes) throws IOException
{
System.out.println("File: " + file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attributes) throws IOException
{
System.out.println("Dir: " + dir);
return FileVisitResult.CONTINUE;
}
}
이 코드는 실행할 준비가되었습니다
public static void main(String... args) {
File[] files = new File("D:/").listFiles();
if (files != null)
getFiles(files);
}
public static void getFiles(File[] files) {
for (File file : files) {
if (file.isDirectory()) {
getFiles(file.listFiles());
} else {
System.out.println("File: " + file);
}
}
}
재귀 순회 외에도 방문자 기반 접근 방식을 사용할 수도 있습니다.
아래 코드는 순회에 방문자 기반 접근 방식을 사용합니다. 아래 코드는 순회에 대한 루트 디렉토리 인 것으로 예상됩니다.
public interface Visitor {
void visit(DirElement d);
void visit(FileElement f);
}
public abstract class Element {
protected File rootPath;
abstract void accept(Visitor v);
@Override
public String toString() {
return rootPath.getAbsolutePath();
}
}
public class FileElement extends Element {
FileElement(final String path) {
rootPath = new File(path);
}
@Override
void accept(final Visitor v) {
v.visit(this);
}
}
public class DirElement extends Element implements Iterable<Element> {
private final List<Element> elemList;
DirElement(final String path) {
elemList = new ArrayList<Element>();
rootPath = new File(path);
for (File f : rootPath.listFiles()) {
if (f.isDirectory()) {
elemList.add(new DirElement(f.getAbsolutePath()));
} else if (f.isFile()) {
elemList.add(new FileElement(f.getAbsolutePath()));
}
}
}
@Override
void accept(final Visitor v) {
v.visit(this);
}
public Iterator<Element> iterator() {
return elemList.iterator();
}
}
public class ElementWalker {
private final String rootDir;
ElementWalker(final String dir) {
rootDir = dir;
}
private void traverse() {
Element d = new DirElement(rootDir);
d.accept(new Walker());
}
public static void main(final String[] args) {
ElementWalker t = new ElementWalker("C:\\temp");
t.traverse();
}
private class Walker implements Visitor {
public void visit(final DirElement d) {
System.out.println(d);
for(Element e:d) {
e.accept(this);
}
}
public void visit(final FileElement f) {
System.out.println(f);
}
}
}
아래 코드를 사용하여 특정 폴더 또는 디렉토리의 파일 목록을 재귀 적으로 얻을 수 있습니다.
public static void main(String args[]) {
recusiveList("D:");
}
public static void recursiveList(String path) {
File f = new File(path);
File[] fl = f.listFiles();
for (int i = 0; i < fl.length; i++) {
if (fl[i].isDirectory() && !fl[i].isHidden()) {
System.out.println(fl[i].getAbsolutePath());
recusiveList(fl[i].getAbsolutePath());
} else {
System.out.println(fl[i].getName());
}
}
}
허용 대답은 당신이 람다 내부 IO를 수행 할 때 고장 그러나, 중대하다.
조치가 IOException을 선언하는 경우 수행 할 수있는 작업은 다음과 같습니다.
필터링 된 스트림을로 취급 Iterable
한 다음 정규 for-each 루프에서 작업을 수행 할 수 있습니다. 이런 식으로 람다 안에서 예외를 처리 할 필요가 없습니다.
try (Stream<Path> pathStream = Files.walk(Paths.get(path))
.filter(Files::isRegularFile)) {
for (Path file : (Iterable<Path>) pathStream::iterator) {
// something that throws IOException
Files.copy(file, System.out);
}
}
그 트릭을 발견했습니다 : https : //.com/a/32668807/1207791
단일 목록이있는 비 재귀 BFS (특히 예제는 * .eml 파일 검색) :
final FileFilter filter = new FileFilter() {
@Override
public boolean accept(File file) {
return file.isDirectory() || file.getName().endsWith(".eml");
}
};
// BFS recursive search
List<File> queue = new LinkedList<File>();
queue.addAll(Arrays.asList(dir.listFiles(filter)));
for (ListIterator<File> itr = queue.listIterator(); itr.hasNext();) {
File file = itr.next();
if (file.isDirectory()) {
itr.remove();
for (File f: file.listFiles(filter)) itr.add(f);
}
}
내 버전 (물론 Java 8;-에서 내장 워크를 사용할 수 있음) :
public static List<File> findFilesIn(File rootDir, Predicate<File> predicate) {
ArrayList<File> collected = new ArrayList<>();
walk(rootDir, predicate, collected);
return collected;
}
private static void walk(File dir, Predicate<File> filterFunction, List<File> collected) {
Stream.of(listOnlyWhenDirectory(dir))
.forEach(file -> walk(file, filterFunction, addAndReturn(collected, file, filterFunction)));
}
private static File[] listOnlyWhenDirectory(File dir) {
return dir.isDirectory() ? dir.listFiles() : new File[]{};
}
private static List<File> addAndReturn(List<File> files, File toAdd, Predicate<File> filterFunction) {
if (filterFunction.test(toAdd)) {
files.add(toAdd);
}
return files;
}
다음을 사용하여 간단하지만 완벽하게 작동하는 솔루션입니다 recursion
.
public static List<Path> listFiles(String rootDirectory)
{
List<Path> files = new ArrayList<>();
listFiles(rootDirectory, files);
return files;
}
private static void listFiles(String path, List<Path> collectedFiles)
{
File root = new File(path);
File[] files = root.listFiles();
if (files == null)
{
return;
}
for (File file : files)
{
if (file.isDirectory())
{
listFiles(file.getAbsolutePath(), collectedFiles);
} else
{
collectedFiles.add(file.toPath());
}
}
}
나는 모든 파일 / 파일 이름을 재귀 적으로 인쇄하기 위해 이것을 생각해 냈습니다.
private static void printAllFiles(String filePath,File folder) {
if(filePath==null) {
return;
}
File[] files = folder.listFiles();
for(File element : files) {
if(element.isDirectory()) {
printAllFiles(filePath,element);
} else {
System.out.println(" FileName "+ element.getName());
}
}
}
예제는 java.nio의 Files.find ()를 사용하여 디렉토리 재귀 검색 서브 디렉토리에서 * .csv 파일을 출력합니다.
String path = "C:/Daten/ibiss/ferret/";
logger.debug("Path:" + path);
try (Stream<Path> fileList = Files.find(Paths.get(path), Integer.MAX_VALUE,
(filePath, fileAttr) -> fileAttr.isRegularFile() && filePath.toString().endsWith("csv"))) {
List<String> someThingNew = fileList.sorted().map(String::valueOf).collect(Collectors.toList());
for (String t : someThingNew) {
t.toString();
logger.debug("Filename:" + t);
}
}
이 예제를 게시하면 Bryan이 제공 한 # 1 예제에서 filename 매개 변수를 전달하는 방법을 이해하는 데 어려움이 있었으므로 foreach on stream-result-
도움이 되었기를 바랍니다.
코 틀린은 FileTreeWalk
이러한 목적을 가지고 있습니다. 예를 들면 다음과 같습니다.
dataDir.walkTopDown().filter { !it.isDirectory }.joinToString("\n") {
"${it.toRelativeString(dataDir)}: ${it.length()}"
}
주어진 루트 아래의 모든 비 디렉토리 파일의 텍스트 목록을 생성합니다. 루트와 길이에 상대적인 경로를 가진 행당 한 파일입니다.
스태커 답변을 기반으로합니다. 다음은 외부 라이브러리없이 JSP에서 작동하는 솔루션이므로 서버의 거의 모든 곳에 배치 할 수 있습니다.
<!DOCTYPE html>
<%@ page session="false" %>
<%@ page import="java.util.*" %>
<%@ page import="java.io.*" %>
<%@ page contentType="text/html; charset=UTF-8" %>
<%!
public List<String> files = new ArrayList<String>();
/**
Fills files array with all sub-files.
*/
public void 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 = new File(request.getRealPath(request.getServletPath()));
File dir = jsp.getParentFile();
walk(dir);
String prefixPath = dir.getAbsolutePath() + "/";
%>
그런 다음 다음과 같은 작업을 수행하십시오.
<ul>
<% for (String file : files) { %>
<% if (file.matches(".+\\.(apk|ipa|mobileprovision)")) { %>
<li><%=file.replace(prefixPath, "")%></li>
<% } %>
<% } %>
</ul>