Нужен элегантный способ перемещения потерянных файлов из папки после перемещения парных файлов с помощью класса FileInfo - PullRequest
0 голосов
/ 23 марта 2011

У меня есть папка, из которой я перемещаю пары связанных файлов (xml в паре с pdf).Дополнительные файлы могут быть помещены в эту папку в любое время, но утилита запускается каждые 10 минут или около того.Мы могли бы использовать класс FileSystemWatcher, но по внутренним причинам мы не используем эту утилиту.

Я использую класс System.IO.FileInfo для чтения всех файлов в папке (будут только xml и pdf) во время каждого пробега.Получив файлы в объекте FileInfo, я перебираю файлы, перемещая совпадения в рабочую папку.Как только это будет сделано, я хочу переместить все файлы, которые не были связаны, но находятся в объекте FileInfo, в папку с ошибками.

Поскольку я не могу удалить элементы из объекта FileInfo (или ячто-то упускаю), было бы проще (1) использовать массив строк из класса Directory .GetFiles, (2) создать словарь из объекта FileInfo и удалить значения из него во время итерации, или (3) есть более элегантныйподход с использованием LINQ или что-то еще?

Вот код на данный момент:

internal static bool CompareXMLandPDFFileNames(FileInfo[] xmlFiles, FileInfo[] pdfFiles, string xmlFilePath)
    {
        string workingFilePath = xmlFilePath + @"\WORKING";            

        if (xmlFiles.Length > 0)
        {
            foreach (var xmlFile in xmlFiles)
            {
                string xfn = xmlFile.Name; //xml file name
                string pdfName = xfn.Substring(0,xfn.IndexOf('_')) + ".pdf"; //parsed pdf file name contained in xml file name

                foreach (var pdfFile in pdfFiles)
                {
                    string pfn = pdfFile.Name; //pdf file name
                    if (pfn == pdfName)
                    {
                        //move xml and pdf files to working folder...
                        FileInfo xmlInfo = new FileInfo(xmlFilePath + xfn);
                        FileInfo pdfInfo = new FileInfo(xmlFilePath + pfn);
                        if (!File.Exists(workingFilePath + xfn))
                        {
                            xmlInfo.MoveTo(workingFilePath + xfn);                                
                        }

                        if (!File.Exists(workingFilePath + pfn))
                        {
                            pdfInfo.MoveTo(workingFilePath + pfn);
                        }                            
                    }
                }
            }

            //all files in the file objects should now be moved to working folder, if not, fix orphans...
        }

        return true;
    }

1 Ответ

0 голосов
/ 23 марта 2011

Если честно, я думаю, что вопрос немного плохой.Проблема сформулирована очень сложным способом.Я думаю, что рабочий процесс должен быть более надежным и детерминированным.(например, почему бы не загружать пары файлов в заархивированных наборах в первую очередь?)

(И никакое "Кто-то" скорее всего "не должен не быть здесь раньше")

Вот некоторые случайные улучшения:

using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;

namespace O
{
    static class X
    {
        private static readonly Regex _xml2pdf = new Regex("(_.*).xml$", RegexOptions.Compiled | RegexOptions.IgnoreCase);

        internal static void MoveFileGroups(string uploadFolder)
        {
            string workingFilePath = Path.Combine(uploadFolder, "PROGRESS");

            var groups = new DirectoryInfo(uploadFolder)
                .GetFiles()
                .GroupBy(fi => _xml2pdf.Replace(fi.Name, ".pdf"), StringComparer.InvariantCultureIgnoreCase)
                .Where(group => group.Count() >1);

            foreach (var group in groups)
            {
                if (!group.Any(fi => File.Exists(Path.Combine(workingFilePath, fi.Name))))
                    foreach (var file in group)
                        file.MoveTo(Path.Combine(workingFilePath, file.Name));
            }
        }

        public static void Main(string[]args)
        {
        }
    }
}
  1. использование читаемых имен (скажем, что вы имеете в виду)
  2. IndexOf возвращает -1, если имя файла не содержит "_";случайная загрузка имен файлов может привести к сбою процедуры
  3. Обрабатывать имена файлов без учета регистра в Windows
  4. Не выполнять конкататы путей вручную (вы можете случайно создать пути UNC, а код будет менее переносимым)
  5. не предполагайте, что один xml будет отображаться в одном pdf: схема именования подразумевает, что многие xmls отображаются в одно и то же имя pdf.Эта реализация позволяет это (или вы можете обнаружить ситуацию, отклонив groups.Where(g => g.Count()>2)
  6. Перемещать группы только атомарно (!): Если какой-либо из файлов в группе существует в целевой директории, не перемещайтелюбой (или у вас будет состояние гонки, когда часть группы get перемещается до того, как последний файл был (полностью) загружен, и она никогда не будет перемещена, поскольку группа больше не обнаруживается

Другие элементы(todo)

  • Не передавайте избыточные параметры. Вы можете передать FI [] вместо необработанного вызова GetFiles (), если вы хотите фильтровать.
  • Делать обработку ошибок, особенно:
    • обрабатывает исключения ввода-вывода
    • возможны ошибки блокировки во время загрузки (тестирование или повреждение файлов), вам нужно атомарно обрабатывать их (т.е. неперемещайте любые файлы в группе, если не все можно было переместить; это будет несколько сложно)
      • протестируйте ваш код (ни один из моих примеров не тестировался; он просто скомпилирован на linux с mono)
...