楼主可能对Set有误解, 看看javadoc: public interface Set extends Collection A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element.比较的规则不确定,自己实现equals方法就是了如果使用HashSet,则麻烦在于除了要覆盖equals方法, 还要根据用户定义的规则调整生成文件名的hasCode的算法, HashSet实际上调用HashMap的containsKey方法, 即首先是基于hashCode实现查找(缩小查找范围), 然后再调用equals比较.
把 600 个文件名存在数组或是 List 里,再比较,应该会快一些。
但这样我这个程序就不能比较两个盘中是不是有多余的文件了
一个盘可是有上万个文件啊,这样比较下去,一天也完不成啊!!!!!
比较字符串,只需要比较对象的地址就可以了,这个速度可就飞快了!!!!!谁能够证实一下!!!!!!!!
谢谢!!!!!!
String[] files = dir.list();
HashSet set = new HashSet(600);
for(int i=0; i<files.length; i++)
{
if(set.contains(files[i]))
System.out.println("file exist:" + files[i]);
else
set.add(files[i]);
}
File dir2 = new File("C:\\");HashSet set = new HashSet(600);String[] files1 = dir1.list();
for(int i=0; i<files1.length; i++)
{
if(set.contains(files1[i]))
System.out.println("file exist:" + files1[i]);
else
set.add(files1[i]);
}String[] files2 = dir2.list();
for(int i=0; i<files2.length; i++)
{
if(set.contains(files2[i]))
System.out.println("file exist:" + files2[i]);
else
set.add(files2[i]);
}
File dir2 = new File("C:\\WINNT");C:\WINNT\system32目录有2081个目录和文件
C:\WINNT目录有188个目录和文件执行时间: 70毫秒
我用最简单的遍历的结果:public class Test {
static int COUNT = 0;
public static void findFile(File dir, String filename) {
File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
findFile(files[i], filename);
} else {
COUNT++;
if (files[i].getName().equals(filename)) {
System.out.println("Got it: " + files[i].getAbsolutePath());
}
}
}
} public static void main(String[] args) {
String NAME = "acpi.sys";
File dir = new File("C:\\Windows");
long time1 = System.currentTimeMillis();
findFile(dir, NAME);
long time2 = System.currentTimeMillis();
System.out.println("Total time " + (time2 - time1));
System.out.println("Total files " + COUNT);
}
}输出:Got it: C:\Windows\system32\drivers\acpi.sys
Total time 750
Total files 7056而且硬盘还是星钻的
{
public static void main(String[] args)
{
String str1 = "This is a very long string!99999999999999999999999999999999999999999999999999999999999999999999999999999";
String str2 = "This is a very long string!999999999999999999999999999999999999999999999999999999999999999999999999999990"; System.out.println("Begin test...");
System.out.println(System.currentTimeMillis() + "");
System.out.println(new Date()); for (int i=0; i<100000000; i++)
{
str1.equals(str2);
}
System.out.println("End test.");
System.out.println(System.currentTimeMillis() + "");
System.out.println(new Date());
}
}试试这个测试程序,1亿次比较,看花多久?
要知道两个字符串相同的部分是很长的,否则要快几十倍。
用VC写同样的程序,一点也不会比java快!
1.列文件清单是非常快的,我自己使用的递归算法,列一个目录(包括子目录)里的文件,经测试,10000个文件全部列出来,并分别构建成 File 类放到一个 List中 ,需要的时间也就只有不到 2S 中的时间.2.程序的真正的性能瓶颈在比较上,我这个程序不是查找某一个文件,而是在一堆文件中查找"相同"的文件(这个相同是由一些用户自己定义的规则来判断的).所以比较的次数是几何增长的. 比如:1000 个文件,每个文件两两都要比较一次,共需比较 1000*500=500000 次.这个数字已经很大了,在我的 P4 上就需要 3-4 分钟了.要是文件数达到 10000 个,比较次数为 10000*5000 = 50000000,一共要 5000万次,这就得好几个钟头了. 要是文件总数达到 10万(谁的硬盘里没有 10 多万个文件),就是不可能完成的任务了.3.关于各位提到了排序,因为这个文件的列表是由具体的用户指定的,也就是具有不确定性.因此可以肯定,10000个文件以下,排序肯定比遍历来得慢.4.使用 Set 来实现(因为 Set 中的对象不能相同).但这是不能用的,不信大家可以试试,大家可创建两个内容相同的不同对象,一样可以添加到 Set 中,也就是说,Set 只会比较是不是同一个对象,而不会去比较对象的内容是不是相同.而且我这里的文件名的比较规则,也并不是要求一摸一样,规则可以用户自己定制.
支持楼主!!!
开多个线程试试,
主线程用于进行比较,
其它的线程用于罗列目录,
并放入容器。
public interface Set extends Collection
A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element.比较的规则不确定,自己实现equals方法就是了如果使用HashSet,则麻烦在于除了要覆盖equals方法, 还要根据用户定义的规则调整生成文件名的hasCode的算法, HashSet实际上调用HashMap的containsKey方法, 即首先是基于hashCode实现查找(缩小查找范围), 然后再调用equals比较.
import java.util.HashMap;public class DuplicateFileCheck
{
private HashMap checkMap = new HashMap();
private HashMap counterMap = new HashMap(); public void check(File dir, boolean recursive)
{
Counter counter = new Counter();
counterMap.put(dir, counter);
check(dir, counter, recursive);
} public void reset()
{
counterMap.clear();
checkMap.clear();
} public int getFileCount(File dir)
{
Counter counter = (Counter) counterMap.get(dir);
return counter.count;
} public int getDistinctCount()
{
return checkMap.size();
} private void check(File file, Counter counter, boolean recursive)
{
if(file.isDirectory())
checkDir(file, counter, recursive);
else
checkFile(file, counter);
} private void checkDir(File dir, Counter counter, boolean recursive)
{
File[] files = dir.listFiles();
for(int i=0; i<files.length; i++)
{
File file = files[i];
if(file.isFile())
{
checkFile(file, counter);
}
else
{
if(recursive)
{
check(file, counter, recursive);
}
}
}
} private void checkFile(File file, Counter counter)
{
counter.count++;
Object key = createCheckKey(file);
File exist = (File) checkMap.get(key);
if(exist != null)
{
System.out.println("file duplicate:" + file.getAbsolutePath() + " <--> " + exist.getAbsolutePath());
}
else
{
checkMap.put(key, file);
}
} protected Object createCheckKey(File file)
{
return new CheckKey(file);
} private static class Counter
{
int count = 0;
} private static class CheckKey
{
private String filename; public CheckKey(File file)
{
this.filename = file.getName();
} public boolean equals(Object obj)
{
CheckKey other = (CheckKey) obj;
return filename.equals(other.filename);
} public int hashCode()
{
return filename.hashCode();
} public String toString()
{
return filename.toString();
}
} public static void main(String[] args) throws Exception
{
File[] dirs = new File[]{
new File("C:\\WINNT"),
new File("D:\\temp"),
new File("D:\\share")
}; DuplicateFileCheck checker = new DuplicateFileCheck();
boolean recursive = true; //是否包含子目录 long startTime = System.currentTimeMillis();
for(int i=0; i<dirs.length; i++)
checker.check(dirs[i], recursive);
long endTime = System.currentTimeMillis(); int totalCount = 0;
for(int i=0; i<dirs.length; i++)
{
int count = checker.getFileCount(dirs[i]);
totalCount += count;
System.out.println(dirs[i] + "下的文件数:" + count);
}
System.out.println("总文件数:" + totalCount);
System.out.println("不重复的文件数:" + checker.getDistinctCount()); System.out.println("耗时:" + (endTime - startTime));
}
}运行结果:C:\WINNT下的文件数:8724
D:\temp下的文件数:1422
D:\share下的文件数:3436
总文件数:13582
不重复的文件数:10368
耗时:3054修改方法createCheckKey()或类CheckKey即可实现不同的比较策略
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++]) {
return false;
}
}
return true;
}
}
return false;
}楼主觉得还能优化?
问题的关键在于减少比较次数,建议楼主找一本算法方面的书,看一下排序算法和二分查找算法。
根据 cbhyk 的提示,我找到了快速的算法!!就是:一边添加文件列表,一边比较和排序,这样列表里的文件就是排序好了的
查找起来就快多了!!!现在结帖,发分!!!
cbhyk 就请到另一个帖子,单独领分!!!!!1如果大家有空,帮我看看我的另一个帖子!!
http://expert.csdn.net/Expert/TopicView1.asp?id=2929280
谢谢!!
我老是想,java的字符串比较速度怎么可能比C/C++还快呢,String的equals方法是下面这个样子的:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}里面有个instanceof操作,有个类型转换,而且数组的访问是有运行期越界检查的,怎么可能比C/C++快嘛!
定睛一看,有这么个判断:
int n = count;
if (n == anotherString.count) {
因为java String的长度是构造String时就已经计算好的,那么,不同长度的String肯定不相等,根本不需要比较(在求String的长度和比较不等长String时java和Pascal相似,比C高效),而我上面给的两个String恰恰不等长!所以说速度很快,比VC编译的同样的C程序还快。但是,当把第一个String改为和第二个一样长,末尾为“1”后,整个执行时间变成了10多分钟,效率不到C的10分之一!