الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

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

بدأه محمد رضى في 28 مارس 2011 · 5 رد · 1,628 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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

هذا كود برنامج بسيط من نوع 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
#2

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

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

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

#3

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

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

#4

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

شكرا لجهودك

+1

---------

وبالنسبة لل JCreator

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

---

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

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

#5

10/10 :)

تسلم ايدك

شغل جميل

Software Developer
Mahmoudkelany.com


 

#6

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

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

مواضيع مشابهة