Как получить только 3 типа файлов? [Дубликат]

Классы нового стиля - это подклассы «объект» (прямо или косвенно). Они имеют метод класса __new__ в дополнение к __init__ и имеют несколько более рациональное поведение на низком уровне.

Обычно вы хотите переопределить __getattr__ (если вы тоже переопределяете) , в противном случае вам будет сложно поддерживать синтаксис «self.foo» в ваших методах.

Дополнительная информация: http://www.devx.com/opensource/Article/31482/0 / Главная / 4

302
задан lahsrah 15 January 2013 в 04:45
поделиться

24 ответа

для

var exts = new[] { "mp3", "jpg" };

Вы могли бы:

public IEnumerable<string> FilterFiles(string path, params string[] exts) {
    return
        Directory
        .EnumerateFiles(path, "*.*")
        .Where(file => exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase)));
}

Но реальная выгода EnumerateFiles появляется, когда вы разделяете фильтры и объединяете результаты:

public IEnumerable<string> FilterFiles(string path, params string[] exts) {
    return 
        exts.Select(x => "*." + x) // turn into globs
        .SelectMany(x => 
            Directory.EnumerateFiles(path, x)
            );
}

Это становится немного быстрее, если вам не нужно их поворачивать

Оценка производительности на основе следующего теста LinqPad (примечание: Perf просто повторяет делегат 10000 раз) https://gist.github.com / zaus / 7454021

(повторно отправлено и расширено от 'duplicate', поскольку этот вопрос специально запросил LINQ: Несколько расширений файлов searchPattern для System.IO.Directory.GetFiles )

439
ответ дан Community 22 August 2018 в 14:03
поделиться
  • 1
    Человек, я должен думать в терминах LINQ чаще. Хорошее решение! – Ken Pespisa 23 September 2009 в 03:29
  • 2
    Просто убедитесь, что вы понимаете последствия: это вернет файлы all в массив строк, а затем отфильтрует их по указанным расширениям. Это может быть не большой проблемой, если «C: \ Path» не имеет большого количества файлов под ним, но может быть проблемой памяти / производительности в «C: \ & quot; или что-то типа того. – Christian.K 14 February 2010 в 13:13
  • 3
    ... 2 года спустя: Хороший код, но следите за этим, если у вас есть файл, который заканчивается на .JPG, он этого не сделает. Лучше добавьте s.ToLower().Endswith... – Stormenet 5 May 2010 в 10:35
  • 4
    вы можете просто использовать s.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase) – Paul Farry 31 May 2010 в 23:58
  • 5
    Обратите внимание, что с .NET 4.0 вы можете заменить Directory.GetFiles на Directory.EnumerateFiles, msdn.microsoft.com/en-us/library/dd383571.aspx , что позволит избежать проблем с памятью, которые @Christian .K упоминает. – Jim Mischel 3 December 2011 в 00:58
  • 6
    что вы имеете в виду под «i становится немного быстрее, если вам не нужно превращать их в глобусы»? Это O (1) или O (n) (в отношении количества файлов, а не числа расширений)? Я бы предположил, что это O (1) (или O (n) в отношении количества расширений) и, вероятно, где-то в диапазоне нескольких процессорных циклов ... Если это так, то это, вероятно, - разумный результат - пренебрежимо малый – BatteryBackupUnit 22 July 2014 в 13:39
  • 7
    @BatteryBackupUnit да с 10 000 повторами против 2 расширений разница в glob vs. str равна 3 мс, поэтому да технически незначительна (см. Ссылку на исходные результаты), но не зная, сколько расширений вам нужно отфильтровать, и я понял, что стоит отметить, что есть разница; я оставлю это вам, чтобы решить, является ли «упрощенное использование». (то есть .FilterFiles(path, "jpg", "gif")) лучше, чем «явные глобусы». (т. е. .FilterFiles(path, "*.jpg", "*.gif")). – drzaus 23 July 2014 в 16:42
  • 8
    отлично, спасибо. Извините, я как-то пропустил эту ссылку github. Может быть, я должен адаптировать настройки цвета экрана :) – BatteryBackupUnit 23 July 2014 в 19:46
  • 9
    Поддерживает ли это расширение в верхнем регистре, такое как .JPG или .MKV? – Wahyu 23 April 2016 в 07:18
  • 10
    Недостатком решения SelectMany является то, что он будет перебирать все файлы, как только они будут переданы в одно расширение файла. – 17 of 26 15 September 2016 в 13:12
449
ответ дан Community 5 November 2018 в 11:37
поделиться

Следующая функция выполняет поиск по нескольким шаблонам, разделенным запятыми. Вы также можете указать исключение, например: «! Web.config» будет искать все файлы и исключать «web.config». Шаблоны могут быть смешаны.

private string[] FindFiles(string directory, string filters, SearchOption searchOption)
{
    if (!Directory.Exists(directory)) return new string[] { };

    var include = (from filter in filters.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) where !string.IsNullOrEmpty(filter.Trim()) select filter.Trim());
    var exclude = (from filter in include where filter.Contains(@"!") select filter);

    include = include.Except(exclude);

    if (include.Count() == 0) include = new string[] { "*" };

    var rxfilters = from filter in exclude select string.Format("^{0}$", filter.Replace("!", "").Replace(".", @"\.").Replace("*", ".*").Replace("?", "."));
    Regex regex = new Regex(string.Join("|", rxfilters.ToArray()));

    List<Thread> workers = new List<Thread>();
    List<string> files = new List<string>();

    foreach (string filter in include)
    {
        Thread worker = new Thread(
            new ThreadStart(
                delegate
                {
                    string[] allfiles = Directory.GetFiles(directory, filter, searchOption);
                    if (exclude.Count() > 0)
                    {
                        lock (files)
                            files.AddRange(allfiles.Where(p => !regex.Match(p).Success));
                    }
                    else
                    {
                        lock (files)
                            files.AddRange(allfiles);
                    }
                }
            ));

        workers.Add(worker);

        worker.Start();
    }

    foreach (Thread worker in workers)
    {
        worker.Join();
    }

    return files.ToArray();

}

Использование:

foreach (string file in FindFiles(@"D:\628.2.11", @"!*.config, !*.js", SearchOption.AllDirectories))
            {
                Console.WriteLine(file);
            }
4
ответ дан 2 revs 22 August 2018 в 14:03
поделиться
List<string> FileList = new List<string>();
DirectoryInfo di = new DirectoryInfo("C:\\DirName");

IEnumerable<FileInfo> fileList = di.GetFiles("*.*");

//Create the query
IEnumerable<FileInfo> fileQuery = from file in fileList
                                  where (file.Extension.ToLower() == ".jpg" || file.Extension.ToLower() == ".png")
                                  orderby file.LastWriteTime
                                  select file;

foreach (System.IO.FileInfo fi in fileQuery)
{
    fi.Attributes = FileAttributes.Normal;
    FileList.Add(fi.FullName);
}
28
ответ дан abatishchev 22 August 2018 в 14:03
поделиться
  • 1
    Помогите мне в этом, пожалуйста ... Когда я печатаю imageFile, он дает полный путь к нему. Как я могу сжать его только к имени файла. – Naresh 24 May 2011 в 09:03
  • 2
    System.IO.Path.GetFileName (ImageFile) – jnoreiga 25 May 2011 в 18:43
  • 3
    Path.GetExtension возвращает '.ext', а не '* .ext' (по крайней мере, в 3.5+). – nullable 4 January 2012 в 22:43
  • 4
    FYI: вам нужен System.Linq для .where ( – jnoreiga 28 March 2012 в 22:20
  • 5
    У файла getfiles нет перегруженного u. – nawfal 27 July 2012 в 14:51
  • 6
    file.Extension.ToLower() - плохая практика. – abatishchev 27 July 2012 в 15:35
  • 7
    то что мы должны использовать? @abatishchev – Nitin Sawant 18 June 2013 в 11:56
  • 8
    @Nitin: String.Equals(a, b, StringComparison.OrdinalIgnoreCase) – abatishchev 18 June 2013 в 18:34
  • 9
    Фактически, файл .Extension.Equals (& quot; .jpg & quot;, StringComparison.OrdinalIgnoreCase) - это то, что я предпочитаю. Кажется, это быстрее, чем .ToLower или .ToUpper, или так говорят везде, где я искал. На самом деле .Equals быстрее, чем ==, так как == вызовы .Equals и проверяют на null (потому что вы не можете сделать null.Equals (null)). – ThunderGr 1 November 2013 в 15:19
  • 10
    Существует потенциальная ошибка. Нам давно предшествуют дни, когда расширения должны быть ровно тремя символами. Предположим, вы можете столкнуться с файлом с .abc, а поддерживаемыйExtensions содержит .abcd. Будет соответствовать, хотя это не должно. Исправить: supportedExtensions = ".jpg|.abcd|"; с .Contains(Path.GetExtension(s).ToLower() + "|"). То есть, укажите свой разделительный символ в тесте. ВАЖНО: ваш разделительный символ также должен быть после записи LAST в поддерживаемыхExceptions. – ToolmakerSteve 2 April 2018 в 13:10

Как насчет этого:

private static string[] GetFiles(string sourceFolder, string filters, System.IO.SearchOption searchOption)
{
   return filters.Split('|').SelectMany(filter => System.IO.Directory.GetFiles(sourceFolder, filter, searchOption)).ToArray();
}

Я нашел его здесь (в комментариях): http://msdn.microsoft.com/en-us/library/wz42302f.aspx

48
ответ дан Albert 22 August 2018 в 14:03
поделиться
  • 1
    Я предполагаю, что это позволяет избежать потенциальных ошибок памяти в рейтинге ответа? В этом случае он должен быть оценен выше! – Dan W 1 February 2013 в 20:48
  • 2
    @DanW Самый рейтинговый ответ, безусловно, ставит нагрузку на память, но я думаю, что это не должно быть такой проблемой. Мне тоже понравился этот ответ, но это на самом деле (намного) медленнее, чем принятый ответ. Проверьте этот параметр SpeedTest – OttO 14 February 2013 в 00:37
  • 3
    Благодарю. Рад видеть, что это примерно вдвое медленнее - я буду придерживаться этого, тем временем, я думаю. – Dan W 17 February 2013 в 21:47
  • 4
    Он только в два раза медленнее, если есть только два расширения. Если у вас есть список расширений X, это будет в X раз более медленным. Потому что здесь вы вызываете функцию Directory.GetFiles несколько раз, тогда как в другом решении она вызывается только один раз. – Oscar Hermosilla 12 May 2016 в 13:25
  • 5
    @OscarHermosilla Можно использовать Parallel.ForEach, чтобы получить их параллельно – FindOutIslamNow 21 June 2018 в 12:22

Существует также решение спуска, которое, как представляется, не имеет какой-либо памяти или производительности накладных расходов и довольно элегантно:

string[] filters = new[]{"*.jpg", "*.png", "*.gif"};
string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();
8
ответ дан Bas1l 22 August 2018 в 14:03
поделиться
  • 1
    Полагаю, я мог бы отредактировать его так, чтобы он принял неизвестное неограниченное количество расширений с новой строковой переменной и функцией Split. Но даже тогда, как это лучше, чем решение гнорейги? Это быстрее? Меньше памяти? – Brackets 12 July 2017 в 17:33
  • 2
    Есть компромисс. Этот подход вызывает GetFiles несколько раз, по одному на фильтр. Эти многочисленные вызовы могут быть значительными и «служебными» служебными данными ». в некоторых ситуациях у него есть важное преимущество в том, что каждый GetFiles возвращает массив с сопоставлением путей файла. Я бы ожидал, что это обычно будет хорошим результатом производительности, возможно даже superior , но это нужно протестировать. Если GetFiles значительно быстрее, чем EnumerateFiles, то это может быть лучший подход. Также обратите внимание, что окончательный «.Array ()» может быть опущено, когда IEnumerable можно использовать напрямую. – ToolmakerSteve 2 April 2018 в 13:32

Nop ... Я считаю, что вам нужно сделать столько звонков, сколько требуемых типов файлов.

Я бы создал функцию, которая сама взяла массив в строках с необходимыми расширениями и затем перебирала на этом массиве все необходимые вызовы. Эта функция вернет общий список файлов, соответствующих адресам, которые я отправил.

Надеюсь, что это поможет.

10
ответ дан bluish 22 August 2018 в 14:03
поделиться
  • 1
    Зачем использовать Linq? Будет ли это быстрее, чем использовать List и addrange? – ThunderGr 1 November 2013 в 15:16
  • 2
    Я не знаю, что будет быстрее, и не думайте, что это важный вопрос. для почти любого места, где вы будете использовать код для решения этой проблемы, разница в производительности будет незначительной. вопрос должен состоять в том, что более читаемо для облегчения ремонтопригодности кода в будущем. я думаю, что это разумный ответ, потому что он помещается в одну строку источника, которая, по моему мнению, является частью того, что хочет этот вопрос, призывы необходимы и четко выражают намерение этой линии. list и addrange отвлекают несколько шагов, чтобы выполнить одно и то же. – Dave Rael 1 November 2013 в 19:13

Если вы используете VB.NET (или импортировали зависимость в свой проект C #), на самом деле существует удобный метод, который позволяет фильтровать несколько расширений:

Microsoft.VisualBasic.FileIO.FileSystem.GetFiles("C:\\path", Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, new string[] {"*.mp3", "*.jpg"});

В VB.NET это могут быть доступны через My-namespace:

My.Computer.FileSystem.GetFiles("C:\path", FileIO.SearchOption.SearchAllSubDirectories, {"*.mp3", "*.jpg"})

К сожалению, эти удобные методы не поддерживают лениво оцененный вариант, например Directory.EnumerateFiles().

0
ответ дан Crusha K. Rool 22 August 2018 в 14:03
поделиться

Я не знаю, какое решение лучше, но я использую это:

String[] ext = "*.ext1|*.ext2".Split('|');

            List<String> files = new List<String>();
            foreach (String tmp in ext)
            {
                files.AddRange(Directory.GetFiles(dir, tmp, SearchOption.AllDirectories));
            }
0
ответ дан elle0087 22 August 2018 в 14:03
поделиться

Сделайте расширения, в которых вы хотите одну строку i.e «.mp3.jpg.wma.wmf», а затем проверьте, содержит ли каждый файл требуемое расширение. Это работает с .net 2.0, поскольку он не использует LINQ.

string myExtensions=".jpg.mp3";

string[] files=System.IO.Directory.GetFiles("C:\myfolder");

foreach(string file in files)
{
   if(myExtensions.ToLower().contains(System.IO.Path.GetExtension(s).ToLower()))
   {
      //this file has passed, do something with this file

   }
}

Преимущество этого подхода состоит в том, что вы можете добавлять или удалять расширения без редактирования кода, то есть добавлять png-изображения, просто напишите myExtensions = " .jpg.mp3.png».

2
ответ дан Evado 22 August 2018 в 14:03
поделиться

надеюсь, что это кому-то поможет:

//getting only playable Audio/Video Files from open dialog

OpenFileDialog dlg = new OpenFileDialog();

dlg.Filter = ""All Media Files|*.wav;*.aac;*.wma;*.wmv;*.avi;*.mpg;*.mpeg;*.m1v;*.mp2;*.mp3;*.mpa;*.mpe;*.m3u;*.mp4;*.mov;*.3g2;*.3gp2;*.3gp;*.3gpp;*.m4a;*.cda;*.aif;*.aifc;*.aiff;*.mid;*.midi;*.rmi;*.mkv;*.WAV;*.AAC;*.WMA;*.WMV;*.AVI;*.MPG;*.MPEG;*.M1V;*.MP2;*.MP3;*.MPA;*.MPE;*.M3U;*.MP4;*.MOV;*.3G2;*.3GP2;*.3GP;*.3GPP;*.M4A;*.CDA;*.AIF;*.AIFC;*.AIFF;*.MID;*.MIDI;*.RMI;*.MKV";

dlg.ShowDialog();
-1
ответ дан Hassaan Raza 22 August 2018 в 14:03
поделиться

Я знаю, что это старый вопрос, но LINQ: (.NET40 +)

var files = Directory.GetFiles("path_to_files").Where(file => Regex.IsMatch(file, @"^.+\.(wav|mp3|txt)$"));
14
ответ дан Icehunter 22 August 2018 в 14:03
поделиться
  • 1
    Хорошая идея. Подумайте, используя file.ToLower(), чтобы легко соответствовать расширениям верхнего регистра. И почему бы не извлечь расширение сначала, поэтому Regex не должен проверять весь путь: Regex.IsMatch(Path.GetExtension(file).ToLower(), @"\.(wav|mp3|txt)"); – ToolmakerSteve 2 April 2018 в 13:17

Интересно, почему так много «решений» отправлено?

Если мое понимание новобранец о том, как работает GetFiles, прав, есть только два варианта, и любое из вышеперечисленных решений может быть сведено до эти:

  1. GetFiles, а затем фильтр: быстрый, но убийца памяти из-за хранения служебных данных до тех пор, пока фильтры не будут применены
  2. Фильтр в то время как GetFiles: медленнее добавляется больше фильтров, но малое использование памяти, поскольку никакие накладные расходы не хранятся. Это объясняется в одном из вышеуказанных сообщений с впечатляющим эталоном: каждый параметр фильтра вызывает отдельную операцию GetFile, так что одна и та же часть жесткого диска читается несколько раз.

На мой взгляд, вариант 1) лучше, но использование SearchOption.AllDirectories в таких папках, как C: \, будет использовать огромные объемы памяти. Поэтому я бы просто сделал рекурсивный под-метод, который проходит через все подпапки, используя опцию 1)

Это должно привести только к 1 GetFiles-операции в каждой папке и, следовательно, быть быстрым (вариант 1), но использовать только небольшой объем памяти, поскольку фильтры применяются после того, как каждая вложенная папка «чтение»> служебные данные удаляются после каждой подпапки.

Пожалуйста, исправьте меня, если я ошибаюсь. Я, как я сказал, совершенно новый для программирования, но хочу глубже понять вещи, чтобы в итоге стать хорошим:)

1
ответ дан Janis 22 August 2018 в 14:03
поделиться

Просто нашел другой способ сделать это. Все еще не одна операция, а бросание ее, чтобы посмотреть, что другие люди думают об этом.

private void getFiles(string path)
{
    foreach (string s in Array.FindAll(Directory.GetFiles(path, "*", SearchOption.AllDirectories), predicate_FileMatch))
    {
        Debug.Print(s);
    }
}

private bool predicate_FileMatch(string fileName)
{
    if (fileName.EndsWith(".mp3"))
        return true;
    if (fileName.EndsWith(".jpg"))
        return true;
    return false;
}
3
ответ дан Jason Z 22 August 2018 в 14:03
поделиться

Нет. Попробуйте следующее:

List<string> _searchPatternList = new List<string>();
    ...
    List<string> fileList = new List<string>();
    foreach ( string ext in _searchPatternList )
    {
        foreach ( string subFile in Directory.GetFiles( folderName, ext  )
        {
            fileList.Add( subFile );
        }
    }

    // Sort alpabetically
    fileList.Sort();

    // Add files to the file browser control    
    foreach ( string fileName in fileList )
    {
        ...;
    }

Взято из: http://blogs.msdn.com/markda/archive/2006/04/20/580075.aspx

6
ответ дан NotMe 22 August 2018 в 14:03
поделиться

Или вы можете просто преобразовать строку расширений в String ^

vector <string>  extensions = { "*.mp4", "*.avi", "*.flv" };
for (int i = 0; i < extensions.size(); ++i)
{
     String^ ext = gcnew String(extensions[i].c_str());;
     String^ path = "C:\\Users\\Eric\\Videos";
     array<String^>^files = Directory::GetFiles(path,ext);
     Console::WriteLine(ext);
     cout << " " << (files->Length) << endl;
}
3
ответ дан Pankaj 22 August 2018 в 14:03
поделиться

У меня была та же проблема и я не смог найти правильное решение, поэтому написал функцию GetFiles:

/// <summary>
/// Get all files with a specific extension
/// </summary>
/// <param name="extensionsToCompare">string list of all the extensions</param>
/// <param name="Location">string of the location</param>
/// <returns>array of all the files with the specific extensions</returns>
public string[] GetFiles(List<string> extensionsToCompare, string Location)
{
    List<string> files = new List<string>();
    foreach (string file in Directory.GetFiles(Location))
    {
        if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.')+1).ToLower())) files.Add(file);
    }
    files.Sort();
    return files.ToArray();
}

Эта функция будет вызывать Directory.Getfiles() только один раз.

Например, вызовите функцию следующим образом:

string[] images = GetFiles(new List<string>{"jpg", "png", "gif"}, "imageFolder");

EDIT: для получения одного файла с несколькими расширениями используйте этот:

/// <summary>
    /// Get the file with a specific name and extension
    /// </summary>
    /// <param name="filename">the name of the file to find</param>
    /// <param name="extensionsToCompare">string list of all the extensions</param>
    /// <param name="Location">string of the location</param>
    /// <returns>file with the requested filename</returns>
    public string GetFile( string filename, List<string> extensionsToCompare, string Location)
    {
        foreach (string file in Directory.GetFiles(Location))
        {
            if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.') + 1).ToLower()) &&& file.Substring(Location.Length + 1, (file.IndexOf('.') - (Location.Length + 1))).ToLower() == filename) 
                return file;
        }
        return "";
    }

Например, вызовите функцию, подобную этой :

string image = GetFile("imagename", new List<string>{"jpg", "png", "gif"}, "imageFolder");
1
ответ дан Quispie 22 August 2018 в 14:03
поделиться

в .NET 2.0 (нет Linq):

public static List<string> GetFilez(string path, System.IO.SearchOption opt,  params string[] patterns)
{
    List<string> filez = new List<string>();
    foreach (string pattern in patterns)
    {
        filez.AddRange(
            System.IO.Directory.GetFiles(path, pattern, opt)
        );
    }


    // filez.Sort(); // Optional
    return filez; // Optional: .ToArray()
}

Затем используйте его:

foreach (string fn in GetFilez(path
                             , System.IO.SearchOption.AllDirectories
                             , "*.xml", "*.xml.rels", "*.rels"))
{}
2
ответ дан Stefan Steiger 22 August 2018 в 14:03
поделиться
29
ответ дан abatishchev 5 November 2018 в 11:37
поделиться
10
ответ дан bluish 5 November 2018 в 11:37
поделиться
3
ответ дан Pankaj 5 November 2018 в 11:37
поделиться
29
ответ дан abatishchev 5 November 2018 в 11:37
поделиться
10
ответ дан bluish 5 November 2018 в 11:37
поделиться
3
ответ дан Pankaj 5 November 2018 в 11:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: