4
\$\begingroup\$

I have the following C# code for deleting files from a folder (and from its sub folders) excluding a list of files specified in an Excel file. The code works fine.

The deletion is happening one-by-one in a for loop. Is there a way to improve its performance by reducing the time taken for deletion?

class Program
{
    public static List<string> AllFilesStaticList = new List<string>();

    static void Main(string[] args)
    {

        string locationOfExcelList = @"G:\Test1\ExclusionList.xls";
        string sheetName = "List$";
        string sourceDirectory = @"G:\TFS2\";

        List<string> excludeList = Import_To_DataTable_FromExcel(locationOfExcelList, sheetName);
        ProcessAllDirectoryToGetFileList(sourceDirectory);

        //Get files to be deleted (Items that are not present in excludeList)
        List<string> eligibleListToProcess = AllFilesStaticList.Where(x => !excludeList.Any(y => x.Contains(y))).ToList();


        //Iterating two lists - need to be improved
        foreach (string fileEntry in eligibleListToProcess)
        {
            try
            {
                if (File.Exists(fileEntry))
                {
                    //foreach delete need to be made more efficient
                    File.Delete(fileEntry);
                    Console.WriteLine(fileEntry);
                }
            }
            catch
            {
                //Hide the exception for now
            }
        }
        Console.ReadLine();
    }

    // Process all files in the directory passed in, recurse on any directories 
    // that are found, and process the files they contain.
    public static  void ProcessAllDirectoryToGetFileList(string targetDirectory)
    {
        // Process the list of files found in the directory.
        //Get files with their path
        string[] fileEntries = Directory.GetFiles(targetDirectory);
        foreach (string fileName in fileEntries)
        {
            AddFile(fileName);
        }

        // Recurse into subdirectories of this directory.
        string[] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
        foreach (string subdirectory in subdirectoryEntries)
        {
            ProcessAllDirectoryToGetFileList(subdirectory);
        }
    }

    public static void AddFile(string fileName)
    {
        //Console.WriteLine();
        AllFilesStaticList.Add(fileName);
    }



    private static List<string> Import_To_DataTable_FromExcel(string FilePath,string sheetName)
    {
        List<string> deploymentFiles = new List<string>();

        string conStr = null;
        conStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 8.0;IMEX=1;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text'";

        conStr = string.Format(conStr, FilePath);
        OleDbConnection connExcel = new OleDbConnection(conStr);
        OleDbCommand cmdExcel = new OleDbCommand();
        OleDbDataAdapter oda = new OleDbDataAdapter();

        cmdExcel.Connection = connExcel;


        connExcel.Open();
        DataTable dtExcelSchema = default(DataTable);
        dtExcelSchema = connExcel.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);


        connExcel.Close();

        //Read Data from First Sheet 
        connExcel.Open();
        cmdExcel.CommandText = "SELECT * From [" + sheetName + "]";
        oda.SelectCommand = cmdExcel;

        DataTable deploymentListTable = new DataTable("deploymentListTable");
        oda.Fill(deploymentListTable);
        connExcel.Close();


        foreach (DataRow row in deploymentListTable.Rows )
        {
            //Read third column from the excel sheet
            string cellFileName = row[2].ToString();
            if (!String.IsNullOrEmpty(cellFileName))
            {
                deploymentFiles.Add(cellFileName);
            }
        }

        return deploymentFiles;


    }



}
\$\endgroup\$
5
\$\begingroup\$

I may suggest the following : why checking for file deletion ?

if (File.Exists(fileEntry))

After all, in file.delete documentation we have :

If the file to be deleted does not exist, no exception is thrown.

\$\endgroup\$
  • 3
    \$\begingroup\$ The file could also disappear between the time the Exists check runs and the time the Delete does. \$\endgroup\$ – Dan Lyons Aug 24 '16 at 18:25
1
\$\begingroup\$
internal class Program
{
    private static void Main()
    {
        const string locationOfExcelList = @"G:\Test1\ExclusionList.xls";
        const string sheetName = "List$";
        const string sourceDirectory = @"G:\TFS2\";

        var excludeList = ImportToDataTableFromExcel(locationOfExcelList, sheetName);

        var filesToDelete = GetFilesRecursive(sourceDirectory).Except(excludeList);

        Parallel.ForEach(filesToDelete, DeleteAndReport);

        Console.ReadLine();
    }

    private static void DeleteAndReport(string fileEntry)
    {
        try
        {
            File.Delete(fileEntry);

            Console.WriteLine(fileEntry);
        }
        catch
        {
            //Hide the exception for now
        }
    }

    public static IEnumerable<string> GetFilesRecursive(string targetDirectory)
    {
        foreach (var fileEntry in Directory.GetFiles(targetDirectory))
            yield return fileEntry;

        foreach (var subdirectory in Directory.GetDirectories(targetDirectory))
            foreach (var fileEntry in GetFilesRecursive(subdirectory))
                yield return fileEntry;
    }

    private static IEnumerable<string> ImportToDataTableFromExcel(string filePath, string sheetName)
    {
        var connectionString = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={filePath};" +
                                "Extended Properties='Excel 8.0;" +
                                "IMEX=1;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text'";

        var deploymentListTable = new DataTable("deploymentListTable");

        using (var connection = new OleDbConnection(connectionString))
        using (var command = connection.CreateCommand())
        {
            connection.Open();

            // Why are you getting the schema? For validation?
            //var schema = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);

            command.CommandText = $"SELECT * From [{sheetName}]";

            var adapter = new OleDbDataAdapter { SelectCommand = command };

            adapter.Fill(deploymentListTable);

            connection.Close();
        }

        return deploymentListTable.Rows
                                  .Cast<DataRow>()
                                  .Select(row => row[2].ToString())
                                  .Where(cellFileName => !string.IsNullOrEmpty(cellFileName));
    }
}

The parallel for each should improve performances where possible.

The code is a bit cleaner and the names are consistent (methods, parameters and local variable).

As suggested by @thesyndarn, you don't need to check for the existence before deleting.

Avoid static lists when the scope can be reduced (helps garbage collection as well).

The yield keyword can help making the recursive method cleaner.

You don't need to open/close the connection of every command; is the schema used somewhere? I have commented it as I appreciate the code might be incomplete.

Don't forget to dispose the connection.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.