У меня есть эта функция, которая рекурсивно печатает имена всех файлов в каталоге. Проблема в том, что мой код очень медленный, потому что он должен получать доступ к удаленному сетевому устройству на каждой итерации.
Мой план состоит в том, чтобы сначала рекурсивно загрузить все файлы из каталога, а затем просмотреть все файлы с помощью регулярного выражения, чтобы отфильтровать все файлы, которые мне не нужны. Есть ли у кого-нибудь лучшее предложение?
public static printFnames(String sDir){
File[] faFiles = new File(sDir).listFiles();
for(File file: faFiles){
if(file.getName().matches("^(.*?)")){
System.out.println(file.getAbsolutePath());
}
if(file.isDirectory()){
printFnames(file.getAbsolutePath());
}
}
}
Позже это просто тест. Я не собираюсь использовать подобный код, вместо этого я собираюсь добавить путь и дату модификации каждого файла, который соответствует расширенному регулярному выражению, в массив.
Ответы:
Если предположить , что это фактическое производство кода вы будете писать, то я предлагаю использовать решение такого рода вещи , которые уже были решены - Apache Commons IO , в частности
FileUtils.listFiles()
. Он обрабатывает вложенные каталоги, фильтры (на основе имени, времени модификации и т. Д.).Например, для вашего регулярного выражения:
Collection files = FileUtils.listFiles( dir, new RegexFileFilter("^(.*?)"), DirectoryFileFilter.DIRECTORY );
Это будет рекурсивно искать файлы, соответствующие
^(.*?)
регулярному выражению, возвращая результаты в виде коллекции.Стоит отметить, что это будет не быстрее, чем откат вашего собственного кода, он делает то же самое - перебор файловой системы в Java просто медленный. Разница в том, что в версии Apache Commons ошибок не будет.
источник
Files.walk(Paths.get("/etc")).filter(Files::isRegularFile).collect(Collectors.toList())
В Java 8, это 1-вкладыш через
Files.find()
с произвольно большой глубине (например999
) иBasicFileAttributes
изisRegularFile()
public static printFnames(String sDir) { Files.find(Paths.get(sDir), 999, (p, bfa) -> bfa.isRegularFile()).forEach(System.out::println); }
Чтобы добавить дополнительную фильтрацию, улучшите лямбда, например, все файлы jpg, измененные за последние 24 часа:
(p, bfa) -> bfa.isRegularFile() && p.getFileName().toString().matches(".*\\.jpg") && bfa.lastModifiedTime().toMillis() > System.currentMillis() - 86400000
источник
Это очень простой рекурсивный метод получения всех файлов из заданного корня.
Он использует класс Java 7 NIO Path.
private List<String> getFileNames(List<String> fileNames, Path dir) { try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) { for (Path path : stream) { if(path.toFile().isDirectory()) { getFileNames(fileNames, path); } else { fileNames.add(path.toAbsolutePath().toString()); System.out.println(path.getFileName()); } } } catch(IOException e) { e.printStackTrace(); } return fileNames; }
источник
С Java 7 быстрым способом пройти через дерево каталогов было введено с
Paths
иFiles
функциональностью. Они намного быстрее, чем "старый"File
способ.Это будет код для обхода и проверки имен путей с помощью регулярного выражения:
public final void test() throws IOException, InterruptedException { final Path rootDir = Paths.get("path to your directory where the walk starts"); // Walk thru mainDir directory Files.walkFileTree(rootDir, new FileVisitor<Path>() { // First (minor) speed up. Compile regular expression pattern only one time. private Pattern pattern = Pattern.compile("^(.*?)"); @Override public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes atts) throws IOException { boolean matches = pattern.matcher(path.toString()).matches(); // TODO: Put here your business logic when matches equals true/false return (matches)? FileVisitResult.CONTINUE:FileVisitResult.SKIP_SUBTREE; } @Override public FileVisitResult visitFile(Path path, BasicFileAttributes mainAtts) throws IOException { boolean matches = pattern.matcher(path.toString()).matches(); // TODO: Put here your business logic when matches equals true/false return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path path, IOException exc) throws IOException { // TODO Auto-generated method stub return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path path, IOException exc) throws IOException { exc.printStackTrace(); // If the root directory has failed it makes no sense to continue return path.equals(rootDir)? FileVisitResult.TERMINATE:FileVisitResult.CONTINUE; } }); }
источник
Быстрый способ получить содержимое каталога с помощью Java 7 NIO:
import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.FileSystems; import java.nio.file.Path; ... Path dir = FileSystems.getDefault().getPath( filePath ); DirectoryStream<Path> stream = Files.newDirectoryStream( dir ); for (Path path : stream) { System.out.println( path.getFileName() ); } stream.close();
источник
Files.newDirectoryStream
может вызвать исключение IOException. Я предлагаю обернуть эту строку в Java7 try-with-statement, чтобы поток всегда был закрыт для вас (исключение или нет, без необходимости в afinally
). См. Также здесь: stackoverflow.com/questions/17739362/…Интерфейс Java для чтения содержимого папок файловой системы не очень производительный (как вы обнаружили). JDK 7 исправляет это с помощью совершенно нового интерфейса для такого рода вещей, который должен обеспечить производительность такого рода операций на собственном уровне.
Основная проблема заключается в том, что Java выполняет собственный системный вызов для каждого отдельного файла. В интерфейсе с низкой задержкой это не так уж важно, но в сети даже с умеренной задержкой это действительно складывается. Если вы профилируете свой алгоритм выше, вы обнаружите, что большая часть времени тратится на надоедливый вызов isDirectory () - это потому, что вы совершаете круговой обход для каждого отдельного вызова isDirectory (). Большинство современных операционных систем могут предоставить такую информацию, когда изначально был запрошен список файлов / папок (в отличие от запроса каждого отдельного пути к файлу для его свойств).
Если вы не можете дождаться JDK7, одна из стратегий устранения этой задержки - перейти в многопоточность и использовать ExecutorService с максимальным количеством потоков для выполнения вашей рекурсии. Это не очень хорошо (вам придется иметь дело с блокировкой ваших структур выходных данных), но это будет чертовски быстрее, чем при использовании этого однопоточного.
Во всех ваших обсуждениях такого рода вещей я настоятельно рекомендую вам сравнивать лучшее, что вы можете сделать, используя собственный код (или даже сценарий командной строки, который делает примерно то же самое). Сказать, что на обход сетевой структуры уходит час, на самом деле не так много. Сказать нам, что вы можете сделать это нативно за 7 секунд, но это займет час в Java, привлечет внимание людей.
источник
это будет работать нормально ... и его рекурсивный
File root = new File("ROOT PATH"); for ( File file : root.listFiles()) { getFilesRecursive(file); } private static void getFilesRecursive(File pFile) { for(File files : pFile.listFiles()) { if(files.isDirectory()) { getFilesRecursive(files); } else { // do your thing // you can either save in HashMap and use it as // per your requirement } } }
источник
Мне лично нравится эта версия FileUtils. Вот пример, который находит все mp3 или flac в каталоге или любом из его подкаталогов:
String[] types = {"mp3", "flac"}; Collection<File> files2 = FileUtils.listFiles(/path/to/your/dir, types , true);
источник
Это будет работать нормально
public void displayAll(File path){ if(path.isFile()){ System.out.println(path.getName()); }else{ System.out.println(path.getName()); File files[] = path.listFiles(); for(File dirOrFile: files){ displayAll(dirOrFile); } } }
источник
Эта функция, вероятно, перечислит все имя файла и его путь из своего каталога и его подкаталогов.
public void listFile(String pathname) { File f = new File(pathname); File[] listfiles = f.listFiles(); for (int i = 0; i < listfiles.length; i++) { if (listfiles[i].isDirectory()) { File[] internalFile = listfiles[i].listFiles(); for (int j = 0; j < internalFile.length; j++) { System.out.println(internalFile[j]); if (internalFile[j].isDirectory()) { String name = internalFile[j].getAbsolutePath(); listFile(name); } } } else { System.out.println(listfiles[i]); } } }
источник
Java 8
public static void main(String[] args) throws IOException { Path start = Paths.get("C:\\data\\"); try (Stream<Path> stream = Files.walk(start, Integer.MAX_VALUE)) { List<String> collect = stream .map(String::valueOf) .sorted() .collect(Collectors.toList()); collect.forEach(System.out::println); } }
источник
Ваше чувство неправильное. Так работают файловые системы. Нет более быстрого способа (кроме случаев, когда вам нужно делать это повторно или для разных шаблонов, вы можете кэшировать все пути к файлам в памяти, но тогда вам придется иметь дело с недействительностью кеша, т.е. что происходит, когда файлы добавляются / удаляются / переименовываются во время приложение запускается).
источник
Просто чтобы вы знали, что isDirectory () - довольно медленный метод. Я нахожу это довольно медленным в моем файловом браузере. Я буду искать библиотеку, чтобы заменить ее собственным кодом.
источник
Более эффективный способ работы с миллионами папок и файлов, который я нашел, - это захват списка каталогов с помощью команды DOS в каком-либо файле и его анализ. После анализа данных вы можете проводить анализ и вычислять статистику.
источник
import java.io.*; public class MultiFolderReading { public void checkNoOfFiles (String filename) throws IOException { File dir=new File(filename); File files[]=dir.listFiles();//files array stores the list of files for(int i=0;i<files.length;i++) { if(files[i].isFile()) //check whether files[i] is file or directory { System.out.println("File::"+files[i].getName()); System.out.println(); } else if(files[i].isDirectory()) { System.out.println("Directory::"+files[i].getName()); System.out.println(); checkNoOfFiles(files[i].getAbsolutePath()); } } } public static void main(String[] args) throws IOException { MultiFolderReading mf=new MultiFolderReading(); String str="E:\\file"; mf.checkNoOfFiles(str); } }
источник
В Guava вам не нужно ждать, пока вам вернут коллекцию, но вы можете перебирать файлы. Легко представить
IDoSomethingWithThisFile
интерфейс в сигнатуре следующей функции:public static void collectFilesInDir(File dir) { TreeTraverser<File> traverser = Files.fileTreeTraverser(); FluentIterable<File> filesInPostOrder = traverser.preOrderTraversal(dir); for (File f: filesInPostOrder) System.out.printf("File: %s\n", f.getPath()); }
TreeTraverser также позволяет переключаться между различными стилями обхода.
источник
public class GetFilesRecursive { public static List <String> getFilesRecursively(File dir){ List <String> ls = new ArrayList<String>(); for (File fObj : dir.listFiles()) { if(fObj.isDirectory()) { ls.add(String.valueOf(fObj)); ls.addAll(getFilesRecursively(fObj)); } else { ls.add(String.valueOf(fObj)); } } return ls; } public static List <String> getListOfFiles(String fullPathDir) { List <String> ls = new ArrayList<String> (); File f = new File(fullPathDir); if (f.exists()) { if(f.isDirectory()) { ls.add(String.valueOf(f)); ls.addAll(getFilesRecursively(f)); } } else { ls.add(fullPathDir); } return ls; } public static void main(String[] args) { List <String> ls = getListOfFiles("/Users/srinivasab/Documents"); for (String file:ls) { System.out.println(file); } System.out.println(ls.size()); } }
источник
Другой оптимизированный код
import java.io.File; import java.util.ArrayList; import java.util.List; public class GetFilesRecursive { public static List <String> getFilesRecursively(File dir){ List <String> ls = new ArrayList<String>(); if (dir.isDirectory()) for (File fObj : dir.listFiles()) { if(fObj.isDirectory()) { ls.add(String.valueOf(fObj)); ls.addAll(getFilesRecursively(fObj)); } else { ls.add(String.valueOf(fObj)); } } else ls.add(String.valueOf(dir)); return ls; } public static void main(String[] args) { List <String> ls = getFilesRecursively(new File("/Users/srinivasab/Documents")); for (String file:ls) { System.out.println(file); } System.out.println(ls.size()); } }
источник
Еще один пример перечисления файлов и каталогов с использованием Java 8
filter
public static void main(String[] args) { System.out.println("Files!!"); try { Files.walk(Paths.get(".")) .filter(Files::isRegularFile) .filter(c -> c.getFileName().toString().substring(c.getFileName().toString().length()-4).contains(".jpg") || c.getFileName().toString().substring(c.getFileName().toString().length()-5).contains(".jpeg") ) .forEach(System.out::println); } catch (IOException e) { System.out.println("No jpeg or jpg files"); } System.out.println("\nDirectories!!\n"); try { Files.walk(Paths.get(".")) .filter(Files::isDirectory) .forEach(System.out::println); } catch (IOException e) { System.out.println("No Jpeg files"); } }
источник