• 0
محمد رضى

كود برنامج Duplicated Files Finder بسيط

سؤال

السلام عليكم و رحمة الله تعالى و بركاته...

هذا كود برنامج بسيط من نوع Duplicated Files Finder يقوم بالبحث داخل مجلد(ات)/وحدات تخزين بحثا عن الملفات المكررة عن طريق حساب hash code لكل ملف يجده و تخزينها بطريقة تمكنه من التعرف على الملفات المكررة حتى لو كانت متواجدة في أماكن متفرقة في وحدة التخزين أو المجلد.

البرنامج كتبته للتسلية فقط, و أضعه بين أيديكم عسى أن يفيد...

الكود مكون من ثلاث فئات.

الفئة الأولى AsyncFileFinder تقوم بالبحث عن الملفات...


/**
* @(#)AsyncFileFinder.java
*
*
* @author Mohamed Rida
*/

import java.util.*;
import java.io.*;

public class AsyncFileFinder {

private static final int FIFO_MAX = 10;

private String startPath = "";
private String regex = ".*";
private int fifoMax = FIFO_MAX;
private boolean aborted = false;
private boolean subDir = false;
private boolean running = false;
private boolean finished = false;
private boolean started = false;
private boolean caseSens = false;
private LinkedList<String> queue = new LinkedList<String>();
private Object synch = new Object();

/**
*/
public AsyncFileFinder(String path, String rgx) throws FileNotFoundException, UnsupportedOperationException {
File file = new File(path);
if(!file.exists()) throw new FileNotFoundException("Folder [" + path + "] not found!");
if(!file.isDirectory()) throw new UnsupportedOperationException("Path [" + path +"] must be a folder");
startPath = path;
regex = rgx.toLowerCase();
}

/**
*/
public AsyncFileFinder(String path, String rgx, boolean subDir) throws FileNotFoundException, UnsupportedOperationException {
this(path, rgx);
this.subDir = subDir;
}

/**
*/
public AsyncFileFinder(String path, String rgx, boolean subDir, boolean caseSens) throws FileNotFoundException, UnsupportedOperationException {
this(path, rgx);
this.subDir = subDir;
this.caseSens = caseSens;
if(caseSens) regex = rgx;
}

/**
*/
public void setQueueMaxLength(int length) throws IllegalArgumentException {
if(length <= 0) throw new IllegalArgumentException("The new queue length must be greater than 0!");
fifoMax = length;
}

public int getQueueMaxLength() { return fifoMax; }
public void abort() { aborted = true; }
public boolean isRunning() { return running; }
public boolean isAborted() { return aborted; }
public boolean isFinished() { return finished; }
public boolean hasNext() { return queue.size() > 0; }

/**
*/
public void start() throws UnsupportedOperationException {
boolean b = started || aborted || finished || running;
if(b) throw new UnsupportedOperationException("Cannot start now! Please use a new AsyncFileFinder object.");

started = true;
new Thread() {
@Override
public void run() {
running = true;
FindIntoNextFolder(startPath);
running = false;
finished = true;
synchronized(AsyncFileFinder.this) { // Wake up owner, we've finished...
AsyncFileFinder.this.notifyAll();
}
}
}.start();
}

/**
*/
private void FindIntoNextFolder(String path) {
if(aborted) return;
File dir = new File(path);
File[] files = dir.listFiles();
if(files != null) {
for(File f: files) {
if(f.isFile()) {
String name = f.getName();
if(!caseSens) name = name.toLowerCase();
if(name.matches(regex)) {
// TODO : Add support for raising an event when a file is found
while(queue.size() >= fifoMax) {
synchronized(this) { // Notify owner to process new found files
this.notifyAll();
}
//System.out.println(System.currentTimeMillis() + " : Queue is full! Waiting on synch...");
try {
synchronized(synch) { // Queue is full, wait...
synch.wait(100);
}
} catch(InterruptedException ex) {}
//System.out.println(System.currentTimeMillis() + " : synch is woken up.");
}
synchronized(queue) {
queue.addFirst(f.getAbsolutePath());
}
synchronized(this) { // Notify owner to process new found files
this.notifyAll();
}
}
}
}
if(subDir) {
for(File f: files) {
if(f.isDirectory()) {
FindIntoNextFolder(f.getAbsolutePath());
}
}
}
}
}

/**
*/
public String peekFile() {
String path = null;
if(queue.size() > 0) {
synchronized(queue) {
path = queue.removeLast();
}
}
synchronized(synch) { // Notify search thread to continue
synch.notifyAll();
}
return path;
}

/**
*/
public static String fileFilterToRegEx(String filter) {
return filter.replace(".", "\\.").replace("*", ".*").replace("?", ".").replace(";", "|");
}
}

الفئة الثانية تقوم بعملية التعرف على الملفات المكررة :


/**
* @(#)AsyncFileFinder.java
*
*
* @author Mohamed Rida
*/

import java.util.*;
import java.io.*;
import java.security.*;


public class DuplicateFinder extends Thread {
private final int MAX_THREADS = 10;

private int maxThreads = MAX_THREADS;
private Hashtable filesSig = new Hashtable();
private int files = 0; // Processed files
private int errors = 0; // Errors count
private boolean started = false;
private boolean running = false;
private boolean aborted = false;
private boolean finished = false;
private AsyncFileFinder finder = null;
private int threadsCount = 0; // Current threads count
private Object freeThread = new Object(); // Wait on if threadsCount = maxThreads

public boolean isStarted() { return started; }
public boolean isRunning() { return running; }
public boolean isAborted() { return aborted; }
public boolean isFinished() { return finished; }
public void abort() { aborted = started && running; }
public int getProcessedFilesCount() { return files; }
public int getErrorsCount() { return errors; }

/**
*/
public DuplicateFinder(String folder) throws UnsupportedOperationException, FileNotFoundException {
File f = new File(folder);
if(!f.isDirectory()) throw new UnsupportedOperationException("[" + folder + "] is not a valid folder!");
if(!f.exists()) throw new FileNotFoundException("[" + folder + "] does not exist!");
finder = new AsyncFileFinder(folder, ".*", true); // Search for all files including sub directories
}

/**
*/
public DuplicateFinder(String folder, int threads) throws UnsupportedOperationException, FileNotFoundException {
this(folder);
maxThreads = threads;
}

/**
*/
@Override
public void run() {
started = true;
running = true;
finder.start();
while(!aborted && (!finder.isFinished() || finder.hasNext())) {
if(finder.hasNext()) {
final String path = finder.peekFile();
// Do we have a free thread
while(threadsCount >= maxThreads) {
synchronized(freeThread) {
try {
freeThread.wait();
} catch(InterruptedException ex) {}
}
}
// Process peeked file
threadsCount++;
new Thread() {
@Override
public void run() {
boolean b = processFile(path);
files += b ? 1 : 0;
errors += b ? 0 : 1;
threadsCount--;
synchronized(freeThread) {
freeThread.notifyAll();
}
}
}.start();
} else {
synchronized(finder) { // Wait for a new found files
try {
finder.wait();
} catch(InterruptedException ex) {}
}
}
}
while(threadsCount > 0) { // Wait for threads to terminate
synchronized(freeThread) {
try {
freeThread.wait();
} catch(InterruptedException ex) {}
}
}
running = false;
finished = true;
synchronized(this) { // Wake up owner
this.notifyAll();
}
}

/**
*/
private boolean processFile(String fileName) {
try {
System.out.println(fileName);
// Get file Hash string
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName));
DigestInputStream dis = new DigestInputStream(bis, MessageDigest.getInstance("SHA1"));
while(dis.read() != -1);
byte[] h = dis.getMessageDigest().digest();
Formatter frmt = new Formatter();
for(byte b : h) frmt.format("%02x", b);
String hash = frmt.toString();
// Check if it is duplicated
synchronized(filesSig) {
ArrayList al = (ArrayList)filesSig.get(hash);
if(al != null) { // Duplicated
synchronized(al) {
al.add(fileName);
}
} else { // Not yet! We'll see if it is
al = new ArrayList();
al.add(fileName);
filesSig.put(hash, al);
}
}
} catch(Exception ex) {
ex.printStackTrace();
return false;
}
return true;
}

/**
*/
public void printScanResult() throws IllegalStateException {
if(!finished) throw new IllegalStateException("DuplicateFinder scan is still running!..");
for(Enumeration e = filesSig.keys(); e.hasMoreElements(); ) {
String hash = (String)e.nextElement();
ArrayList al = (ArrayList)filesSig.get(hash);
if(al.size() > 1) { // Duplicated entry
System.out.println(hash); // Hash
for(int i = 0; i < al.size(); i++) {
System.out.println((String)al.get(i)); // Duplicated file names
}
System.out.println("====================\n");
}
}
}
}

الفئة الثالثة هي فئة التطبيق :

الكود الذي تم تحويله إلى تعليق هو لتجربة الفئة أعلاه في البحث عن ملفات.


/**
* @(#)test.java
*
* test application
*
* @author Mohamed Rida
* @version 1.00 2011/3/25
*/

public class test {

public static void main(String[] args) throws java.io.FileNotFoundException {
DuplicateFinder dupf = new DuplicateFinder(args[0]);
dupf.start();
synchronized(dupf) {
try {
dupf.wait();
} catch(InterruptedException ex) {}
}
System.out.println("\n==========");
System.out.println("Scan result for : " + args[0]);
System.out.println("==========");
dupf.printScanResult();
System.out.println("Files processed : " + dupf.getProcessedFilesCount());
System.out.println("Errors occured : " + dupf.getErrorsCount());
/*
System.out.println("Path : " + args[0] + "\nFilter : " + args[1] + "\n");
AsyncFileFinder finder = new AsyncFileFinder(args[0], AsyncFileFinder.fileFilterToRegEx(args[1]), true);
finder.start();
String path = "";
do {
if(finder.hasNext()) {
path = finder.peekFile();
// Work with the file...
System.out.println(path);
} else {
//System.out.println(System.currentTimeMillis() + " : Queue is empty! Waiting on finder...");
synchronized(finder) {
try {
finder.wait(); // Wait for a new found file
} catch(InterruptedException ex) {}
}
//System.out.println(System.currentTimeMillis() + " : finder is woken up.");
}
} while(!finder.isFinished());
System.out.println("\n====\nProgram successfully terminated.");
*/
}
}

أمضيت ساعة كاملة أكتب تعاليق باللغة العربية على الكود لكن اكتشفت بعد فوات الأوان أن JCreator LE لا يدعم UNICODE!

test.rar

2

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

5 إجابة على هذا السؤال .

  • 0

يعطيك صحة على هذا العمل فكرة برنامج جيدة

يمكنك أن تراسل أخ علاء و يضعه في قسم الموضيع المميزة لكي يستفيد الجميع

وبارك الله فيك على مجهود

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

بارك الله فيك أخي محمد :)

الجافا لغة برمجة رائعة خالية من التعقيدات الأمر الذي يجعلني دائما استمتع بتطوير مشاريع بسيطة بها في أوقات الفراغ حتى لا أنسى ما تعلمته.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

هذه الفكرة لدي من سنين ، لايجاد ملفات ال MP3 المكررة، لكنني لم انفذها، وانت اوجدت اداة مفيدة لي جدا

شكرا لجهودك

+1

---------

وبالنسبة لل JCreator

اعتقد انه عليك تغيير نوع الخط ليستقبل العربية

---

تم اضافتها للمواضيع المميزة تحت قسم المشاريع :ph34r:

تخطينا حدود علاء الصالحي

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

10/10 :)

تسلم ايدك

شغل جميل

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

شكرا لكم على هذه الردود الطيبة :)

بارك الله فيكم

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .