Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.IO;
- using System.Security.Cryptography;
- using System.Text;
- using System.Threading;
- using System.Windows.Forms;
- namespace Duplicate_File_Finder
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
- private void Form1_Load(object sender, EventArgs e)
- {
- // At the Form1_Load I made sure that the groupbox was not enabled until the checkbox "cbxSearchByFileType" was checked.
- // I also made sure the Treeview would have checkboxes (to enable easy deletion of the files)
- gbxSearchByFiletype.Enabled = false;
- txtSearchLocation.Enabled = false;
- Duplicates.CheckBoxes = true;
- pgbProgress.Minimum = 0;
- pgbProgress.Maximum = 100;
- }
- Hashtable fileHashes; //A hashtable to hold the hashes of every file.
- List<string> fileEntries; //A List to hold the path of every file
- double bytesWasted; //A double to count the bytes that are wasted because of duplicates.
- #region Controls
- private void cbxSearchByFileType_CheckedChanged(object sender, EventArgs e)
- {
- //This if/else statement checks if the Checkbox is checked, if it is, the groupbox should enable, if not, the groupbox should disable.
- if (cbxSearchByFileType.Checked == true)
- {
- gbxSearchByFiletype.Enabled = true;
- }
- else
- {
- gbxSearchByFiletype.Enabled = false;
- }
- }
- private void btnSearchLocation_Click(object sender, EventArgs e)
- {
- //Opens a folderdialog to specify the path to search for duplicates.
- FolderBrowserDialog dialog = new FolderBrowserDialog();
- DialogResult result = dialog.ShowDialog();
- if (result == DialogResult.OK)
- {
- txtSearchLocation.Text = dialog.SelectedPath.ToString();
- }
- }
- private void DeleteFiles_Click(object sender, EventArgs e)
- {
- //This loops through all nodes in the Treeview Duplicates to check if the checkbox is checked, if it is, it deletes the file.
- foreach (TreeNode node in Duplicates.Nodes)
- {
- for (int i = 0; i < node.GetNodeCount(false); i++)
- {
- if (node.Nodes[i].Checked == true)
- {
- File.Delete(node.Nodes[i].Text);
- node.Nodes[i].Remove();
- }
- }
- }
- }
- private void searchDups_Click(object sender, EventArgs e)
- {
- //Whenever the button "Find Duplicates" is pressed, we make sure that all variables is clean
- //Then we start a thread to do the work.
- ClearVariables();
- Thread t = new Thread(new ThreadStart(DoWork));
- t.IsBackground = true;
- t.Start();
- }
- #endregion
- #region DoWork Function
- private void DoWork()
- {
- //Check if any path is specified
- if (txtSearchLocation.Text.Length == 0)
- {
- MessageBox.Show("You have to specify a directory to scan", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
- }
- else
- {
- //Check if the "Search By filetype" is checked, and which filetypes they want to search for
- if (cbxSearchByFileType.Checked == true)
- {
- //A LOT of If statements to check which checkboxes are checked.
- if (cbxAudioSearch.Checked == true)
- {
- //This pattern repeats throughout all the if-statements
- //Create a try-catch to catch the error if we don't have access to the specified path
- try
- {
- //Create some arrays to hold all the files + path to the file
- string[] audioFiles = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.wav", SearchOption.AllDirectories);
- string[] audioFiles2 = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.mp3", SearchOption.AllDirectories);
- //Loop through the arrays and add the strings to the list "FileEntries"
- foreach (string audio in audioFiles)
- {
- fileEntries.Add(audio);
- }
- foreach (string audio in audioFiles2)
- {
- fileEntries.Add(audio);
- }
- }
- catch (UnauthorizedAccessException UAX)
- {
- MessageBox.Show(UAX.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
- }
- }
- if (cbxDocumentSearch.Checked == true)
- {
- try
- {
- string[] documentFiles = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.txt", SearchOption.AllDirectories);
- string[] documentFiles2 = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.doc", SearchOption.AllDirectories);
- string[] documentFiles3 = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.rtf", SearchOption.AllDirectories);
- foreach (string document in documentFiles)
- {
- fileEntries.Add(document);
- }
- foreach (string document in documentFiles2)
- {
- fileEntries.Add(document);
- }
- foreach (string document in documentFiles3)
- {
- fileEntries.Add(document);
- }
- }
- catch (UnauthorizedAccessException UAX)
- {
- MessageBox.Show(UAX.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
- }
- }
- if (cbxPictureSearch.Checked == true)
- {
- try
- {
- string[] pictureFiles = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.jpg", SearchOption.AllDirectories);
- string[] pictureFiles2 = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.jpeg", SearchOption.AllDirectories);
- string[] pictureFiles3 = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.bmp", SearchOption.AllDirectories);
- string[] pictureFiles4 = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.png", SearchOption.AllDirectories);
- string[] pictureFiles5 = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.gif", SearchOption.AllDirectories);
- foreach (string picture in pictureFiles)
- {
- fileEntries.Add(picture);
- }
- foreach (string picture in pictureFiles2)
- {
- fileEntries.Add(picture);
- }
- foreach (string picture in pictureFiles3)
- {
- fileEntries.Add(picture);
- }
- foreach (string picture in pictureFiles4)
- {
- fileEntries.Add(picture);
- }
- foreach (string picture in pictureFiles5)
- {
- fileEntries.Add(picture);
- }
- }
- catch (UnauthorizedAccessException UAX)
- {
- MessageBox.Show(UAX.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
- }
- }
- if (cbxVideoSearch.Checked == true)
- {
- try
- {
- string[] videoFiles = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.mp4", SearchOption.AllDirectories);
- string[] videoFiles2 = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.mkv", SearchOption.AllDirectories);
- string[] videoFiles3 = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*.avi", SearchOption.AllDirectories);
- foreach (string video in videoFiles)
- {
- fileEntries.Add(video);
- }
- foreach (string video in videoFiles2)
- {
- fileEntries.Add(video);
- }
- foreach (string video in videoFiles3)
- {
- fileEntries.Add(video);
- }
- }
- catch (UnauthorizedAccessException UAX)
- {
- MessageBox.Show(UAX.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
- }
- }
- if (txtCustomFileType.Text.Length != 0)
- {
- try
- {
- string[] customFiles = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*." + txtCustomFileType.Text, SearchOption.AllDirectories);
- foreach (string customFile in customFiles)
- {
- fileEntries.Add(customFile);
- }
- }
- catch (UnauthorizedAccessException UAX)
- {
- MessageBox.Show(UAX.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
- }
- }
- }
- //If they didn't want to search by filetype
- else
- {
- //Same pattern as before with the try-catch
- try
- {
- //and the arrays. But here there is an option to search all files by just entering "*"
- string[] files = Directory.GetFileSystemEntries(txtSearchLocation.Text, "*", SearchOption.AllDirectories);
- foreach (string file in files)
- {
- fileEntries.Add(file);
- }
- }
- catch (UnauthorizedAccessException UAX)
- {
- MessageBox.Show(UAX.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
- }
- }
- //Then we loop through each file in "FileEntries"
- for (int i = 0; i < fileEntries.Count; i++)
- {
- //Calls "CreateHash" to get our hash
- string hash = CreateHash(fileEntries[i]);
- //Check if we actually got a hash
- if (hash != "")
- {
- //Call "SearchDups" to check for duplicates
- string duplicateFile = SearchDups(hash);
- if (duplicateFile != "")
- {
- //If there was a duplicate, calculate the percentage of completion and call "AddNodes"
- int percentage = Convert.ToInt32(i * 100 / fileEntries.Count);
- AddNodes("FILL", fileEntries[i], duplicateFile, hash, percentage);
- }
- //At last, we add the new hash to our hashtable
- fileHashes.Add(fileEntries[i], hash);
- }
- }
- //When the loop is completed we once again call "AddNodes" with the argument "PROGRESSCOMPLETED" to indicate that we're done.
- AddNodes("PROGRESSCOMPLETED", string.Empty, string.Empty, string.Empty, 0);
- }
- }
- #endregion
- #region CrossThread Stuff
- //This is the cross-threading part, I've actually never really tried this before, so this was a new concept for me in this competition.
- //We create a delegate to invoke our calls to the controls in the main-thread
- private delegate void AddNodesDel(string arg, string newFile, string oldFile, string hash, int percentage);
- //And the function "AddNodes"
- public void AddNodes(string arg, string newFile, string oldFile, string hash, int percentage)
- {
- //This is self-explanatory, if there's required an invoke, we create a new AddNodesDel delegate to invoke our calls
- if (InvokeRequired)
- {
- Invoke(new AddNodesDel(AddNodes), new object[] { arg, newFile, oldFile, hash, percentage });
- }
- else
- {
- //Switch the string "arg" to check what to do
- switch (arg)
- {
- //If the progress is completed, indicate it by completely filling the ProgressBar
- case "PROGRESSCOMPLETED":
- pgbProgress.Value = 100;
- break;
- //If we want to "fill" our treeview
- case "FILL":
- //Create a new array of treenodes to check if we can find a matching hash somewhere
- TreeNode[] nodes = Duplicates.Nodes.Find(hash, true);
- if (nodes.Length != 0)
- {
- //If we could we loop through the nodes with the same hash (even though there should only be one) add the new file to the treeview and update the Byteswasted label
- for (int p = 0; p < nodes.Length; p++)
- {
- nodes[p].Nodes.Add(newFile);
- lblWastingBytes.Text = String.Format("{0:0.00}", ((bytesWasted / 1024.0) / 1024.0)) + " MB";
- }
- }
- else
- {
- //If we couldn't find the hash in the treeview, we create a new node with the two duplicates as children and update the Bytewasted label
- TreeNode newNote = new TreeNode();
- newNote.Text = hash.ToUpper();
- newNote.Name = hash;
- newNote.ForeColor = System.Drawing.Color.DarkRed;
- newNote.Nodes.Add(newFile);
- newNote.Nodes.Add(oldFile);
- Duplicates.Nodes.Add(newNote);
- lblWastingBytes.Text = String.Format("{0:0.00}", ((bytesWasted / 1024.0) / 1024.0)) + " MB";
- }
- //At last we update the Progressbar
- pgbProgress.Value = percentage;
- break;
- }
- }
- }
- #endregion
- #region User defined functions
- //This function clears all controls and variavbles that needs clearing.
- private void ClearVariables()
- {
- fileHashes = new Hashtable();
- fileEntries = new List<string>();
- bytesWasted = 0.0;
- lblWastingBytes.Text = String.Empty;
- Duplicates.Nodes.Clear();
- pgbProgress.Value = 0;
- }
- //This function loops through the hashtable to see if there is any duplicates of the hash in there, if there is it returns the filename of the duplicate of the hash.
- public string SearchDups(string hash)
- {
- IDictionaryEnumerator en = fileHashes.GetEnumerator();
- while (en.MoveNext())
- {
- if (hash == en.Value.ToString())
- {
- return en.Key.ToString();
- }
- }
- return "";
- }
- //This function gets a filepath as argument
- public string CreateHash(string filePath)
- {
- //Create a new SHA256 hash creator (Sorry, I don't know what to call it?)
- SHA256 shaM = new SHA256Managed();
- try
- {
- //Filestream opens the filepath
- FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read);
- //Compute a hash of the bytes in the file
- byte[] result = shaM.ComputeHash(file);
- StringBuilder builder = new StringBuilder();
- foreach (byte b in result)
- {
- //Loop through each byte in the result and append it to the string, and a trick HSP teached me to add the "x2" to make it HEX values.
- builder.Append(b.ToString("x2"));
- }
- //store the hash
- string hash = builder.ToString();
- //And if the hashtable contains the hash, we might as well add the bytes to byteswasted while the file is open allready.
- if (fileHashes.ContainsValue(hash)) { bytesWasted += file.Length; }
- //Close off and return the hash.
- builder.Clear();
- file.Close();
- return hash;
- }
- //Catch to control if there is any file (There should be, but just in case)
- catch (FileNotFoundException ex)
- {
- MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
- return "";
- }
- //Catch to see if we don't have authorization to access the file
- catch (UnauthorizedAccessException)
- {
- return "";
- }
- }
- #endregion
- }
- }
Add Comment
Please, Sign In to add comment