Link to home
Start Free TrialLog in
Avatar of CipherIS
CipherISFlag for United States of America

asked on

C# Linq -> Remove files from List<string>

I want to delete files that have a certain criteria in the filename.

I have the below code which works with deleting directories.
        public const string Excel = "*.xls*";

        public static string GetFilesWithExt()
        {
            return Excel;
        }

        public const string CAD = "CAD";

        public static IEnumerable<string> RemoveDirectories = new[]
        {
            CAD
        };

        List<string> files = Directory.GetFiles(dir, CriteriaConstants.GetFilesWithExt(), SearchOption.AllDirectories)
                                          .Where(dirs => !CriteriaConstants.RemoveDirectories.Any(dirname => dirs.Contains(dirname))).ToList();

Open in new window

I tried the below code but I do not get any data.
        public const string Excel = "*.xls*";

        public static string GetFilesWithExt()
        {
            return Excel;
        }

        public const string BOM = "BOM ";
        public const string TopLevel = "Top Level";

        public static IEnumerable<string> RemoveFiles = new[]
        {
            BOM,
            TopLevel
        };

        List<string> file = Directory.GetFiles(dir, CriteriaConstants.GetFilesWithExt(), SearchOption.TopDirectoryOnly)
                                .Where(dirs => !CriteriaConstants.RemoveFiles.Any(dirname => dirs.Contains(dirname))).ToList();

Open in new window


Found the issue.  I'm using Directory.GetFiles to obtain a list of files.  The directory contains the name "BOM" and the filename also contains the name "BOM".  How do I delete where the filename contains "BOM" regardless of the directory.
Avatar of Chinmay Patel
Chinmay Patel
Flag of India image

Hi CipherIS,

I need some clarity, you need to get the list of directories? or files? - which contains a given word?

Regards,
Chinmay.
Avatar of CipherIS

ASKER

Here is an example:

C:\dir1\dir2\dir3\dir4\dir 2 file1.xlsx
C:\dir1\dir2\dir3\dir4\dir 2 abc2.xlsx
C:\dir1\dir2\dir3\dir4\dir 2 def3.xlsx

So I want to delete anything that has a file name containing "dir 2" in the filename only.  The full bath is stored in my List<string>
When you say anything, meaning any file/directory with dir 2?
Delete "file" with name "dir 2" only.  Do not delete from directory named "dir 2".

I didn't set up the structure.  I'm writing a reconciliation process and I need to remove some files from my List<string>.  

The problem is that user named a directory "dir 2" (example) and some file names start with "dir 2" (example).

I just want to delete the files.  

I can loop through the list and use URI to get the filename and then not add it to a new list.

Wondering if there is an easier way.
Oh, that can be solved in many ways but this is the on I prefer the most as it is as straightforward as it can get (It won't throw an error for non-existing files). There is a built-in static method of File class, called File.Exists(path), you can use it in your expression or in a separate function.
File.Exists(path)

Open in new window


Please check: https://docs.microsoft.com/en-us/dotnet/api/system.io.file.exists?view=netframework-4.7.2
Don't think that is what I'm looking for.  Below is an example how I can solve it with loop.
            List<string> result = new List<string>();

            List<string> files = Directory.GetFiles(dir, CriteriaConstants.GetFilesWithExt(), SearchOption.TopDirectoryOnly).ToList();

            foreach (var f in files)
            {
                Uri uri = new Uri(f);
                if (uri.IsFile)
                {
                    string fn = System.IO.Path.GetFileName(uri.LocalPath);
                    if (!fn.Contains(CriteriaConstants.RemoveFiles))
                    {
                              result.add(fn);
                    }
                }                

Open in new window


My question is, is there a way to remove files that contain the "Dir 2" in the filename without obviously looping and check each one?
No. There is no other way. You will have to loop. Either you write the loop on your own or you use Linq(Behind the scenes it will also do the same).

The last snippet is flawed a bit though, I combined it with the original code to make some sense out of it. Your RemoveFiles is an List<string> but it contains constants but then are those string in your directories/file names? Or you want to search top level directories? Because when you do String.Contains, it is not going to check for Directory or File, it will just check if a string has certain another string and will add it to your list. I would tweak that code to do File.Exists check if I really wanted to figure out if I am dealing with a file or directory.
                   if (!fn.Contains(CriteriaConstants.RemoveFiles))
                    {
File.Exists(fn)
                       {
       result.add(fn);
                    }
}

Open in new window


You are enforcing search in TopDirectories only that means it will not check any directories under the root directory.

I think first you need to write code even with the looping that works. Or maybe clear the requirements a bit more.

I have taken  your requirements and created the following structure
C:\Temp\Root
 - Dir1
    -Dir1
    -Dir2
 - Dir2
    -Dir1
    -Dir2
 - Dir3
    -Dir1
    -Dir2

And in above structure, at random places I dropped an xlsx file named Dir2.xlsx
then I used this code to get all those xlsx in a list
namespace CrmXpress.EEConsole
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;

    class Program
    {
        static void Main(string[] args)
        {
            Run();
            Console.ReadKey();
        }

        private static void Run()
        {
            List<string> files = Directory.GetFiles(@"C:\Temp\Root\", "*.xlsx", SearchOption.AllDirectories).ToList<string>();

            List<string> result = new List<string>();

            foreach (var f in files)
            {
                Console.WriteLine(f);
                if (File.Exists(f))
                {
                    Console.WriteLine("Adding : " + f);
                    result.Add(f);
                }

            }
        }
    }
}

Open in new window


Please run this code, it wont delete any file but will tell you which files are added to the list(which later can be processed for deletion) and let me know if you are getting the results you wanted. If not, please try to clarify the queries I raised in my above statement. If you have multiple filetypes and along with filenames then we can tweak the code even further but requirement has to be clear.
Thanks.  In the end this is how I solved it.  I only want the files in the current directory and not any subdirectories.
        public static List<string> GetFiles(string dir)
        {
            List<string> result = new List<string>();

            List<string> files = Directory.GetFiles(dir, CriteriaConstants.GetFilesWithExt(), SearchOption.TopDirectoryOnly).ToList();

            foreach (var f in files)
            {
                Uri uri = new Uri(f);
                if (uri.IsFile)
                {
                    string fn = System.IO.Path.GetFileName(uri.LocalPath);
                    if (!CriteriaConstants.RemoveFiles.Any(w => fn.Contains(w)))
                    {
                        result.Add(fn);
                    }
                }
            }

            return files;
        }

Open in new window

This question needs an answer!
Become an EE member today
7 DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.