Java에서 반복적으로 파일 나열
Java의 디렉토리에 있는 모든 파일을 재귀적으로 나열하려면 어떻게 해야 하는가?프레임워크가 효용성을 제공하는가?
나는 진부한 구현을 많이 보았다.그러나 틀이나 nio에서 나온 것은 없다.
Java 8은 트리의 모든 파일을 처리할 수 있는 멋진 스트림을 제공한다.
Files.walk(Paths.get(path))
.filter(Files::isRegularFile)
.forEach(System.out::println);
이것은 파일을 트래버스하는 자연스러운 방법을 제공한다.스트림이기 때문에 당신은 제한, 그룹화, 매핑, 조기 종료 등과 같은 결과에 대한 모든 멋진 스트림 작업을 할 수 있다.
업데이트: 파일 속성 확인이 필요한 경우 보다 효율적인 BiPredicate가 필요한 Files.find도 있다는 점을 지적할 수 있다.
Files.find(Paths.get(path),
Integer.MAX_VALUE,
(filePath, fileAttr) -> fileAttr.isRegularFile())
.forEach(System.out::println);
JavaDoc은 이 방법이 Files보다 더 효율적일 수 있다는 점을 피한다.실제로 동일한 작업이며, 필터 내에서 파일 특성을 검색하는 경우에도 성능의 차이를 확인할 수 있다.결국 속성을 필터링해야 하는 경우 Files.find를 사용하고 그렇지 않으면 Files를 사용하십시오.주로 과부하가 있고 그것이 더 편리하기 때문에 걷는다.
테스트: 요청하신 대로 많은 답변에 대한 성능 비교를 제공했다.결과와 테스트 케이스를 포함하는 Github 프로젝트를 확인하십시오.
FileUtils에는 다음과 같은 기능이 있다.한번 시도해봐. (커먼스-오에서)
편집: 여기서 다양한 접근 방식에 대한 벤치마크를 확인하십시오.커먼스-오(commons-io) 접근은 느린 것 같으니 여기서 좀 더 빠른 것(중요하다면)을 골라라.
// 실행 준비
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
을 가질 것이다 파일이 있다.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은 파일을 사용하여 작업을 수행하도록 지시하기 위해 여기에 있다.일반 파일에는 하위 파일이 없으므로 파일과 디렉터리를 구분할 필요가 없다.
나는 이런 종류의 간단한 전환을 위해 재귀보다 대기열을 사용하는 것을 선호한다.
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);
}
}
}
나는 이것이 그 일을 할 것이라고 생각한다.
File dir = new File(dirname);
String[] files = dir.list();
이렇게 하면 파일과 Dirs를 가지게 된다.이제 재귀(recursion)를 사용하고 dirs(dirs)에 대해서도 동일하게 한다.File
클래스가 가지고 있다.isDirectory()
방법.
자바 8에서는 파일 유틸리티를 사용하여 파일 트리를 걸을 수 있다.아주 간단하다.
Files.walk(root.toPath())
.filter(path -> !Files.isDirectory(path))
.forEach(path -> System.out.println(path));
재귀적 통과 외에 방문자 기반 접근법도 사용할 수 있다.
아래 코드는 횡단보도에 대해 방문자 기반 접근법을 사용한다.프로그램에 대한 입력이 트래버스할 루트 디렉토리인 것으로 예상된다.
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());
}
}
}
나는 모든 파일/파일 이름을 재귀적으로 인쇄하기 위해 이것을 고안했다.
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());
}
}
}
확장자가 제공된 모든 파일을 나열하고 하위 폴더를 검색하는 옵션(재발성)
public static ArrayList<File> listFileTree(File dir,boolean recursive) {
if (null == dir || !dir.isDirectory()) {
return new ArrayList<>();
}
final Set<File> fileTree = new HashSet<File>();
FileFilter fileFilter = new FileFilter() {
private final String[] acceptedExtensions = new String[]{"jpg", "png", "webp", "jpeg"};
@Override
public boolean accept(File file) {
if (file.isDirectory()) {
return true;
}
for (String extension : acceptedExtensions) {
if (file.getName().toLowerCase().endsWith(extension)) {
return true;
}
}
return false;
}
};
File[] listed = dir.listFiles(fileFilter);
if(listed!=null){
for (File entry : listed) {
if (entry.isFile()) {
fileTree.add(entry);
} else if(recursive){
fileTree.addAll(listFileTree(entry,true));
}
}
}
return new ArrayList<>(fileTree);
}
단일 목록이 있는 비복구 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 void fillFilesRecursively(File file, List<File> resultFiles) {
if (file.isFile()) {
resultFiles.add(file);
} else {
for (File child : file.listFiles()) {
fillFilesRecursively(child, resultFiles);
}
}
}
코틀린은 이 목적을 위해 가지고 있다.예를 들면 다음과 같다.
dataDir.walkTopDown().filter { !it.isDirectory }.joinToString("\n") {
"${it.toRelativeString(dataDir)}: ${it.length()}"
}
지정된 루트 아래에 있는 모든 비 디렉토리 파일의 텍스트 목록을 루트 및 길이에 상대적인 경로로 한 줄에 하나씩 생성한다.
받아들여진 답은 훌륭하지만 람다 안에서 IO를 하고 싶을 때는 무너진다.
당신의 행동이 IOExceptions를 선언할 경우, 다음과 같이 할 수 있다.
여과된 스트림을 다음과 같이 처리할 수 있다.Iterable
그리고 나서 규칙적으로 각 루프를 돌린다.이렇게 하면 람다 안에서 예외를 다룰 필요가 없다.
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://stackoverflow.com/a/32668807/1207791
누군가가 이미 Java 8 워크를 제공하더라도 당신이 할 수 있는 또 다른 방법.
이것은 당신에게 모든 파일을 반복적으로 제공할 것이다.
private Stream<File> files(File file) {
return file.isDirectory()
? Arrays.stream(file.listFiles()).flatMap(this::files)
: Stream.of(file);
}
public static String getExten(String path) {
int i = path.lastIndexOf('.');
if (i > 0) {
return path.substring(i);
}
else return "";
}
public static List<String> GetAllFiles(String path, List<String>fileList){
File file = new File(path);
File[] files = file.listFiles();
for(File folder:files) {
if(extensions.contains(getExten(folder.getPath()))) {
fileList.add(folder.getPath());
}
}
File[] direcs = file.listFiles(File::isDirectory);
for(File dir:direcs) {
GetAllFiles(dir.getPath(),fileList);
}
return fileList;
}
이것은 당신에게 모든 파일을 제공하는 간단한 재귀 기능이다.확장은 허용되는 확장자만 포함하는 문자열 목록이다.확장명 예: [.txt",".docx" 등.
수용된 답변은 자원 유출로 이어질 수 있기 때문에 빈약하다.
Files.walk는 DirectoryStreams에 의해 백업된다.
반환된 스트림은 하나 이상의 DirectoryStream을 캡슐화한다.파일 시스템 자원의 적시에 폐기가 필요한 경우, 트라이 위드 리소스 구조를 사용하여 스트림 작업이 완료된 후 스트림의 근접 방법이 호출되도록 해야 한다.폐쇄된 스트림에서 작동하면 불법 상태예외가 발생한다.
DirectoryStream은 해당 javadoc에 지정된 대로 닫아야 한다.
DirectoryStream은 생성 시 열리고 닫힌 메소드를 호출하여 닫힌다.디렉토리 스트림을 닫으면 스트림과 연결된 모든 리소스가 해제된다.스트림을 닫지 않으면 자원 누수가 발생할 수 있다.try-with resource 문은 스트림이 닫히도록 하기 위한 유용한 구성을 제공한다.
Path dir = ...
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path entry: stream) {
...
}
}
그 결과, 진정한 대답은 다음과 같다.
try (Stream<Path> stream = Files.walk(Paths.get(path))) {
// Do something with the stream.
stream.filter(Files::isRegularFile)
.forEach(System.out::println);
}
예: 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 예에서 파일 이름 매개 변수를 전달하는 방법을 이해하는 데 어려움을 겪었기 때문에, Stream-결과에 대한 예시를 사용함 -
이게 도움이 되길 바래.
@Michael 응답을 기반으로 listFiles return null인지 확인 추가
static Stream<File> files(File file) {
return file.isDirectory()
? Optional.ofNullable(file.listFiles()).map(Stream::of).orElseGet(Stream::empty).flatMap(MainActivity::files)
: Stream.of(file);
}
또는 Android5 및 Android6을 지원하는 Lightweight-Stream-API를 사용하십시오.
static Stream<File> files(File f) {
return f.isDirectory() ? Stream.ofNullable(f.listFiles()).flatMap(MainActivity::files) : Stream.of(f);
}
List<Path> filePaths = Files
.find(Paths.get(dir), Integer.MAX_VALUE, (filePath, fileAttr) -> fileAttr.isRegularFile() || fileAttr.isDirectory())
.collect(Collectors.toList());
filePaths
파일 및 폴더 목록을 다시 작성하고 더 진행할 수 있다.
스택러 답변 기준.외부 라이브러리가 없는 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>
import java.io.File;
public class Main {
public static void main(String[] args) {
loopFiles(new File("C:\\Users\\serge.klimkovitch\\Documents"));
}
private static void loopFiles(File element) {
if (element.isDirectory()) {
for (File currentFile : element.listFiles()) {
loopFiles(currentFile);
System.out.println(currentFile);
}
}
}
}
참조URL: https://stackoverflow.com/questions/2056221/recursively-list-files-in-java
'IT이야기' 카테고리의 다른 글
제출의 필드를 비우십시오(ve-validated vue). (0) | 2022.05.20 |
---|---|
자바에서 예외를 던지지 않고 스택 추적을 버리는 방법이 있는가? (0) | 2022.05.20 |
Java에서 마지막 N 요소를 포함하는 크기 제한 대기열 (0) | 2022.05.19 |
Vue 플러그인 내에 Vuex 스토어를 캡슐화할 수 있는 방법(설치 기능)이 있는가? (0) | 2022.05.19 |
java.net.기형식URLException: 프로토콜 없음 (0) | 2022.05.19 |