问题 我需要编写一个简单的软件,给出一定的约束条件,将一系列文件附加到列表中。 用户可以在目录的两个“类型”之间进行选择:一个带有 * 通配符,这意味着它还应该探索子目录,而不使用通配符的经典卡只能获取该目录中存在的文件。
我在做什么
现在我正在做最愚蠢的事情:
import java.io.File;
public class Eseguibile {
private static void displayIt(File node){
System.out.println(node.getAbsoluteFile());
if(node.isDirectory()){
String[] subNote = node.list();
for(String filename : subNote){
displayIt(new File(node, filename));
}
}
}
public static void main(String[] args){
System.out.println("ciao");
displayIt( new File("/home/dierre/") );
}
}
我不需要构建树,因为我只需要文件列表,所以我想也许有更有效的方法来实现它。
我正在阅读TreeModel,但据我所知,它只是实现Jtree的接口。
答案 0 :(得分:8)
现在我正在做最愚蠢的事情......
递归既不“愚蠢”,也不一定效率低下。实际上,在这种特殊情况下,递归解决方案可能比非递归解决方案更有效。当然,递归解决方案比替代方案更容易编码和理解。
递归的唯一潜在问题是,如果目录树在病理学上很深,你可能会溢出堆栈。
如果你真的想避免递归,那么自然的方法是使用“文件列表堆栈”数据结构。您将在每个地方递归,将包含当前目录(剩余)File对象的列表推送到堆栈,读取新目录并开始处理它们。然后,当您完成后,弹出堆栈并继续父目录。这将为您提供深度优先遍历。如果要进行广度优先遍历,请使用“文件队列”数据结构而不是堆栈。
答案 1 :(得分:1)
递归总是可以转换成循环 下面是一个快速而肮脏的解决方案(未经测试):
private static void displayDirectory(File node){
ArraList directories = new ArrayList();
if (node.isDirectory())
directories.append (node);
// Iterate over the directory list
Iterator it = directories.iterator();
while(it.hasNext()){
File dir = (File)it.next();
// get childs
String[] subNote = dir.list();
for(String filename : subNote){
subNode = new File(node, filename);
// display current child name
System.out.println(subNode.getAbsoluteFile());
// if directory : add current child to the list of dir to process
if (subnode.isDirectory()){
directories.append(subNode);
}
}
}
}
请注意,源节点应该是要显示的任何内容的目录 此外,这是广度优先显示。如果你想要一个深度优先,你应该改变“append”将文件放在数组列表中的当前节点之后。
但是,我不确定记忆的安慰 问候答案 2 :(得分:1)
我是一个真正的新手,但在这个问题上工作了一个星期......我有一个干净的解决方案......感谢PATRY和etbal的所有帮助。
public class Recur {
// Process only directories under dir
File dir;
static DirectoryComponent allDirectory;
public Recur(File dir, DirectoryComponent allDirectory) {
// TODO Auto-generated constructor stub
this.dir = dir;
}
public static DirectoryComponent Recur(File dir, DirectoryComponent allDirectory) {
String file;
String path;
File firstDir = new File(dir.getPath());
file = firstDir.getName();
path = firstDir.getPath();
if (dir.isDirectory()) {
file = firstDir.getName();
path = firstDir.getPath();
DirectoryComponent directory = new Directory(file, path);
allDirectory.add(directory);
String [] subNote = dir.list();
for(String filename : subNote){
File subNode = new File(firstDir, filename);
// store current child name
file = subNode.getName();
path = subNode.getPath();
directory.add(new FileItem(file,path));
}
String[] children = dir.list();
for (int i=0; i<children.length; i++) {
Recur(new File(dir, children[i]), allDirectory);
}
}
return allDirectory;
}
}
答案 3 :(得分:1)
我的迭代解决方案:
ArrayDeque<File> stack = new ArrayDeque<File>();
stack.push(new File("<path>"));
int n = 0;
while(!stack.isEmpty()){
n++;
File file = stack.pop();
System.err.println(file);
File[] files = file.listFiles();
for(File f: files){
if(f.isHidden()) continue;
if(f.isDirectory()){
stack.push(f);
continue;
}
n++;
System.out.println(f);
}
}
System.out.println(n);
答案 4 :(得分:1)
@Stephen C:
根据您的要求,我在评论中谈到了我的基准代码(C# - 不是Java)。
请注意,它应该使用秒表代替日期时间以获得更好的准确性,但除此之外它没有问题
我没有测试迭代是否提供与递归相同的数字文件,但它应该。
实际上,如果你注意中位数,你会发现它已经开始只显示很少的文件。(我的桌面文件夹包含2210个文件,415个文件夹,3.2 GB总的来说,下载文件夹中的大部分文件,AppData,以及由于桌面上的一个较大的C#项目[mail-server]而导致的文件数量较多。
要获得我在评论中谈到的数字,请安装cygwin(包含所有内容[我认为大约100GB]),然后索引cygwin文件夹。
正如评论中所提到的,说它无关紧要并不完全正确。
而对于小目录树,递归比迭代(几十毫秒的数量级)的效率可忽略不计,对于非常大的树,递归比迭代慢几分钟(因此明显)慢。要弄清楚原因也不难。如果你必须分配并返回一组新的堆栈变量,每次调用一个函数,并存储所有先前的结果,直到你返回,你当然比在堆上启动一个堆栈结构时慢一些,并为每次迭代使用它。
树不需要在病理学上深入注意这种效果(虽然慢速不是堆栈溢出,但其非常不利的后果与StackOverflow-Bug没有太大区别)。此外,我不会打电话给很多文件&#34;病态&#34;,因为如果你在主驱动器上做索引,你自然会有很多文件。有一些HTML文档,文件数量爆炸。您会发现在很多文件中,迭代在不到30秒内完成,而递归需要appx。 3分钟。
using System;
using System.Data;
using System.Linq;
namespace IterativeDirectoryCSharp
{
public class SearchStrategy
{
//Iterative File and Folder Listing in VB.NET
public static bool IterativeSearch2(string strPath)
{
System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(strPath);
System.IO.FileSystemInfo[] arrfsiEntities = null;
arrfsiEntities = dirInfo.GetFileSystemInfos();
// Creates and initializes a new Stack.
System.Collections.Stack strLastPathStack = new System.Collections.Stack();
System.Collections.Stack iIndexStack = new System.Collections.Stack();
int iIndex = 0;
int iMaxEntities = arrfsiEntities.Length;
do
{
while (iIndex < iMaxEntities)
{
if (arrfsiEntities[iIndex].Attributes == System.IO.FileAttributes.Directory)
{
//Console.WriteLine("Searching directory " + arrfsiEntities[iIndex].FullName);
strLastPathStack.Push(System.IO.Directory.GetParent(arrfsiEntities[iIndex].FullName).FullName);
strLastPathStack.Push(arrfsiEntities[iIndex].FullName);
iIndexStack.Push(iIndex);
dirInfo = null;
Array.Clear(arrfsiEntities, 0, arrfsiEntities.Length);
dirInfo = new System.IO.DirectoryInfo(strLastPathStack.Pop().ToString());
arrfsiEntities = dirInfo.GetFileSystemInfos();
iIndex = 0;
iMaxEntities = arrfsiEntities.Length;
continue;
}
else
{
//Console.WriteLine(arrfsiEntities[iIndex].FullName);
}
iIndex += 1;
} // Whend
dirInfo = null;
Array.Clear(arrfsiEntities, 0, arrfsiEntities.Length);
// Dont try to do move the next line in the loop while/until statement, null reference when pop on an empty stack...
if (strLastPathStack.Count == 0)
break;
dirInfo = new System.IO.DirectoryInfo(strLastPathStack.Pop().ToString());
arrfsiEntities = dirInfo.GetFileSystemInfos();
iIndex = (int)iIndexStack.Pop() + 1;
iMaxEntities = arrfsiEntities.Length;
} // End do
while (true);
return true;
} // End Function IterativeSearch2
public static bool IterativeSearch1(string path)
{
System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(path);
System.IO.FileSystemInfo[] arrfsiEntities = null;
arrfsiEntities = dirInfo.GetFileSystemInfos();
// Creates and initializes a new Stack.
System.Collections.Stack myStack = new System.Collections.Stack();
//Console.WriteLine("Stack is empty when \t stack.count={0}", myStack.Count);
int iIndex = 0;
int iMaxEntities = arrfsiEntities.Length - 1;
do
{
for (iIndex = 0; iIndex <= iMaxEntities; iIndex += 1)
{
if (arrfsiEntities[iIndex].Attributes == System.IO.FileAttributes.Directory)
{
//Console.WriteLine("Searching directory " + arrfsiEntities[iIndex].FullName);
myStack.Push(arrfsiEntities[iIndex].FullName);
}
else
{
//Console.WriteLine("{0}", arrfsiEntities[iIndex].FullName);
}
} // Next iIndex
dirInfo = null;
Array.Clear(arrfsiEntities, 0, arrfsiEntities.Length);
// Dont try to do move the next line in the loop while/until statement, null reference when pop on an empty stack...
if (myStack.Count == 0)
break;
dirInfo = new System.IO.DirectoryInfo(myStack.Pop().ToString());
arrfsiEntities = dirInfo.GetFileSystemInfos();
iIndex = 0;
iMaxEntities = arrfsiEntities.Length - 1;
}
while (true);
return true;
} // End Function IterativeSearch1
//Recursive File and Folder Listing VB.NET
public static bool RecursiveSearch(string path)
{
System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(path);
//System.IO.FileSystemInfo fileObject = default(System.IO.FileSystemInfo);
foreach (System.IO.FileSystemInfo fsiThisEntityInfo in dirInfo.GetFileSystemInfos())
{
if (fsiThisEntityInfo.Attributes == System.IO.FileAttributes.Directory)
{
//Console.WriteLine("Searching directory " + fsiThisEntityInfo.FullName);
RecursiveSearch(fsiThisEntityInfo.FullName);
}
else
{
//Console.WriteLine(fsiThisEntityInfo.FullName);
}
} // Next fiThisFileInfo
return true;
} // End Function RecursiveSearch
// http://forums.asp.net/p/1414929/3116196.aspx
public class TimeFrame
{
public DateTime dtStartTime;
public DateTime dtEndTime;
public TimeFrame(DateTime dtStart, DateTime dtEnd)
{
this.dtStartTime = dtStart;
this.dtEndTime = dtEnd;
} // End Constructor
} // End Class TimeFrame
// Small amount of files
// Iter1 Iter2 Recurs.
// Median 1206.231 3910.367 1232.4079
// Average 1216.431647 3940.147975 1239.092354
// Minimum 1172.5827 3832.0984 1201.2308
// Maximum 1393.4091 4400.4237 1440.3386
public static System.Data.DataTable TestStrategies(string strDirectoryToSearch)
{
System.Data.DataTable dt = new System.Data.DataTable();
System.Collections.Generic.Dictionary<int, string> dictResults = new System.Collections.Generic.Dictionary<int, string>();
dt.Columns.Add("TestRun", typeof(string));
dt.Columns.Add("IterativeSearch1", typeof(double));
dt.Columns.Add("IterativeSearch2", typeof(double));
dt.Columns.Add("RecursiveSearch", typeof(double));
System.Data.DataRow dr = null;
System.Collections.Generic.Dictionary<string, TimeFrame> dictPerformance = null;
for (int i = 0; i < 100; ++i)
{
dr = dt.NewRow();
dr["TestRun"] = i + 1;
dictPerformance = new System.Collections.Generic.Dictionary<string, TimeFrame>();
DateTime startTime;
DateTime endTime;
Console.WriteLine("*********************************************************");
startTime = DateTime.Now;
IterativeSearch1(strDirectoryToSearch);
endTime = DateTime.Now;
dictPerformance.Add("IterativeSearch1", new TimeFrame(startTime, endTime));
Console.WriteLine("*********************************************************");
startTime = DateTime.Now;
IterativeSearch2(strDirectoryToSearch);
endTime = DateTime.Now;
dictPerformance.Add("IterativeSearch2", new TimeFrame(startTime, endTime));
Console.WriteLine("*********************************************************");
startTime = DateTime.Now;
RecursiveSearch(strDirectoryToSearch);
endTime = DateTime.Now;
dictPerformance.Add("RecursiveSearch", new TimeFrame(startTime, endTime));
Console.WriteLine("*********************************************************");
string strResult = "";
foreach (string strKey in dictPerformance.Keys)
{
TimeSpan elapsedTime = dictPerformance[strKey].dtEndTime - dictPerformance[strKey].dtStartTime;
dr[strKey] = elapsedTime.TotalMilliseconds;
strResult += strKey + ": " + elapsedTime.TotalMilliseconds.ToString() + Environment.NewLine;
} // Next
//Console.WriteLine(strResult);
dictResults.Add(i, strResult);
dt.Rows.Add(dr);
} // Next i
foreach(int iMeasurement in dictResults.Keys)
{
Console.WriteLine("Measurement " + iMeasurement.ToString());
Console.WriteLine(dictResults[iMeasurement]);
Console.WriteLine(Environment.NewLine);
} // Next iMeasurement
double[] adblIterSearch1 = dt
.AsEnumerable()
.Select(row => row.Field<double>("IterativeSearch1"))
.ToArray();
double[] adblIterSearch2 = dt
.AsEnumerable()
.Select(row => row.Field<double>("IterativeSearch2"))
.ToArray();
double[] adblRecursiveSearch = dt
.AsEnumerable()
.Select(row => row.Field<double>("RecursiveSearch"))
.ToArray();
dr = dt.NewRow();
dr["TestRun"] = "Median";
dr["IterativeSearch1"] = Median<double>(adblIterSearch1);
dr["IterativeSearch2"] = Median<double>(adblIterSearch2);
dr["RecursiveSearch"] = Median<double>(adblRecursiveSearch);
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["TestRun"] = "Average";
dr["IterativeSearch1"] = dt.Compute("Avg(IterativeSearch1)", string.Empty);
dr["IterativeSearch2"] = dt.Compute("Avg(IterativeSearch2)", string.Empty);
dr["RecursiveSearch"] = dt.Compute("Avg(RecursiveSearch)", string.Empty);
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["TestRun"] = "Minimum ";
dr["IterativeSearch1"] = dt.Compute("Min(IterativeSearch1)", string.Empty);
dr["IterativeSearch2"] = dt.Compute("Min(IterativeSearch2)", string.Empty);
dr["RecursiveSearch"] = dt.Compute("Min(RecursiveSearch)", string.Empty);
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["TestRun"] = "Maximum ";
dr["IterativeSearch1"] = dt.Compute("Max(IterativeSearch1)", string.Empty);
dr["IterativeSearch2"] = dt.Compute("Max(IterativeSearch2)", string.Empty);
dr["RecursiveSearch"] = dt.Compute("Max(RecursiveSearch)", string.Empty);
dt.Rows.Add(dr);
return dt;
} // End Sub TestMain
public static double Median<T>(T[] numbers)
{
int numberCount = numbers.Count();
if (numberCount == 0)
return 0.0;
int halfIndex = numbers.Count() / 2;
var sortedNumbers = numbers.OrderBy(n => n);
double median;
if ((numberCount % 2) == 0)
{
median =
(
(
System.Convert.ToDouble(sortedNumbers.ElementAt<T>(halfIndex)) +
System.Convert.ToDouble(sortedNumbers.ElementAt<T>((halfIndex - 1))
)
) / 2);
}
else
{
median = System.Convert.ToDouble(sortedNumbers.ElementAt<T>(halfIndex));
}
return median;
} // End Function GetMedian
// http://msmvps.com/blogs/deborahk/archive/2010/05/07/linq-mean-median-and-mode.aspx
public static double CalcMedian(int[] numbers)
{
int numberCount = numbers.Count();
int halfIndex = numbers.Count() / 2;
var sortedNumbers = numbers.OrderBy(n => n);
double median;
if ((numberCount % 2) == 0)
{
median = ((sortedNumbers.ElementAt(halfIndex) +
sortedNumbers.ElementAt((halfIndex - 1))) / 2);
}
else
{
median = sortedNumbers.ElementAt(halfIndex);
}
return median;
} // End Function CalcMedian
} // End Class SearchStrategy
} // End Namespace IterativeDirectoryCSharp
答案 5 :(得分:0)
如果您选择使用递归,我找到了一个可能与您当前使用的示例相近的示例,以消除任何歧义。
// Process only directories under dir
public static void visitAllDirs(File dir) {
if (dir.isDirectory()) {
process(dir);
String[] children = dir.list();
for (int i=0; i<children.length; i++) {
visitAllDirs(new File(dir, children[i]));
}
}
}
这是一个非常简单的示例,process()
可以是您在目录上处理或操作的地方。
答案 6 :(得分:0)
派对,谢谢你的建议。我改变了你的代码,这就是我所拥有的
private ArrayList<File> displayDirectory(File node){
ArrayList<File> FileList = new ArrayList();
ArrayList <File>directories = new <File>ArrayList();
if (node.isDirectory())
directories.add(node);
// Iterate over the directory list
Iterator it = directories.iterator();
for (int i = 0 ; i < directories.size();i++){
File dir = directories.get(i);
// get childs
String[] subNode = dir.list();
for(int j = 0 ; j < subNode.length;j++){
File F = new File( directories.get(i).getAbsolutePath(), subNode[j]);
// display current child name
// System.out.println(F.getAbsoluteFile());
// if directory : add current child to the list of dir to process
if (F.isDirectory()) directories.add(F);
else FileList.add(F);
}
}
return FileList;
}
答案 7 :(得分:0)
基于PATRY Guillaume解决方案
public static List<File> getFolderTree(File node)
{
List<File> directories = new ArrayList();
if (node.isDirectory())
{
directories.add(node);
}
for(int i=0; i<directories.size(); i++)
{
File dir = directories.get(i);
String[] subNote = dir.list();
for (String filename : subNote)
{
File subNode = new File(dir, filename);
if (subNode.isDirectory())
{
directories.add(subNode);
}
}
}
return directories;
}