Click here to Skip to main content
15,892,809 members
Articles / Desktop Programming / WPF

Find Duplicate Files and Delete Them

Rate me:
Please Sign up or sign in to vote.
3.91/5 (21 votes)
1 Sep 2012CPOL2 min read 89.2K   5K   39  
Application for seaching similar kinds of files in different folders.
namespace FindDuplicateFile
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Forms;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class DuplicateFileFinder : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

        }

        /// <summary>
        /// get or set this flag to indicate searching through Hash or through file length.
        /// </summary>
        private bool isHashSearch;

        public bool IsHashSearch
        {
            get { return isHashSearch; }
            set { isHashSearch = value; OnPropertyChanged("IsHashSearch"); }
        }

        /// <summary>
        /// Background worker object
        /// </summary>
        private System.ComponentModel.BackgroundWorker backgroundWorker = new System.ComponentModel.BackgroundWorker();

        /// <summary>
        /// Private variable for search criteria.
        /// </summary>
        private string searchExtension = "*.*";

        private string _currentPath = string.Empty;

        /// <summary>
        /// Initialize a new instance of the DuplicateFileFinder class.
        /// </summary>
        public DuplicateFileFinder()
        {
            InitializeComponent();
            this.DataContext = this;

            this.backgroundWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.BackgroundWorker_DoWork);
            this.backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.BackgroundWorker_RunWorkerCompleted);

            this.backgroundWorker.WorkerSupportsCancellation = true;
            this.backgroundWorker.WorkerReportsProgress = true;
            lastStackPanel.RegisterName("wpfProgressBar", wpfProgressBar);
        }

        /// <summary> 
        /// Runs on secondary thread. 
        /// </summary> 
        /// <param name="sender">Sender object</param> 
        /// <param name="e">DoWork event argument</param>         
        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // call long running process and get result           
            DirectoryInfo dinfo = new DirectoryInfo(this._currentPath);

            if (isHashSearch)
            {
                // FileLength = "FileImpression";
                e.Result = this.GetFiles(dinfo)
                            .GroupBy(i => i.fileImpression)
                            .Where(g => g.Count() > 1)
                            .SelectMany(list => list)
                            .ToList<FileAttrib>();

            }
            else
            {
                e.Result = this.GetFiles(dinfo)
                            .GroupBy(i => i.fileLength)
                            .Where(g => g.Count() > 1)
                            .SelectMany(list => list)
                            .ToList<FileAttrib>();
                // FileLength = "FileLength";
            }

            // Cancel if cancel button was clicked. 
            if (this.backgroundWorker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }
        }

        /// <summary> 
        /// Called when DoWork has completed. 
        /// </summary> 
        /// <param name="sender">Sender object</param> 
        /// <param name="e">RunWorker completed argument</param>         
        private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                // Back on primary thread, can access ui controls 
                wpfProgressBarAndText.Visibility = Visibility.Collapsed;

                if (e.Cancelled)
                {
                    dataGrid1.ItemsSource = "There is no Data to display";
                }
                else
                {
                    dataGrid1.ItemsSource = (List<FileAttrib>)e.Result;
                }

                CollectionView cv = (CollectionView)CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource);

                if (IsHashSearch)
                {
                    PropertyGroupDescription pgd = new PropertyGroupDescription("fileImpression");
                    cv.GroupDescriptions.Add(pgd);
                }
                else
                {
                    PropertyGroupDescription pgd = new PropertyGroupDescription("fileLength");
                    cv.GroupDescriptions.Add(pgd);
                }
            }
            finally
            {
                this.Calculate.Content = "Start";
                fileExtension.Visibility = System.Windows.Visibility.Visible;
            }
        }

        /// <summary>
        /// Start/Stop button click event
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Routed event Argument</param>
        private void Button1_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.MessageBox.Show("This tool will skip all the folders that are not authorized to read.", "Information", MessageBoxButton.OK);

            //// set isHashSearch flag from radio button value.
            IsHashSearch = rdbHash.IsChecked.Value;

            if (Directory.Exists(this._currentPath))
            {

                if (this.Calculate.Content.Equals("Start"))
                {
                    this.searchExtension = this.fileExtension.Text;
                    if (string.IsNullOrWhiteSpace(this.searchExtension))
                    {
                        this.searchExtension = "*";
                    }

                    this.Calculate.Content = "Stop";
                    this.dataGrid1.AutoGenerateColumns = true;
                    this.backgroundWorker.RunWorkerAsync();
                    this.wpfProgressBarAndText.Visibility = Visibility.Visible;
                    this.fileExtension.Visibility = System.Windows.Visibility.Collapsed;

                }
                else
                {
                    // Cancel the asynchronous operation.                 
                    this.backgroundWorker.CancelAsync();

                    this.backgroundWorker = new System.ComponentModel.BackgroundWorker();
                    this.backgroundWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.BackgroundWorker_DoWork);
                    this.backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.BackgroundWorker_RunWorkerCompleted);
                    this.backgroundWorker.WorkerSupportsCancellation = true;
                    this.backgroundWorker.WorkerReportsProgress = true;

                    this.backgroundWorker = new BackgroundWorker();
                    this.Calculate.Content = "Start";
                    this.wpfProgressBarAndText.Visibility = Visibility.Collapsed;
                    this.fileExtension.Visibility = System.Windows.Visibility.Visible;
                }
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("Please select correct folder");
            }
        }

        /// <summary>
        /// Method to get all the files from given folder and subfolders.
        /// </summary>
        /// <param name="dinfo">DirectoryInfo object for the directory.</param>
        /// <returns>Gives list of FileAttrib object with all files</returns>
        private List<FileAttrib> GetFiles(DirectoryInfo dinfo)
        {
            List<FileAttrib> files = new List<FileAttrib>();

            try
            {
                if (this.searchExtension == "*")
                {
                    files.AddRange(dinfo.GetFiles().Select(s => this.ConvertFileInfo(s)));
                }
                else
                {
                    files.AddRange(dinfo.GetFiles().Where(g => g.Extension.ToLower() == string.Format(".{0}", this.searchExtension.ToLower())).Select(s => this.ConvertFileInfo(s)));
                }

                foreach (var directory in dinfo.GetDirectories())
                {
                    files.AddRange(this.GetFiles(directory));
                }
            }
            catch (UnauthorizedAccessException)
            {

            }

            return files;
        }

        /// <summary>
        /// Convertor for converting FileInfo object into FileAttrib
        /// </summary>
        /// <param name="finfo">Original FileInfo object</param>
        /// <returns>Generated FileAttrib object</returns>
        private FileAttrib ConvertFileInfo(FileInfo finfo)
        {
            return new FileAttrib
            {
                fileName = finfo.Name,
                filePath = finfo.FullName,
                fileImpression = isHashSearch ? this.FileToMD5Hash(finfo.FullName) : null,
                fileLength = finfo.Length
            };
        }

        /// <summary>
        /// Function to get file hash string from a file location.
        /// </summary>
        /// <param name="_fileName">File name to get byte array</param>
        /// <returns>Byte Array</returns>
        private string FileToMD5Hash(string _fileName)
        {
            var returnString = string.Empty;
            try
            {
                using (var stream = new BufferedStream(File.OpenRead(_fileName), 1200000))
                {
                    SHA256Managed sha = new SHA256Managed();
                    byte[] checksum = sha.ComputeHash(stream);
                    returnString = BitConverter.ToString(checksum).Replace("-", string.Empty);
                }
            }
            catch
            { }
            return returnString;
        }

        /// <summary>
        /// Delete particular file using Menu Sub-item
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">routed event argument</param>
        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var source = dataGrid1.ItemsSource.Cast<FileAttrib>().ToList();

                foreach (var selectedItem in dataGrid1.SelectedItems)
                {
                    var deleteFilePath = source.Where((s, i) => s.filePath == ((FileAttrib)selectedItem).filePath).Select(s => s.filePath).First();
                    if (File.Exists(deleteFilePath))
                    {
                        File.Delete(deleteFilePath);
                        source.RemoveAt(dataGrid1.SelectedIndex);
                    }
                }

                dataGrid1.ItemsSource = source;

                CollectionView cv = (CollectionView)CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource);

                if (IsHashSearch)
                {
                    PropertyGroupDescription pgd = new PropertyGroupDescription("fileImpression");
                    cv.GroupDescriptions.Add(pgd);
                }
                else
                {
                    PropertyGroupDescription pgd = new PropertyGroupDescription("fileLength");
                    cv.GroupDescriptions.Add(pgd);
                }
            }
            catch (UnauthorizedAccessException)
            {
                System.Windows.MessageBox.Show("You do not have permission to delete this file.");
            }
        }

        /// <summary>
        /// Open contain file location using Menu click event.
        /// </summary>
        /// <param name="sender">sender object</param>
        /// <param name="e">Routed event argument</param>
        private void MenuItem_Click_1(object sender, RoutedEventArgs e)
        {
            var source = dataGrid1.ItemsSource.Cast<FileAttrib>().ToList();
            var deleteFilePath = source.Where((s, i) => i == dataGrid1.SelectedIndex).Select(s => s.filePath).First();
            ProcessStartInfo fileFolder = new ProcessStartInfo("explorer.exe", "/select,\"" + deleteFilePath + "\"");
            fileFolder.UseShellExecute = false;
            Process.Start(fileFolder);
        }

        private void selectPath_Click(object sender, RoutedEventArgs e)
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();
            folderDialog.Description = "Select folder to find similar files.";
            folderDialog.SelectedPath = this._currentPath;
            folderDialog.ShowNewFolderButton = false;

            DialogResult result = folderDialog.ShowDialog();

            if (result == System.Windows.Forms.DialogResult.OK)
            {
                this._currentPath = folderDialog.SelectedPath;
                this.folderPath.Text = this._currentPath;
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("You have not selected or canceled Path selection popup");
            }
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions