Система синхронизации каталогов устройств

  • Вид работы:
    Курсовая работа (т)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    434,84 Кб
  • Опубликовано:
    2015-10-21
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

Система синхронизации каталогов устройств

Министерство образования Республики Беларусь

Учреждение образования

«Гомельский государственный университет имени Франциска Скорины»

Математический факультет

Кафедра математических проблем управления








Курсовая работа

Система синхронизации каталогов устройств


Исполнитель

студент группы ПО-42 В.А. Мордвинов






Гомель 2015

Реферат

Ключевые слова: съемный диск, резервное копирование, файл, каталог, синхронизация.

Объект исследования: работа с файловой системой windows, язык C# и программная библиотека .net framework 4.0.

Методы исследования: среда разработки Microsoft Visual Studio 2013, win API.

Цель курсовой работы: проектирование и написание приложения для автоматизации процесса синхронизации каталогов устройств.

Выводы: было спроектировано и разработано приложение, автоматизирующее процесс синхронизации каталогов дисковых устройств, базирующееся на технологии .net framework 4.0.

 

Введение


В настоящее время одним из самых популярных носителей информации является флеш-диск. Его удобство подключения к компьютеру, компактные размеры и, в то же время, довольно большая емкость, позволяют хранить на нем всю необходимую в повседневном пользовании информацию. Но, не смотря на все плюсы данного носителя, полностью полагаться на него нельзя: компактные размеры несут угрозу потери диска, а технология хранения информации (электронные затворы) не позволяет хранить информацию в течение длительного периода времени. Поэтому, лучшим решением будет использование флеш-диска с регулярным созданием резервных копий данных. Это довольно монотонное занятие, которое можно поручить программе.

Целью данной курсовой работы является разработка приложения, которое автоматизирует процесс синхронизации файлов между сменным носителем и каталогом на другом диске. В общих чертах, работа с приложением будет заключаться в выборе двух каталогов (дисков) и, в дальнейшем, первичном определении направления синхронизации.

Программа будет разрабатываться в среде разработки Visual Studio 2013 на языке C#. Данное средство предоставляет широкий инструментарий для разработки клиентских Windows Forms приложений, в том числе, для работы с файловой системой (управление и мониторинг изменений файлов и каталогов) и со сменными носителями (перехват событий подключения/отключения устройств).

Основная часть курсовой работы представлена четырьмя разделами:

)        описание назначения приложения;

)        краткий обзор использованных технологий;

)        схема диалога пользователя с разработанным приложением;

)        алгоритм синхронизации каталогов.

Первый раздел курсовой работы содержит подробное описание назначения приложения, а также схематическое описание логики работы приложения.

Второй раздел посвящен теоретическим сведениям об использованных технологиях и компонентах:

-   win API;

-        BackgroundWorker;

         FileSystemWatcher;

-        пространство имен «Sysrem.IO» стандартной библиотеки классов языка c#.

В трерьем разделе показаны основные операции, которые позволяет выполнить программа, а также последовательности действий, которые нужно воспроизвести конечному пользователю для выполнения данных операций.

Четвертый раздел описывает схему переключения состояний синхронизации:

-   Analyzing (анализ состояния каталогов);

-        Ok (каталоги синхронизированы);

-        Off (синхронизация каталогов отключена);

-        InProcess (идет процесс синхронизации);

-        WaitSolution (ожидание выбора направления синхронизации пользоватлем);

-        WaitProcess (в очереди на синхронизацию);

         NotAvailable (один из каталогов недоступен);

         UnSuccess (в процессе синхронизации произошла ошибка).

1. Назначение разработанного приложения

Разработанное приложение предназначено для автоматизации процесса синхронизации каталогов.

Данное приложение позволяет выбрать пары каталогов (в том числе и на сменных носителях), содержимое которых, в дальнейшем, будет синхронизироваться в режиме реального времени. Если же один из каталогов недоступен, синхронизация произойдет в момент появления этого каталога (например, при подключении флеш-диска), при этом, пользователю будет предоставлен выбор направления синхронизации. Можно выбрать неограниченное количество таких пар. Если одновременно нескольким из этих пар будет нужна синхронизация, то они будут помещены в очередь на синхронизацию и последовательно обработаны. Процесс текущей синхронизации можно прервать соответствующей кнопкой в строке состояния.

Общий алгоритм работы программы можно представить в виде схемы, изображенной на рисунке 1.

Рисунок 1 - Общая логическая схема приложения

2. Использованные технологии и компоненты

2.1Пространство имен System.IO


Основной задачей приложения является копирование файлов. Следовательно, для работы с ними нужна специальная библиотека методов. В набор стандартных библиотек языка C# входит пространство имен «System.IO», предназначенное для работы с данными, в том числе, и с файлами. Оно и использовалось при разработке программы.

Классы, применяемые для просмотра файловой системы и выполнения таких операций, как перемещение, копирование и удаление файлов, показаны на рисунке 2.

Рисунок 2 - Иерархия классов для работы с файловой системой

В следующем списке объясняется предназначение всех этих классов:

-   System.MarshalByRefObject - это базовый класс для всех классов .NET, позволяющих удаленное взаимодействие; разрешает маршализацию между доменами приложений;

-        FileSystemlnfo - это базовый класс, представляющий любой объект файловой системы;

         Filelnfo и File - классы, представляющие файлы в файловой системе;

         Directorylnfo и Directory - классы, представляющие папки в файловой Системе;

         Path - класс содержит статические члены, используемые для манипулирования путевыми именами;

         Drive Info - класс включает свойства и методы, представляющие информацию о выбранном диске.

Как можно было видеть в приведенном выше списке, два класса используются для представления папки и два - для представления файла. Какой именно класс использовать в каждом конкретном случае, зависит в основном от того, сколько раз нужно обратиться к файлу или папке. и File включают только статические методы; экземпляры этих классов никогда не создаются. Эти классы используются с применением пути к соответствующему объекту файловой системы при каждом вызове методов-членов. Если нужно выполнить только одну операцию над файлом или папкой, то использование этих классов более эффективно, поскольку позволяет сэкономить за счет накладных расходов, связанных с созданием экземпляров классов .NET. и Filelnfo реализуют почти те же общедоступные методы, что и Directory и File, наряду с некоторыми общедоступными свойствами и конструкторами, но эти методы запоминают состояние, и члены этих классов не являются статическими. Перед тем, как ассоциировать экземпляры этих классов с определенной папкой или файлом, должны быть созданы экземпляры. Это значит, что данные классы более эффективны, когда нужно выполнять множество операций над соответствующим объектом файловой системы, не перечитывая каждый раз информацию о нем заново. В отличие от них, классы без состояния должны при каждом вызове метода всякий раз проверять все детали, касающиеся файла или папки.

Для сравнения двух этих типов классов, приведем пример кода копирования файла. С испольованием метода copy класса Filelnfo:

Filelnfo myFile = new Filelnfo("С:\ProgramFiles\MyProgram\ReadMe.txt");

myFile.CopyTo(@"D:\Copies\ReadMe.txt");

И с использованием аналогичного метода класса File:

File.Copy(@"C:\Program Files\My Program\ReadMe.txt",

@"D:\Copies\ReadMe.txt");

Первый фрагмент кода выполняется несколько дольше, поскольку ему необходимо создать экземпляр myFile объекта класса Filelnfo, но после этого myFile остается в памяти и готов для осуществления других операций с тем же файлом. При использовании второго примера нет необходимости создавать объект, чтобы скопировать файл.

Классы Directorylnfo и Filelnfo также позволяют получить сведения об элементе файловой системы, представленные в виде таблицы 1.

Над объектами файловой системы можно также выполнять действия, перечисленные в таблице 2.

Таблица 1 - Основные свойства классов Directorylnfo и Filelnfo

Имя

Описание

CreationTime

Время создания папки или файла.

DirectoryName (только для Filelnfo)

Полное путевое имя содержащей папки.

Parent (только для Directorylnfo)

Родительский каталог указанного подкаталога.

Exists

Существует ли файл или папка.

Extension

Расширение файла; пустое для папок.

FullName

Полное путевое имя файла или папки.

LastAccessTime

Время последнего доступа к файлу или папке.

LastWriteTime

Время последней модификации файла или папки.

Name

Имя файла или папки.

Root (только для Directoryinfо)

Корневая часть пути.

Length (только для Filelnfo)

Размер файла в байтах.


Таблица 2 - Основные методы классов Directorylnfo и Filelnfo

Имя

Назначение

Create()

Создает папку или пустой файл с заданным именем. Для Filelnfo это также возвращает потоковый объект, позволяющий выполнять запись в файл.

Delete ()

Удаляет файл или папку. Для папок предусмотрена опция рекурсивного удаления вложений.

MoveTo()

Перемещает и/или переименовывает файл или папку.

СоруТо() (Только для Filelnfo)

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

GetDirectories() (Только для Directorylnfo)

Возвращает массив объектов Directorylnfo, представляющий все папки, вложенные в данную.

GetFiles() (Только для Directorylnfo)

Возвращает массив объектов Filelnfo, представляющий все файлы, находящиеся в папке.

GetFileSystemlnfos () (Только для Directorylnfo)

Возвращает объекты Filelnfo и Directorylnfo, представляющие все объекты, находящиеся в папке, как массив объектов FileSystemlnfo.


Класс Path представляет ряд статических методов, которые упрощают операции с путевыми именами. Например, предположим, что вы хотите отобразить полное имя файла ReadMe.txt в папке С:\Му Documents. Получить путь этого файла можно с помощью следующего кода:

Console.WriteLine(Path.Combine(@"C:\My Documents", "ReadMe.txt"));

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

2.2 Компонент FileSystemWatcher


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

Для отслеживания изменений во всех файлах нужно установить свойство Filter равным пустой строке ("") или используйте подстановочные знаки ("*.*"). Для отслеживания определенного файла свойство Filter устанавливается равным имени этого файла. Например, для отслеживания изменений в файле MyDoc.txt значения свойства Filter должно быть равным MyDoc.txt. Можно также отслеживать изменения в файлах определенного типа. Например, для отслеживания изменений в текстовых файлах свойство Filter должно быть равным *.txt.

Имеется несколько типов изменений, которые можно отслеживать в каталоге или файле. Например, можно отслеживать изменения атрибутов Attributes, даты и времени последней записи LastWrite или размера Size файлов или каталогов. Это осуществляется путем назначения свойству NotifyFilter одного из выше перечисленных значений.

Можно отслеживать изменение имени, удаление или создание файлов или каталогов. Эти события инициируют выполнение следующих обработчиков:

-   OnChanged - сообщает об изменениях в атрибутах файла, созданных файлах и удаленных файлах;

-        OnRenamed - перечисляет старый и новый пути переименованных файлов и папок, рекурсивно расширяющихся в случае необходимости.

2.3 Компонент BackgroundWorker


Класс BackgroundWorker позволяет выполнить операцию в отдельном, выделенном потоке. Операции, требующие много времени, такие как копирование файлов, могут создавать впечатление, что пользовательский интерфейс перестал отвечать на действия пользователя. Если необходимо обеспечить быстрое реагирование пользовательского интерфейса, а подобные операции приводят к длительным задержкам, эффективным решением может стать класс BackgroundWorker.

Чтобы запустить занимающую много времени операцию в фоновом режиме, следует создать экземпляр BackgroundWorker и отслеживать события, сообщающие о ходе выполнения операции и сигнализирующие о ее завершении. Можно создать объект BackgroundWorker программными средствами или перетащить его в форму из вкладки Компоненты Панели элементов. Класс BackgroundWorker, созданный в конструкторе Windows Forms, появляется в области компонентов, а его свойства отображаются в окне "Свойства".

Чтобы настроить выполнение операции в фоновом режиме, необходимо добавить обработчик события для события DoWork. Вызовите операцию, которая занимает много времени, в этом обработчике событий. Чтобы начать операцию, вызовите RunWorkerAsync. Чтобы получать уведомления о ходе выполнения, необходимо обработать событие ProgressChanged. Если необходимо получать уведомление после завершения операции, обработайте событие RunWorkerCompleted.

2.4 Win API


Несмотря на богатство стандартных библиотек языка c#, иногда все же приходится прибегать к использованию внешних библиотек. В разрабатываемом приложении возникла потребность подписки на системные события подключения/отключения внешнего накопителя данных. Доступ к данным событиям и обеспечивает Win API.

API - это аббревиатура названия Application Programming Interface (интерфейс прикладного программирования). API представляет собой совокупность функций и инструментов, позволяющих программисту создавать приложения (программы), работающие в некоторой среде.API - это набор функций для создания программ, работающих под управлением Microsoft Windows.

Всё взаимодействие пользовательского приложения с операционной системой посредством Win API основано на концепции сообщений. С точки зрения приложения, сообщение является уведомлением о том, что произошло некоторое событие, которое может требовать, а может и не требовать выполнения определенных действий. Это событие может быть следствием действий пользователя, например перемещения курсора или щелчка кнопкой мыши, изменения размеров окна или выбора пункта меню. Кроме того, событие может генерироваться приложением, а также операционной системой. Обычно, эти события принимаются оконной процедурой.

Оконная процедура - это «функция обратного вызова», предназначенная для обработки сообщений, адресованных любому окну того «оконного класса», в котором содержится ссылка на данную процедуру. Эту функцию, обычно, вызывает сама операционная система.

Оконная процедура обычно имеет заголовок со стандартным синтаксисом:

LRESULT CALLBACK Иия_функции (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM IParam)

В этом определении LRESULT - тип возвращаемого значения, hWnd - дескриптор окна, которому адресовано сообщение, uMsg - код сообщения, wParam и IParam - параметры сообщения. Имя функции может быть произвольным, но для главного окна приложения обычно используется имя WndProc.

В теле функции после объявления необходимых локальных переменных обычно размещается оператор switch, внутри которого и происходит обработка нужных сообщений.

Каждому коду сообщения в Windows сопоставлен уникальный символический идентификатор. Все системные идентификаторы определены при помощи директивы #define в заголовочном файле winuser.h. Это облегчает чтение и понимание программ.

Чаще всего приложение обрабатывает оконные сообщения (window messages), начинающиеся с префикса WM_, в нашем случае это WM_DEVICECHANGE. Данный идентификатор позволяет отсеивать сообщения, связанные с событиями подключаемых usb-устройств. В качестве дополнительных параметров нас интересуют следующие два:

-   DBT_DEVICEARRIVAL - сообщает о подключении устройства;

-        DBT_DEVICEQUERYREMOVE - сообщает об отключении устройства.

3. Схема диалога пользователя с разработанным приложением


Диалог пользователя с разработанным приложением «DriveSync» начинается с главного окна - рисунок 3. Исходный код данной формы приведен в приложении А.

Рисунок 3 - Главное окно программы

В данном окне, из соответствующей панели пользователю доступны следующие операции над синхронизациями:

-   добавить - добавление новой пары синхронизируемых каталогов;

-        синхронизировать - синхронизация каталогов (команда доступна в случае необходимости выбора пользователем направления синхронизации);

         изменить - изменение пары синхронизируемых каталогов, а также дополнительных параметров их синхронизации;

         удалить - удаление пары синхронизируемых каталогов;

         включить/отключить - активация/деактивация мониторинга за состоянием каталогов и прерывание текущего процесса синхронизации.

Для сокращения написания введем следующий термин - синхропара, он будет означать сокращенное написание выражения «пара синхронизируемых каталогов».

Для начала нужно создать синхропару. Это можно сделать из соответствующей панели - рисунок 4, появляющейся по нажатию кнопки «Добавить». В поля «Каталог А» и «Каталог Б» нужно ввести полный путь к синхронизируемым каталогам. Сделать это также можно с помощью диалогового окна выбора каталога, появляющегося по нажатию кнопки «Обзор…». Синхронизируемые каталоги должны быть различными и не являться взаимовложенными (во избежание зацикливания синхронизации). Под полями ввода путей есть чекбокс «Автоматическая синхронизация», при установке которого включается мониторинг за изменением содержимого данных каталогов, и файлы и папки данных каталогов синхронизируются автоматически при их изменении в одной из директорий. Если оба введенных пути корректны, то нажатие кнопки «Создать» завершит создание синхропары.

Кнопка «Изменить» становится активна только после выбора одной из пар синхронизации в их списке. Процесс изменения синхропары такой же, как и при создании, только в поля уже введены старые значения.

Рисунок 4 - Панель создания пары синхронизируемых каталогов

Нажатие кнопки «Удалить» или клавиши Delete удалит выбранные в списке записи (если не выбрано ни одной записи - клавиша будет неактивна) и прервет текущий процесс синхронизации всех данных пар каталогов.

Кнопка «Синхронизировать» активна в том случае, если для выбранной пары синхронизируемых каталогов требуется выбрать направление синхронизации. При этом, направление будет выбрано автоматически: в сторону замены более старых файлов и копирования отсутствующих.

При синхронизации больших объемов данных в строке состояния можно увидеть название и полосу прогресса копирования текущего файла - рисунок 5.

Рисунок 5 - Окно выбора направления синхронизации содержимого каталогов

При выборе пары каталогов, для которой требуется выбор направления синхронизации (состояние - «Выберите направление») можно вручную указать направление синхронизации. Для этого нужно либо нажать клавишу Enter, либо просто дважды кликнуть по данной записи в списке. После этого появится окно выбора направления синхронизации - рисунок 6.

Рисунок 6 - Окно выбора направления синхронизации содержимого каталогов

В нижней части данной формы расположен список содержимого пары каталогов, требующей синхронизации. В верхней части расположены поля, содержащие полные пути синхронизируемых каталогов, а также, метки дисков в квадратных скобках (если таковые имеются у диска). Под полями с названиями расположены кнопка синхронизации, которая запустит процесс, а также выпадающий список с перечнем направлений синхронизации, с помощью которого и задается направление. Направление синхронизации также можно из контекстного меню каждого элемента списка объектов - рисунок 7, требующих выбора направления. По умолчанию выбирается направление от нового к старому и от существующего к отсутствующему.

Рисунок 7 - Контекстное меню выбора направления синхронизации

Исходный код данной формы содержится в приложении Б.

Данное приложение подразумевает постоянную фоновую работу, поэтому логично разместить ее значок в системном трее, откуда, кроме вызова главной формы, можно получить доступ к контекстному меню программы, содержащему два пункта: «Выход» и «Настройки». Кнопка выход, соответственно, завершит работу программы, а вторая кнопка откроет окно настроек - рисунок 8.

Рисунок 8 - Окно настроек

Здесь имеется три пункта:

-   «Запрос подтверждения закрытия программы» - данный пункт отвечает за отображения диалогового окна, предлагающего свернуть программу в трей вместо закрытия, которое может отображаться при попытке закрытия главного окна программы;

-        «Сворачивать вместо закрытия» - данный пункт настроек отображается только в том случае, если не отмечен верхний;

         «Запускать при старте Windows» - данный пункт отвечает за добавление программы в список автозагрузки системы.

Исходный код данной формы представлен в приложении В.

4. Алгоритм синхронизации каталогов


В предыдущем разделе описывался интерфейс программы и способы взаимодействия пользователя с ним. В этой же будет рассмотрен алгоритм самого процесса синхронизации каталогов, начиная от создания новой синхропары и заканчивая процессом непосредственных манипуляций с файлами.

Синхропары могут принимать следующие состояния:

-   Analyzing (анализ состояния каталогов);

-        Ok (каталоги синхронизированы);

-        Off (синхронизация каталогов отключена);

-        InProcess (идет процесс синхронизации);

-        WaitSolution (ожидание выбора направления синхронизации пользоватлем);

-        WaitProcess (в очереди на синхронизацию);

         NotAvailable (один из каталогов недоступен);

         UnSuccess (в процессе синхронизации произошла ошибка).

Схему переключения же этих состояний можно представить в виде графической схемы, изображенной на рисунке 9.

Представленный на предыдущем рисунке алгоритм можно описать следующей последовательностью операций:

1) В начале, синхропара может иметь два состояния: анализ и отключена. Если она отключена, то данная синхропара не принимает участия в дальнейших операциях.

2)      Далее, проверяется доступность каталогов синхропары: если один из каталогов не доступен, то ей присваивается состояние «один из каталогов недоступен» и она возвращается в очередь на анализ.

)        Следующим этапом производится проверка флага «авто-синхронизация» (до первого анализа он отключен у всех синхропар) и, если необходима синхронизация, а также отключен данный флаг, то синхропаре присваивается состояние «выбор направления синхронизации».

Рисунок 9 - Схема порядка смены состояний синхропар

4) Далее синхропара помещается в очередь синхронизации. Это происходит сразу после анализа (если присвоено состояние «ожидание обработки»), либо после выбора пользователем направления синхронизации.

5)      Затем наступает очередь непосредственной синхронизации. Если в ее процессе происходит некий сбой, то синхронизация прерывается и синхропаре присваивается состояние «ошибка синхронизации», при котором она исключается из цикла синхронизации до тех пор, пока пользователь не перезапустит ее. Если же синхронизация завершена успешно, то синхропаре присваивается состояние «успех» и она возвращается в очередь на анализ.

Этот алгоритм, а также прочее свойства и методы сущности синхропары содержатся в классе SyncDirs. Его исходный код представлен в приложении Г.

Коллекция синхропар и все связанные с ней операции (очереди, групповая обработка и т.д.) реализованы в классе SyncDirsList описанном в приложении Д.

 

Заключение


В ходе выполнения курсовой работы, было разработано приложение «SyncDirs», предназначенное для автоматизации процесса синхронизации каталогов устройств. Также, в процессе разработки приложения были изучены основы использования методов win API, .net компонентов BackgroundWorker и FileSystemWatcher, а также классов пространства имен System.IO, предназначенных для работы с элементами файловой системы.

Приложение и данный отчет выполнены в полном объеме, намеченном в начале курсового проектирования.

Разработанное приложение, «SyncDirs», предназначено для повседневного использования на компьютерах с любой операционной системой (начиная с Windows XP и новее), на которой установлен .net framework 4.0. Оно будет полезно как для синхронизации документов, так и для ведения медиатеки на устройствах типа «mp3-плеер».

Список использованных источников

1.   Нейгел К. C# 2005 и платформа .NET 3.0 для профессионалов. / К. Нейгел, Б. Ивьен, Д. Глинн, М. Скиннер, К. Уотсон. - М.: Вильямс, 2008. - 1376 с.

2.      Троелсен, Э. Язык программирования С# 5.0 и платформа .NET 4.5, 6-е изд. / Э. Троелсен. - М.: Вильямс, 2013. - 1321 с.

.        Фленов, М. Библия С# - 2-е изд., перераб. и доп. / М. Фленов. - СПб.: БХВ-Петербург, 2011. - 560 с.

.        Щупак, Ю. Win32 API. Эффективная разработка приложений / Ю. Щупак. - СПб.: Питер, 2007. - 572 с.

5.      MSDN: Руководство по программированию на C#

Приложение А

Программный код главной формы

public partial class MainForm : Form

{const string FileRemConf = "SyncDriveConfig.ini";

[DllImport("user32.dll")]extern int ShowWindow(IntPtr hWnd, uint Msg);uint SW_RESTORE = 0x09;driveDetector = null;syncDirs;<int> idRemovableDrives;<string> nameRemovableDrives;syncForm = null;lvwColumnSorter;startMinimized;MainForm(bool startMinimized)

{();= new SyncDirsList(lVDirs, statusStrip1);.MainForm = this;.Pointer.LoadSettings();= SettingsForm.Pointer.IdRemovableDrives;= SettingsForm.Pointer

.NameRemovableDrives;.startMinimized = startMinimized;(startMinimized)

{= false;= 0;

}(int i = 0; i < lVDirs.Columns.Count && i < SettingsForm

.Pointer.ColSizes.Count; i++).Columns[i].Width = (int)SettingsForm.Pointer

.ColSizes[i];pathsA = SettingsForm.Pointer.PathsA;pathsB = SettingsForm.Pointer.PathsB;marksA = SettingsForm.Pointer.MarksA;marksB = SettingsForm.Pointer.MarksB;<SyncState> states = SettingsForm.Pointer.States;<bool> allowAutoSyncs = SettingsForm.Pointer

.AllowAutoSyncs;(int i = 0; i < pathsA.Count; i++).Add(new SyncDirs(pathsA[i], pathsB[i], marksA[i], marksB[i], states[i], allowAutoSyncs[i]));(DriveInfo drive in DriveInfo.GetDrives())(drive);.Enabled = true;= new ListViewColumnSorter();.ListViewItemSorter = lvwColumnSorter;

}void Form1_Shown(object sender, EventArgs e)

{= new DriveDetector();.DeviceArrived +=newDriveDetectorEventHandler(OnDriveArrived);(startMinimized)

{();= 100;= true;

}

}OnDriveArrived(object sender, DriveDetectorEventArgs e)

{(DriveInfo drive in DriveInfo.GetDrives())(drive);

}MainForm_FormClosing(object sender, FormClosingEventArgs e)

{(SettingsForm.Pointer.AlowQuestionForClose && > 0)

{alow = false;.MessageBox dlg = new MsgBoxCheck

.MessageBox();dr = dlg.Show(

"Запомнить выбор (можно изменить в настройках)",

"Свернуть в трей вместо закрытия?",

"Закрытие окна программы..." + new String(' ', 25),

MessageBoxButtons.YesNo, MessageBoxIcon.Question, ref alow);.Pointer.AlowQuestionForClose = !alow;.Pointer.AlowClose = dr == DialogResult.No;

}(!SettingsForm.Pointer.AlowClose)

{();.Cancel = true;

}

{.Pointer.ColSizes.Clear();(int i = 0; i < lVDirs.Columns.Count; i++).Pointer.ColSizes

.Add(lVDirs.Columns[i].Width);pathsA = new StringCollection();pathsB = new StringCollection();marksA = new StringCollection();marksB = new StringCollection();<SyncState> states = new List<SyncState>();<bool> allowAutoSync = new List<bool>();(SyncDirs item in syncDirs)

{.Add(item.PathA);.Add(item.PathB);.Add(item.MarkA);.Add(item.MarkB);.Add(item.State);.Add(item.AllowAutoSync);

}.Pointer.PathsA = pathsA;.Pointer.PathsB = pathsB;.Pointer.MarksA = marksA;.Pointer.MarksB = marksB;.Pointer.States = states;.Pointer.AllowAutoSyncs = allowAutoSync;.Pointer.IdRemovableDrives = idRemovableDrives;.Pointer.NameRemovableDrives = nameRemovableDrives;(syncForm != null).Close();.Pointer.SaveSettings();(syncDirs.CurrentTask.State == SyncState.InProcess).CurrentTask.Cancel();.Pointer.Close();

}

}void tSMIExit_Click(object sender, EventArgs e)

{= 0;.Pointer.AlowClose = true;();

}void btCancelAdd_Click(object sender, EventArgs e)

{.Text = "";.Text = "";.Visible = false;.Visible = true;.Enabled = true;.Focus();

}void btAddSync_Click(object sender, EventArgs e)

{.Visible = true;.Visible = false;.Visible = true;.Visible = false;.Enabled = false;.Checked = true;

}void btReviewA_Click(object sender, EventArgs e)

{.SelectedPath = tBPathA.Text;result = folderBrowserDialog.ShowDialog();(result == DialogResult.OK).Text = folderBrowserDialog.SelectedPath;

}void btReviewB_Click(object sender, EventArgs e)

{.SelectedPath = tBPathB.Text;result = folderBrowserDialog.ShowDialog();(result == DialogResult.OK).Text = folderBrowserDialog.SelectedPath;

}void btApplyAdd_Click(object sender, EventArgs e)

{errMess = null;syncDirs = new SyncDirs(tBPathA.Text, tBPathB.Text, SyncState.Analyzing, cBAutoSync.Checked);(SyncDirs.IsValidPaths(tBPathA.Text, tBPathB.Text, errMess))

{(SyncDirs item in this.syncDirs)

{(item.PathA == tBPathA.Text && .PathB == tBPathB.Text || item.PathB == tBPathA.Text && .PathA == tBPathB.Text)

{=

"Данная пара каталогов уже есть в списке синхронизации!";

break;

}

}(errMess == null && wellBeCycle(tBPathA.Text, tBPathB.Text)) =

"Синхронизация данных каталогов приведет к зацикливанию!";

if (errMess == null).syncDirs.Add(syncDirs);

}(errMess != null)

{.Text = errMess;.Visible = true;

}

{driveA = new DriveInfo(tBPathA.Text[0].ToString());driveB = new DriveInfo(tBPathB.Text[0].ToString());(driveA, true);(driveB, true);_Click(sender, e);

}.Focus();

}void btApplyEdit_Click(object sender, EventArgs e)

{errMess = null;curItem = (SyncDirs)lVDirs.SelectedItems[0].Tag;(!((curItem.PathA == tBPathA.Text && curItem.PathB == tBPathB.Text) || (curItem.PathB == tBPathA.Text && curItem.PathA == tBPathB.Text)) && SyncDirs.IsValidPaths(tBPathA.Text, tBPathB.Text, ref errMess))

{(SyncDirs item in syncDirs)

{(item != curItem && ( item.PathA == tBPathA.Text && item.PathB == tBPathB.Text || item.PathB == tBPathA.Text && item.PathA == tBPathB.Text))

{

errMess = "Данная пара каталогов уже есть в списке синхронизации!";

break;

}

}(wellBeCycle(tBPathA.Text, tBPathB.Text)) = "Синхронизация данных каталогов приведет к зацикливанию!";

}(errMess != null)

{.Text = errMess;.Visible = true;.StateChanged = true;

}

{.AllowAutoSync = cBAutoSync.Checked;.PathA = tBPathA.Text;.PathB = tBPathB.Text;driveA = new DriveInfo(tBPathA.Text[0].ToString());driveB = new DriveInfo(tBPathB.Text[0].ToString());(driveA, true);(driveB, true);_Click(sender, e);

}.Focus();

}isSubDir(string dirA, string dirB)

{(dirA == dirB)true;if (dirA.Length > dirB.Length)

{(dirA.StartsWith(dirB) && dirA.Substring(dirB.Length).Contains("\\"))true;

}

{(dirB.StartsWith(dirA) && dirB.Substring(dirA.Length).Contains("\\"))true;

}false;

}wellBeCycle(string pathA, string pathB, <SyncDirs> tackedItems = null)

{(tackedItems == null)= new List<SyncDirs>();(SyncDirs item in syncDirs)

{(tackedItems.Contains(item));.Add(item);((isSubDir(pathA, item.PathA) && isSubDir(pathB, item.PathB)) || (isSubDir(pathA, item.PathB) && isSubDir(pathB, item.PathA)))true;(isSubDir(pathA, item.PathA) && wellBeCycle(item.PathB, pathB, new List<SyncDirs>(tackedItems)))true;(isSubDir(pathA, item.PathB) && wellBeCycle(item.PathA, pathB, new List<SyncDirs>(tackedItems)))true;.Remove(item);

}false;

}markRemoveble(DriveInfo drive, bool append = false)

{resultFile = new StringBuilder();newDrive = drive.RootDirectory.ToString();found = false;id = 1, j = 0;(drive.DriveType == DriveType.Removable && drive.IsReady)

{

{(StreamReader sr = new StreamReader(newDrive + FileRemConf))

{line;bufPathFile;bufId;((line = sr.ReadLine()) != null)

{(line.StartsWith("syncronization"))

{= int.Parse(line.Substring(15));= sr.ReadLine();.AppendLine(line);(int i = 0; i < idRemovableDrives.Count; i++)

{(idRemovableDrives[i] == id && nameRemovableDrives[i] == bufPathFile)

{.AppendLine(newDrive);= bufId;= true;= i;

}

}(!found)

{.AppendLine(bufPathFile);= bufId + 1;

}

}}.Close();}}(Exception)

{ }(found)

{syncDirs.UpdatePaths(nameRemovableDrives[j], newDrive);[j] = newDrive;}

{idRemovableDrives.Add(id);.Add(newDrive);

}(File.Exists(newDrive + FileRemConf)).SetAttributes(newDrive + FileRemConf, FileAttributes.Normal);(File.Exists(newDrive + FileRemConf) || append)

{if (!found && append)(StreamWriter w = File.AppendText(drive.RootDirectory + FileRemConf))

{.WriteLine("syncronization " + id);.WriteLine(newDrive);.Close();}(StreamWriter w = new StreamWriter(drive.RootDirectory.ToString() + FileRemConf))

{.Write(resultFile);.Close();

};.SetAttributes(newDrive + FileRemConf, FileAttributes.Hidden);

}

}

}void tBPath_TextChanged(object sender, EventArgs e)

{.Text = "";.Visible = false;

}void btDelSync_Click(object sender, EventArgs e)

{(ListViewItem item in lVDirs.SelectedItems)

{.Remove((SyncDirs)item.Tag);

}.Enabled = false;.Enabled = false;.Enabled = false;.Enabled = false;.Enabled = false;

}void btOnSync_Click(object sender, EventArgs e)

{(DriveInfo drive in DriveInfo.GetDrives())(drive);.SelSetState(SyncState.Analyzing);

}void btOffSync_Click(object sender, EventArgs e)

{.SelSetState(SyncState.Off);

}void lVDirs_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)

{isSelected = lVDirs.SelectedItems.Count > 0;isNeedSync = lVDirs.SelectedItems.Count > 0;(ListViewItem item in lVDirs.SelectedItems)(!((item.Tag as SyncDirs).State == SyncState.WaitSolution))

{= false;;

}.Enabled = isNeedSync;.Enabled = lVDirs.SelectedItems.Count == 1;.Enabled = isSelected;.Enabled = isSelected;.Enabled = isSelected;

((SyncDirs)e.Item.Tag).Selected = e.IsSelected;

}void btEditSync_Click(object sender, EventArgs e)

{.Visible = false;.Visible = true;.Text = (lVDirs.SelectedItems[0].Tag as SyncDirs).PathA;.Text = (lVDirs.SelectedItems[0].Tag as SyncDirs).PathB;.Checked = (lVDirs.SelectedItems[0].Tag as SyncDirs).AllowAutoSync;.Visible = true;

//statusStrip1.Visible = true;.Visible = false;.Enabled = false;

}notifyIcon_MouseClick(object sender, MouseEventArgs e)

{(e.Button == System.Windows.Forms.MouseButtons.Left)

{(WindowState == FormWindowState.Minimized || !Visible)

{();();(this.Handle, SW_RESTORE);

}();

}

{<ToolStripItem> items = new List<ToolStripItem>();(DriveInfo drive in DriveInfo.GetDrives())(drive.DriveType == DriveType.Removable && drive.IsReady)

{item = new System.Windows.Forms.ToolStripMenuItem("Извлечь " + drive.VolumeLabel + "(" + drive.RootDirectory + ")");.Tag = drive.RootDirectory.ToString()[0];.Click += new EventHandler(Eject_Click);.Add(item);

}(items.Count > 0).Add(new ToolStripSeparator());(ToolStripItem item in cMSTray.Items)(item.Tag != null && item.Tag.ToString() == "1").Add(item);.Items.Clear();.Items.AddRange(items.ToArray());mi = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.Instance | BindingFlags.NonPublic);.Invoke(notifyIcon, null);

}

}void Eject_Click(object sender, EventArgs e)

{<SyncDirs> syncs = new List<SyncDirs>();(SyncDirs item in syncDirs)

{(item.State != SyncState.Off && (.PathA.StartsWith((sender as ToolStripItem).Tag.ToString()) ||.PathB.StartsWith((sender as ToolStripItem).Tag.ToString())))

{.State = SyncState.Off;.Add(item);

}

}.EjectDrive((char)(sender as ToolStripItem).Tag);(SyncDirs item in syncs).State = SyncState.Analyzing;

}void timerScanner_Tick(object sender, EventArgs e)

{.Text = syncDirs.SyncsUpdate();

}void lVDirs_DoubleClick(object sender, EventArgs e)

{(lVDirs.SelectedItems.Count == 1 && lVDirs.SelectedItems[0].SubItems[2].Text == StateStrings.Items[(int)SyncState.WaitSolution])

{= new SynchronizationForm((SyncDirs)lVDirs.SelectedItems[0].Tag);.ShowDialog();= null;

}

}lVDirs_ColumnClick(object sender, ColumnClickEventArgs e)

{(e.Column == lvwColumnSorter.SortColumn)

{(lvwColumnSorter.Order == SortOrder.Ascending).Order = SortOrder.Descending;.Order = SortOrder.Ascending;

}

}.lVDirs.Sort();

}void btSync_Click(object sender, EventArgs e)

{currSync;(ListViewItem item in lVDirs.SelectedItems)

{= (item.Tag as SyncDirs);.AutoSync = true;.State = SyncState.Analyzing;

}

}void lVDirs_KeyUp(object sender, KeyEventArgs e)

{(e.KeyValue)

{ case (int)Keys.Delete:(btDelSync.Enabled)_Click(null, null);;(int)Keys.Insert:_Click(null, null);;(int)Keys.F2:_Click(null, null);;(int)Keys.Enter:(e.Shift && btSync.Enabled)_Click(null, null);_DoubleClick(null, null);;(int)Keys.Escape:_Click(null, null);;(int)Keys.F1:_Click(null, null);;}}void tBPathA_KeyUp(object sender, KeyEventArgs e)

{(e.KeyData)

{Keys.Escape:_Click(null, null);;Keys.Enter:(btApplyAdd.Visible)_Click(null, null);(btApplyEdit.Visible)_Click(null, null);;

}}}

синхронизация файл программа

Приложение Б

Программный код формы «Выбор направления синхронизации»

public partial class SynchronizationForm : Form

{syncDirs;lvwColumnSorter;SynchronizationForm()

{();= SettingsForm.SyncForm.Size;= SettingsForm.SyncForm.Location;= SettingsForm.SyncForm.WindowState;(int i = 0; i < lVFiles.Columns.Count && i < SettingsForm.Pointer.ColSizesSyncForm.Count; i++).Columns[i].Width = (int)SettingsForm.Pointer.ColSizesSyncForm[i];

}SynchronizationForm(SyncDirs syncDirs)

: this()

{.syncDirs = syncDirs;

}void SynchronizationForm_Shown(object sender, EventArgs e)

{.Text = (syncDirs.MarkA == "" ? "" : "[" + syncDirs.MarkA + "] ") + syncDirs.PathA;.Text = (syncDirs.MarkB == "" ? "" : "[" + syncDirs.MarkB + "] ") + syncDirs.PathB;.SelectedIndex = -1;= new ListViewColumnSorter();.ListViewItemSorter = lvwColumnSorter;(var item in syncDirs.SyncList)

{fileName = item.Key.Substring(1);pIFile = new ListViewItem();(Directory.Exists(syncDirs.PathA + item.Key) || Directory.Exists(syncDirs.PathB + item.Key)).ImageIndex = 0;.ImageIndex = 1;fileA = new FileInfo(syncDirs.PathA + item.Key);fileB = new FileInfo(syncDirs.PathB + item.Key);dateA = fileA.LastWriteTime>new DateTime(1602,1,1) ? fileA.LastWriteTime.ToString("dd.MM.yyyy hh:mm") : "-";dateB = fileB.LastWriteTime > new DateTime(1602,1,1) ? fileB.LastWriteTime.ToString("dd.MM.yyyy hh:mm") : "-";.Text = fileName;.ListViewSubItem cIDateA = new ListViewItem.ListViewSubItem(pIFile, dateA);.ListViewSubItem cIDateB = new ListViewItem.ListViewSubItem(pIFile, dateB);.ListViewSubItem cIMode = new ListViewItem.ListViewSubItem(pIFile, ModeStrings.Items[(int)item.Value]);.SubItems.Add(cIDateA);.SubItems.Add(cIDateB);.SubItems.Add(cIMode);.Tag = item.Value;.Items.Add(pIFile);

}.lVFiles.Sort();

}SynchronizationForm_FormClosing(obj s, FormClosingEventArgs e)

{.SyncForm.WindowState = WindowState;= 0;= FormWindowState.Normal;.SyncForm.Size = Size;.SyncForm.Location = Location;.Pointer.ColSizesSyncForm.Clear();(int i = 0; i < lVFiles.Columns.Count; i++).Pointer.ColSizesSyncForm.Add(lVFiles.Columns[i].Width);(ListViewItem item in lVFiles.Items)

{.SyncList["\\" + item.Text] = (SyncMode)item.Tag;

}(syncDirs.AutoSync).State = SyncState.Analyzing;

}void cmSymcMode_Opening(object sender, CancelEventArgs e)

{(lVFiles.SelectedItems.Count == 0).Cancel = true;

}cBSyncMode_SelectedIndexChanged(object sender, EventArgs e)

{(cBSyncMode.SelectedIndex == -1);(lVFiles.SelectedItems.Count == 0 || lVFiles.SelectedItems.Count == lVFiles.Items.Count)(ListViewItem item in lVFiles.Items)

{.SubItems[3].Text = ModeStrings.Items[cBSyncMode.SelectedIndex];.Tag = (SyncMode)cBSyncMode.SelectedIndex;

}

{(ListViewItem item in lVFiles.SelectedItems)

{.SubItems[3].Text = ModeStrings.Items[cBSyncMode.SelectedIndex];.Tag = (SyncMode)cBSyncMode.SelectedIndex;

}

}

}void tSMNoneSync_Click(object sender, EventArgs e)

{.SelectedIndex = (int)SyncMode.NoneNync;

}lVFiles_SelectedIndexChanged(object sender, EventArgs e)

{prewMode;(lVFiles.SelectedItems.Count == 0)

{= (SyncMode)lVFiles.Items[0].Tag;(ListViewItem item in lVFiles.Items)

{((SyncMode)item.Tag != prewMode)

{.SelectedIndex = -1;;

}

}

}

{= (SyncMode)lVFiles.SelectedItems[0].Tag;(ListViewItem item in lVFiles.SelectedItems)

{((SyncMode)item.Tag != prewMode)

{.SelectedIndex = -1;;

}

}

}.SelectedIndex = (int)prewMode;

}вНаправленииАBToolStripMenuItem_Click(object s, EventArgs e)

{.SelectedIndex = (int)SyncMode.AToB;

}вНаправленииВAToolStripMenuItem_Click(object s, EventArgs e)

{.SelectedIndex = (int)SyncMode.BToA;

}lVFiles_ColumnClick(object sender, ColumnClickEventArgs e)

{(e.Column == lvwColumnSorter.SortColumn)

{(lvwColumnSorter.Order == SortOrder.Ascending).Order = SortOrder.Descending;.Order = SortOrder.Ascending;

}

{.SortColumn = e.Column;.Order = SortOrder.Ascending;

}.lVFiles.Sort();

}void btSync_Click(object sender, EventArgs e)

{.AutoSync = true;();

}

}

Приложение В

Процедуры сохранения / восстановления настроек программы

public void LoadSettings()

{set = Settings.Default;states;iDRemovableDrives;allowAutoSyncs;nameRemovableDrives;rkApp = Registry.CurrentUser.OpenSubKey(

"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);.Checked = (rkApp.GetValue("DriveSync") != null);= set.AlowClose;= set.AlowQuestionForClose;.Checked = !alowClose;.Checked = alowQuestionForClose;= set.CollsSize;= set.CollsSizeSyncForm;= set.PathsA;= set.PathsB;= set.MarksA;= set.MarksB;= set.States;.Size = set.Size;.Location = set.Location;.Size = set.SizeSyncForm;.Location = set.LocationSyncForm;= new List<SyncState>();(states != null)

{foreach (SyncState item in states)

{if(item ==SyncState.Off).Add(item);.Add(SyncState.Analyzing);}}= new List<bool>();= set.AllowAutoSyncs;(allowAutoSyncs != null)

{(object item in allowAutoSyncs).Add((bool)item);

}= set.IDRemovableDrives;= set.RemovableDrives;.idRemovableDrives = new List<int>();.nameRemovableDrives = new List<string>();(iDRemovableDrives != null)

{(int i = 0; i < iDRemovableDrives.Count; i++)

{.idRemovableDrives.Add((int)iDRemovableDrives[i]);.nameRemovableDrives.Add(nameRemovableDrives[i]);

}

}(set.SyncFormMax).WindowState = FormWindowState.Maximized;(set.FormMax).WindowState = FormWindowState.Maximized;(colSizes == null)= new ArrayList();(colSizesSyncForm == null)= new ArrayList();(pathsB == null)= new StringCollection();(pathsA == null)= new StringCollection();(marksB == null)= new StringCollection();(marksA == null)= new StringCollection();}void SaveSettings(bool saveWinSize = true)

{Settings set = Settings.Default;states = new ArrayList();iDRemovableDrives = new ArrayList();allowAutoSyncs = new ArrayList();namesRemovableDrives = new StringCollection();rkApp = Registry.CurrentUser.OpenSubKey(

"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);(cBAutoRun.Checked).SetValue("DriveSync", Application.ExecutablePath.ToString() + " /StartMinimized");.DeleteValue("DriveSync", false);(SyncState item in this.states)

{(item != SyncState.Off).Add(SyncState.Analyzing);.Add(item);

}(int item in idRemovableDrives).Add(item);(string item in nameRemovableDrives).Add(item);(bool item in AllowAutoSyncs).Add(item);.AllowAutoSyncs = allowAutoSyncs;.AlowClose = alowClose;.AlowQuestionForClose = alowQuestionForClose;.PathsA = pathsA;.PathsB = pathsB;.MarksA = marksA;.MarksB = marksB;.States = states;(saveWinSize)

{.FormMax = (MainForm.WindowState == FormWindowState.Maximized);.Opacity = 0;.WindowState = FormWindowState.Normal;.Size = MainForm.Size;.SyncFormMax = (SyncForm.WindowState == FormWindowState.Maximized);.WindowState = FormWindowState.Normal;.SizeSyncForm = SyncForm.Size;

}.Location = MainForm.Location;.LocationSyncForm = SyncForm.Location;.CollsSize = colSizes;.CollsSizeSyncForm = colSizesSyncForm;.IDRemovableDrives = iDRemovableDrives;.RemovableDrives = namesRemovableDrives;

set.Save();}

Приложение Г

Исходный код сущности синхропары

public enum SyncState

{= 0,= 1,= 2,= 3,= 4,= 5,= 6,= 7

}enum SyncMode

{,,

}class StateStrings

{static readonly string[] Items =

{

"Анализируется...",

"Готово",

"Отключено",

"Синхронизируется...",

"Выберите направление",

"В очереди на синхронизацию",

"Один из каталогов недоступен",

"Не все файлы синхронизировались"

};

}

static class ModeStrings

{static readonly string[] Items =

{

"Не синхронизировать",

"А -> Б",

"Б -> А"

};

}class SyncDirs

{remA, remB;pathA;pathB;markA;markB;selected;needShow;needSync;autoSync;allowAutoSync;success;state;fileWatcherA;fileWatcherB;<string, SyncMode> syncList;progressMess;progressPercent;AutoResetEvent _resetEvent = new AutoResetEvent(false);BackgroundWorker backgroundSync;double ProgressPercent

{{ return progressPercent; }

}string ProgressMess

{{ return progressMess; }

}Dictionary<string, SyncMode> SyncList

{{ return syncList; }

}bool AllowAutoSync

{{ return allowAutoSync; }

{(value && value != allowAutoSync && state == SyncState.Off)= SyncState.Analyzing;= value;

}

}bool AutoSync

{{ return autoSync; }{ autoSync = value; }

}string MarkA

{{ return markA; }

}string MarkB

{{ return markB; }

}bool NeedSync

{{ return needSync; }

}string PathA

{{ return pathA; }

{(pathA != value)

{(fileWatcherA != null).Dispose();= null;

}= true;= value;(pathA.Length > 0 && ((pathA[0] <= 'z' && pathA[0] >= 'a') || (pathA[0] <= 'Z' && pathA[0] >= 'A')))

{drive = new DriveInfo(pathA.Substring(0, 1));(drive.IsReady)= drive.VolumeLabel;

}

}

}string PathB

{{ return pathB; }

{(pathB != value)

{(fileWatcherB != null).Dispose();= null;

}= true;= value;(pathB.Length > 0 && ((pathB[0] <= 'z' && pathB[0] >= 'a') || (pathB[0] <= 'Z' && pathB[0] >= 'A')))

{drive = new DriveInfo(pathB.Substring(0, 1));(drive.IsReady)= drive.VolumeLabel;

}

}

}SyncState State

{

{state;

}

{= value;(state)

{SyncState.Analyzing:= true;;SyncState.Off:SyncState.NotAvailable:(fileWatcherA != null).Dispose();(fileWatcherB != null).Dispose();= null;= null;= false;.Clear();;SyncState.Ok:SyncState.UnSuccess:.Clear();= true;(fileWatcherA == null && AllowAutoSync)

{= new FileSystemWatcher(pathA);.Changed += new FileSystemEventHandler(dirChanged);.Created += new FileSystemEventHandler(dirChanged);.Renamed += new RenamedEventHandler(dirRenamed);.Deleted += new FileSystemEventHandler(dirDeleted);.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastWrite;.IncludeSubdirectories = true;.EnableRaisingEvents = true;

}(fileWatcherB == null && AllowAutoSync)

{= new FileSystemWatcher(pathB);.Changed += new FileSystemEventHandler(dirChanged);.Created += new FileSystemEventHandler(dirChanged);.Renamed += new RenamedEventHandler(dirRenamed);.Deleted += new FileSystemEventHandler(dirDeleted);.NotifyFilter = NotifyFilters.DirectoryName | .FileName | NotifyFilters.LastWrite;.IncludeSubdirectories = true;.EnableRaisingEvents = true;

};

}

}

}bool Selected

{{ return selected; }{ selected = value; }

}string StateString

{

{(state == SyncState.InProcess && progressMess == "")StateStrings.Items[(int)SyncState.Analyzing];StateStrings.Items[(int)state];

}

}bool NeedShow

{

{buf = needShow;= false;buf;

}{ needShow = value; }

}dirChanged(object sender, FileSystemEventArgs e)

{(e.FullPath.StartsWith(pathA) && !e.FullPath.StartsWith(pathB))= true;= true;= SyncState.Analyzing;= true;(fileWatcherA != null)

{.Dispose();= null;

}(fileWatcherB != null)

{.Dispose();= null;

}

}

dirDeleted(object sender, FileSystemEventArgs e)

{(e.FullPath.StartsWith(pathA) && !e.FullPath.StartsWith(pathB))= true;= true;= SyncState.Analyzing;= true;(fileWatcherA != null)

{.Dispose();= null;

}(fileWatcherB != null)

{.Dispose();= null;

}

}dirRenamed(object sender, RenamedEventArgs e)

{(e.OldFullPath.StartsWith(pathA) && !e.OldFullPath.StartsWith(pathB))= true;= true;= SyncState.Analyzing;= true;(fileWatcherA != null)

{.Dispose();= null;

}(fileWatcherB != null)

{.Dispose();= null;

}

}bool DirsExists()

{(Directory.Exists(pathA) && Directory.Exists(pathB))true;false;

}SyncDirs()

{= "";= -1;= SyncState.Ok;= false;= false;= false;= false;= true;= false;= true;= new Dictionary<string, SyncMode>();= new BackgroundWorker();.WorkerSupportsCancellation = true;.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundSync_DoWork);.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundSync_RunWorkerCompleted);.ProgressChanged += new ProgressChangedEventHandler(reportProgress);.WorkerReportsProgress = true;

}SyncDirs(string pathA, string pathB, SyncState state, bool allowAutoSync)

: this()

{= pathA;= pathB;(!allowAutoSync && state == SyncState.Off)= SyncState.Analyzing;.state = state;.allowAutoSync = allowAutoSync;

}SyncDirs(string pathA, string pathB, string markA, string markB, SyncState state, bool allowAutoSync)

: this(pathA, pathB, state, allowAutoSync)

{.markA = markA;.markB = markB;

}static bool IsValidPaths(string pathA, string pathB, string errMess)

{= null; (pathA == "")

errMess = "Выберите каталог А";

else if (pathB == "")= "Выберите каталог Б";

{(pathA[pathA.Length - 1] == '\\')= pathA.Remove(pathA.Length - 1, 1);(pathB[pathB.Length - 1] == '\\')= pathB.Remove(pathB.Length - 1, 1);(!Directory.Exists(pathA))=

"Такого пути не существует! (Каталог А)";

else if (!Directory.Exists(pathB)) =

"Такого пути не существует! (Каталог Б)";if (Path.Equals(pathA, pathB)) =

"Нет смысла синхронизировать каталог сам с собой...";

else if (pathA.StartsWith(pathB) && pathA.Substring(pathB.Length).Contains("\\")) =

"Не надо пытаться синхронизировать корневой каталог с его дочерними...";

else if (pathB.StartsWith(pathA) && pathB.Substring(pathA.Length).Contains("\\")) =

"Не надо пытаться синхронизировать корневой каталог с его дочерними...";

}(errMess == null);

}

void backgroundSync_RunWorkerCompleted(object s, RunWorkerCompletedEventArgs e)

{= true;= false;= "";= -1;

{(!success && File.Exists(CustomFileCopier.lastCopiedFile)).Delete(CustomFileCopier.lastCopiedFile);

}(Exception)

{

}

_resetEvent.Set();

}void Cancel()

{= false;

_resetEvent.WaitOne();

{(File.Exists(CustomFileCopier.lastCopiedFile)).Delete(CustomFileCopier.lastCopiedFile);

}(Exception)

{ }

}void Analyze()

{= SyncState.InProcess;(!backgroundSync.IsBusy).RunWorkerAsync();

}void backgroundSync_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)

{fileSystemEntry;fileA;fileB;mode;(syncList.Count == 0)

{(string currentFile in Directory.EnumerateFileSystemEntries(pathA))

{= currentFile.Substring(pathA.Length);(fileSystemEntry == "\\" + MainForm.FileRemConf ||.StartsWith("\\~"));= new FileInfo(pathA + fileSystemEntry);= new FileInfo(pathB + fileSystemEntry);(Directory.Exists(pathB + fileSystemEntry))

{cmp = DirsCompare(fileA.FullName, fileB.FullName);(cmp != 0)

{(cmp>0)= SyncMode.AToB;= SyncMode.BToA;(remA)= SyncMode.AToB;(remB)= SyncMode.BToA;.Add(fileSystemEntry, mode);

}

}if (!File.Exists(pathB + fileSystemEntry) ||.LastWriteTime != fileB.LastWriteTime)

{= SyncMode.AToB;(remB)= SyncMode.BToA;(remA)= SyncMode.AToB;.Add(fileSystemEntry, mode);

}

}(string currentFile in Directory.EnumerateFileSystemEntries(pathB))

{= currentFile.Substring(pathB.Length);(fileSystemEntry == "\\" + MainForm.FileRemConf ||.StartsWith("\\~"));(!Directory.Exists(pathA + fileSystemEntry) && !File.Exists(pathA + fileSystemEntry))

{= SyncMode.BToA;(remB)= SyncMode.BToA;(remA)= SyncMode.AToB;.Add(fileSystemEntry, mode);

}

}

}(syncList.Count > 0)

{= true;(autoSync)

//k();= SyncState.WaitSolution;

}= SyncState.Ok;= false;= false;= true;

}static int DirsCompare(string dirNameA, string dirNameB)

{(string fileNameA in Directory.GetDirectories(dirNameA, "*"))

{fileNameB = fileNameA.Replace(dirNameA, dirNameB);(Directory.Exists(fileNameB))

{cmpRes = DirsCompare(fileNameA, fileNameB);(cmpRes != 0)cmpRes;

}1;

}(string fileNameB in Directory.GetDirectories(dirNameB, "*"))

{fileNameA = fileNameB.Replace(dirNameB, dirNameA);(!Directory.Exists(fileNameA))1;

}fileA, fileB;(string fileName in Directory.GetFiles(dirNameA, "*.*"))

{= new FileInfo(fileName);= new FileInfo(fileName.Replace(dirNameA, dirNameB));(fileB.Exists)

{(fileA.LastWriteTime != fileB.LastWriteTime)fileA.LastWriteTime.CompareTo(fileB.LastWriteTime);

}1;

}(string fileName in Directory.GetFiles(dirNameB, "*.*"))

{= new FileInfo(fileName.Replace(dirNameB, dirNameA));(!fileA.Exists)-1;

}0;

}void Synchronize()

{compliteCount = 0;= " ";= true;<string> removeItems = new List<string>();(var item in syncList)

{(item.Value)

{SyncMode.AToB:(pathA, pathB, item.Key);++;;SyncMode.BToA:(pathB, pathA, item.Key);++;;SyncMode.NoneNync:= false;;

}(success).Add(item.Key);(syncList.Count == 0);

}(compliteCount == syncList.Count)

{(AllowAutoSync)

{(success)= SyncState.Ok;= SyncState.UnSuccess;

}= SyncState.Off;

}= SyncState.WaitSolution;(string item in removeItems).Remove(item);

}syncDirsProcess(string pathA, string pathB, string file)

{= true;

{(Directory.Exists(pathA + file))

{.CreateDirectory(pathB + file);(string dirPath in Directory.GetDirectories(pathA + file, "*"))(pathA, pathB, dirPath.Substring(pathA.Length));(string dirPath in Directory.GetDirectories(pathB + file, "*"))

{(!Directory.Exists(dirPath.Replace(pathB, pathA))).Delete(dirPath, true);

}(string fileName in Directory.GetFiles(pathB + file, "*.*"))

{(!File.Exists(fileName.Replace(pathB, pathA))).Delete(fileName);

}(string newFile in Directory.GetFiles(pathA + file, "*.*"))

{fileA = new FileInfo(newFile);fileB = new FileInfo(newFile.Replace(pathA, pathB));(!fileB.Exists || fileA.LastWriteTime > fileB.LastWriteTime)

{.ReportProgress(1, fileA.Name);fileCopier = new CustomFileCopier(newFile, newFile.Replace(pathA, pathB));.OnProgressChanged += new ProgressChangeDelegate(fileCopier_OnProgressChanged);.Copy();

}

}

}

{(File.Exists(pathA + file))

{.ReportProgress(1, (new FileInfo(pathA + file)).Name);fileCopier = new CustomFileCopier(pathA + file, pathB + file);.OnProgressChanged += new ProgressChangeDelegate(fileCopier_OnProgressChanged);.Copy();

}if (File.Exists(pathB + file)).Delete(pathB + file);.Delete(pathB + file, true);

}

}(Exception)

{= false;

}

}reportProgress(object sender, ProgressChangedEventArgs e)

{= e.UserState.ToString();

}fileCopier_OnProgressChanged(double persentage, bool cancel)

{(!success)= true;= persentage;

}

}

Приложение Д

Исходный код сущности коллекции синхропар

class SyncDirsList : List<SyncDirs>

{statusStrip;listView;currentTask;<SyncDirs> itemsInProcess;stateChanged;SyncDirs CurrentTask

{{ return currentTask; }

}bool StateChanged

{

{bufVal = stateChanged;(bufVal)= false;bufVal;

}{ stateChanged = value; }

}Queue<SyncDirs> ItemsInProcess

{{ return itemsInProcess; }

}ListView ListView

{{ return listView; }{ listView = value; }

}SyncDirsList(ListView listView, StatusStrip statusStrip)

{.listView = listView;.statusStrip = statusStrip; ;= new Queue<SyncDirs>();= new SyncDirs();= true;

}new void Add(SyncDirs newItem)

{.Add(newItem);parentItem = new ListViewItem(newItem.PathA);.ListViewSubItem childItem = new ListViewItem.ListViewSubItem(parentItem, newItem.PathB);.ListViewSubItem childItem2 = new ListViewItem.ListViewSubItem(parentItem, newItem.StateString);.SubItems.Add(childItem);.SubItems.Add(childItem2);.Tag = newItem;.Items.Add(parentItem);= true;

}new bool Remove(SyncDirs removingItem)

{(ListViewItem item in listView.Items)(item.Tag == removingItem)

{(removingItem == currentTask)

{.Cancel();= new SyncDirs();

}.Items.Remove(item);.Remove(removingItem);= true;true;

}false;

}void UpdateList()

{(!StateChanged);.Items.Clear();pIPathA;pathA, pathB;(SyncDirs item in this)

{= item.MarkA != "" ? "[" + item.MarkA + "] " + item.PathA : item.PathA;= item.MarkB != "" ? "[" + item.MarkB + "] " + item.PathB : item.PathB;= new ListViewItem(pathA);.ListViewSubItem cIPathB = new ListViewItem.ListViewSubItem(pIPathA, pathB);.ListViewSubItem cIState = new ListViewItem.ListViewSubItem(pIPathA, item.StateString);.SubItems.Add(cIPathB);.SubItems.Add(cIState);.Tag = item;.Selected = item.Selected;.Items.Add(pIPathA);

}

}void SelSetState(SyncState state)

{sDItem;<ListViewItem> items = new List<ListViewItem>();(ListViewItem item in listView.SelectedItems).Add(item);(ListViewItem item in items)

{.Selected = true;= (SyncDirs)item.Tag;(sDItem == currentTask)(state != SyncState.InProcess || state != SyncState.Analyzing)

{.Cancel();= new SyncDirs();

};.State = state;.SyncList.Clear();

}= true;();

}string SyncsUpdate()

{state = SyncState.Ok;(SyncDirs item in this)

{(item.State != SyncState.Off)

{(!item.DirsExists())

{(item.State != SyncState.NotAvailable)

{.State = SyncState.NotAvailable;= true;

}

}if (item.State == SyncState.NotAvailable).State = SyncState.Analyzing;

}(item.State == SyncState.Analyzing || item.State == SyncState.Ok || item.State == SyncState.UnSuccess)

{(item.NeedSync)

{.State = SyncState.WaitProcess;(!itemsInProcess.Contains(item)).Enqueue(item);= true;

}if (item.State == SyncState.Analyzing)

{.State = SyncState.Ok;= true;

}

}(item.State == SyncState.WaitSolution)

{= SyncState.WaitSolution;

}

}(currentTask.State != SyncState.InProcess && itemsInProcess.Count > 0)

{.Analyze();= true;

}

}(currentTask.NeedShow)

{(currentTask.State == SyncState.Ok)= new SyncDirs();= true;

}(currentTask.State == SyncState.InProcess)= SyncState.InProcess;();programmState = StringBuilder("SyncDrive - ");(state != SyncState.InProcess)

{(statusStrip.Items[1].Text != "" && !statusStrip.Items[0].Visible)

{.Items[1].Text = "";.Items[3].Visible = false;

(statusStrip.Items[3] as ToolStripProgressBar).Value = 0;

}

}(state)

{SyncState.Ok:.Append("Все ок");;SyncState.UnSuccess:.Append("Не все ок");.Items[3].Visible = false;;SyncState.InProcess:.Append("Идет синхронизация...");progressMess = currentTask.ProgressMess;progress = currentTask.ProgressPercent;(progressMess != "")

{.Items[1].Text = "Идет копирование: " + progressMess;(progress > -1)

{.Items[3].Visible = true;

(statusStrip.Items[3] as ToolStripProgressBar).Value = (int)progress;

}.Update();

};SyncState.WaitSolution:.Append("Выберите направление синхронизации");

break;

}programmState.ToString();

}void UpdatePaths(string oldDrive, string newDrive)

{(SyncDirs item in this)

{(item.PathA[0] == oldDrive[0])

item.PathA = newDrive[0] + item.PathA.Remove(0, 1);(item.PathB[0] == oldDrive[0])

item.PathB = newDrive[0] + item.PathB.Remove(0, 1);

}

}

}

Похожие работы на - Система синхронизации каталогов устройств

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!