मैं जावा की एक निर्देशिका के तहत सभी फ़ाइलों की पुनरावृत्ति कैसे करूं? क्या ढांचा कोई उपयोगिता प्रदान करता है?
मैंने बहुत सारे हैकी कार्यान्वयन देखे। लेकिन फ्रेमवर्क या एनआईओ में से कोई भी नहीं
मैं जावा की एक निर्देशिका के तहत सभी फ़ाइलों की पुनरावृत्ति कैसे करूं? क्या ढांचा कोई उपयोगिता प्रदान करता है?
मैंने बहुत सारे हैकी कार्यान्वयन देखे। लेकिन फ्रेमवर्क या एनआईओ में से कोई भी नहीं
जवाबों:
जावा 8 एक पेड़ में सभी फाइलों को प्रोसेस करने के लिए एक अच्छी स्ट्रीम प्रदान करता है।
Files.walk(Paths.get(path))
.filter(Files::isRegularFile)
.forEach(System.out::println);
यह फ़ाइलों को ट्रैवर्स करने का एक प्राकृतिक तरीका प्रदान करता है। चूंकि यह एक स्ट्रीम है आप परिणाम पर सभी अच्छे स्ट्रीम ऑपरेशन कर सकते हैं जैसे कि सीमा, समूहन, मैपिंग, जल्दी बाहर निकलना आदि।
अद्यतन : मैं इंगित कर सकता हूँ कि वहाँ भी 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 का उपयोग करें , क्योंकि ज्यादातर ओवरलोड हैं और यह अधिक सुविधाजनक है।
TESTS : जैसा कि मैंने अनुरोध किया है कि मैंने कई उत्तरों की तुलना की है। की जाँच करें Github परियोजना जो परिणाम और एक परीक्षण का मामला शामिल है ।
Files.walk
समानांतर धारा के साथ उपयोग करना सबसे अच्छा है, इसके बाद बारीकी से Files.walkFileTree
जो केवल मामूली धीमा है। कॉमन्स-आईओ का उपयोग करते हुए स्वीकृत उत्तर मेरे परीक्षणों द्वारा 4 गुना धीमा होने का सबसे धीमा है।
Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException
। मैं इसे कैसे ठीक कर सकता हूं
FileUtils है iterateFiles
और listFiles
तरीकों। उन्हें एक कोशिश दे। ( कॉमन्स-आईओ से )
संपादित करें: आप विभिन्न तरीकों के बेंचमार्क के लिए यहां देख सकते हैं । ऐसा लगता है कि कॉमन्स-आईओ एप्रोच धीमा है, इसलिए यहां से कुछ तेज लें (यदि यह मायने रखता है)
FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)
, dir
फ़ाइल ऑब्जेक्ट कहाँ है जो आधार निर्देशिका को इंगित करता है।
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 :
यदि आप एक प्रारंभिक बिंदु और एक फ़ाइल आगंतुक प्रदान करते हैं, तो यह फ़ाइल विज़िटर पर विभिन्न तरीकों को लागू करेगा क्योंकि यह फ़ाइल ट्री में फ़ाइल के माध्यम से चलता है। हम उम्मीद करते हैं कि लोग इसका उपयोग करेंगे यदि वे एक पुनरावर्ती प्रतिलिपि, एक पुनरावर्ती चाल, एक पुनरावर्ती हटाने या एक पुनरावर्ती ऑपरेशन विकसित कर रहे हैं जो अनुमतियाँ सेट करता है या प्रत्येक फ़ाइलों पर एक और ऑपरेशन करता है।
इस प्रश्न पर अब संपूर्ण ओरेकल ट्यूटोरियल है ।
किसी बाहरी पुस्तकालयों की जरूरत नहीं।
एक संग्रह लौटाता है ताकि आप कॉल के बाद इसके साथ जो चाहें कर सकें।
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;
}
मुझे लगता है कि यह काम करना चाहिए:
File dir = new File(dirname);
String[] files = dir.list();
इस तरह आपके पास फाइलें और डायरियां हैं। अब पुनरावर्तन का उपयोग करें और डायर ( File
कक्षा में isDirectory()
विधि) के लिए भी ऐसा ही करें ।
जावा 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());
}
}
}
स्वीकार किए जाते हैं जवाब लेकिन यह टूट जाती है जब आप लैम्ब्डा के अंदर आईओ करना चाहते हैं, बहुत अच्छा है।
यदि आपकी कार्रवाई IOException की घोषणा करती है तो आप यहां क्या कर सकते हैं।
आप फ़िल्टर्ड स्ट्रीम को 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
एकल सूची के साथ गैर-पुनरावर्ती बीएफएस (विशेष उदाहरण * .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);
}
}
मेरा संस्करण (निश्चित रूप से मैं जावा 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);
}
}
}
मैं इसे सभी फ़ाइलों / फ़ाइल नामों की पुनरावृत्ति के लिए प्रिंट करने के लिए आया था।
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());
}
}
}
उदाहरण आउटपुट * .csv निर्देशिका में फ़ाइलें पुनरावर्ती खोज उपनिर्देशिका का उपयोग करके files.find () java.nio से:
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);
}
}
इस उदाहरण को पोस्ट करते हुए, क्योंकि मुझे यह समझने में परेशानी हुई कि ब्रायन द्वारा दिए गए # 1 उदाहरण में फाइलनाम पैरामीटर कैसे पास किया जाए, स्ट्रीम-रिजल्ट पर फॉर्च का उपयोग करके -
उम्मीद है की यह मदद करेगा।
कोटलिन के पास 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>