Копирование файлов в папку с ограничением в 100МБ

433
02 января 2017, 21:12

Пытаюсь скопировать (массив расширений файлов) в папку ( и в эту папку которую я копирую сделать ограничение в 100МБ), если лимит превышен файлов в папке, прекратить копировать! Вот код:

public static void GetFilesList()
{
    long DS = 1000000;
    string[] extens = 
    { 
    ".txt", ".doc", 
    ".cs", ".ico", 
    ".Dll", ".Html", 
    ".Htm", ".Xml", 
    ".Php", ".png", 
    ".jpg", ".gif" 
    };
    if (DirSize(new DirectoryInfo(Easy.GooVer), DS) > DS)
    {
        foreach (string fileName in Directory.GetFiles(Easy.GooVer, "*.*", SearchOption.AllDirectories))
        {
            string ext = Path.GetExtension(fileName);
            if (Array.IndexOf(extens, ext) >= 0)
            { try{
              File.Copy(fileName, Path.Combine(Easy.str1, Path.GetFileName(fileName)), true);}catch { }
            }
        }
    }
}
public static long DirSize(DirectoryInfo d, long aLimit = 0)
{
    long Size = 0;
    FileInfo[] fis = d.GetFiles();
    foreach (FileInfo fi in fis)
    {
        Size += fi.Length;
        if (aLimit > 0 && Size > aLimit)
            return Size;
    }
    DirectoryInfo[] dis = d.GetDirectories();
    foreach (DirectoryInfo di in dis)
    {
        Size += DirSize(di, aLimit);
        if (aLimit > 0 && Size > aLimit)
            return Size;
    }
    return (Size);
}
Answer 1

Попробуйте, например, так:

long copiedSoFar = 0;
foreach (string fileName in
             Directory.GetFiles(Easy.GooVer, "*.*", SearchOption.AllDirectories))
{
    string ext = Path.GetExtension(fileName);
    if (Array.IndexOf(extens, ext) < 0)
        continue;
    try
    {
        var fileSize = new FileInfo(fileName).Length;
        if (copiedSoFar + fileSize > DS)
            continue; // другие файлы могут ещё влезть
        File.Copy(fileName, Path.Combine(Easy.str1, Path.GetFileName(fileName)), true);
        copiedSoFar += fileSize;
    }
    catch
    {
        // тут надо сделать что-то разумное
    }
}
Answer 2

Можно эту задачу решить через паттерн ИТЕРАТОР, хотя может это будет и сложнее и больше писанины, но ведь это же классика!

Нам понадобиться Enumerator

internal class FilesEnumerator : IEnumerator<FileInfo>
{
    private string _StartPath;
    private IEnumerator<string> _FileEnumerator;
    //ctor
    public FilesEnumerator(string startPath, string searchPattern)
    {
        _StartPath = startPath;
        var files = Directory.EnumerateFiles(_StartPath, searchPattern, SearchOption.AllDirectories);
        _FileEnumerator = files.GetEnumerator();
    }
    public FileInfo Current
    {
        get
        {
            return new FileInfo(_FileEnumerator.Current);
        }
    }
    object IEnumerator.Current
    {
        get
        {
            return this.Current;
        }
    }
    public bool MoveNext()
    {
        return _FileEnumerator.MoveNext();
    }
    public void Reset()
    {
        _FileEnumerator.Reset();
    }
    public void Dispose()
    {
        _FileEnumerator.Dispose();
    }
}

далее локатор

public class FilesLocator : IEnumerable<FileInfo>
{
    private string _StartPath;
    private string _SearchPattern;
    //ctor
    public FilesLocator(string startPath, string searchPattern = "*.*")
    {
        if (String.IsNullOrEmpty(startPath)) throw new ArgumentException($"{nameof(startPath)} не может быть пустым");
        if (String.IsNullOrEmpty(startPath)) throw new ArgumentException($"{nameof(searchPattern)} не может быть пустым");
        _StartPath = startPath;
        _SearchPattern = searchPattern;
    }
    public IEnumerator<FileInfo> GetEnumerator()
    {
        return new FilesEnumerator(_StartPath, _SearchPattern);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

Ну, а пользоваться можно так

[TestMethod()]
    public void FilesLocatorTest()
    {
        string fromC = @"D:\Temp";
        string toC = @"C:\Temp";
        //вы уж извините, я тут свои другие расширения подставил
        List<string> extensions = new List<string>() { ".json", ".txt" };
        //опять же можете др. лимит прописать
        long limit = 100000;
        var files = new FilesLocator(fromC);
        foreach (var file in files)
        {
            string ext = Path.GetExtension(file.Name);
            int id = extensions.IndexOf(ext);
            if ( id < 0) continue;
            if ((limit -= file.Length) < 0) break;
            try
            {
                file.CopyTo(Path.Combine(toC, file.Name));
            }
            catch
            {
                //
            }
        }
    }
READ ALSO
Как очистить DatePicker

Как очистить DatePicker

Выбранная дата в DatePicker биндится к свойству во ViewModel

651
Выделение памяти List C#

Выделение памяти List C#

Краткий, может быть глупый вопрос: как при создании List<тип> выделить сразу память под n Элементов? Конструктор позволяет задать только примерную...

439
Generic или не Generic

Generic или не Generic

В обсуждении моего ответа на вопрос возник один спорный момент

362