[Из песочницы] Передача файлов с помощью pipes и другие мелочи на Delphi

?v=1

Поставили как-то передо мной задачу написать несколько юнитов на Delphi, обеспечивающие доступ к следующим возможностям Windows:

  1. Shared memory.
  2. Pipes.


Использовать компоненты сторонних разработчиков было нельзя. Shared memory предполагалось использовать для сортировки текстовых файлов больших размеров — несколько десятков или даже сотен мегабайт, на которых TStringList падал с EOutOfMemory. Pipes — для передачи файлов от одного приложения другому.

Переписать код примеров из документации Microsoft с C на Delphi — это было даже не полдела, а процентов 10. Главное было связать это все вместе, дописать, где нужно, дополнительные функции и заставить всё это работать, а не просто существовать в виде исходного кода. В результате родился такой уродливый монстр, что его не то, что показывать кому-то, а просто смотреть на него было страшно. Однако, может, кто-то найдет в его недрах что-то для себя полезное (а вдруг?), поэтому я решил его здесь выложить. На всеобщее поругание. Полный исходный код этой abomination выложен на GitHub. В тексте статьи будут даны названия файлов, где можно посмотреть тот или иной кусок реализации.

Первая задача — сортировка текстового файла — решалась так:

  1. Открываем файл (CreateFile).
  2. Используем CreateFileMapping и MapViewOfFile (common\MemoryMappedFileUnit.pas).
  3. Определяем кодировку файла. Здесь я ограничился, по сути, только двумя кодировками: UTF-16 и ACP — однобайтовая кодировка с кодовой страницей по умолчанию. В русскоязычной Windows обычно используется Windows-1251.
  4. Разбиваем текст на строки. То есть ищем маркеры конца строк и, соответственно, считаем текст от маркера до маркера одной строкой.
  5. Сортируем полученный массив строк (SortingTest\MergeSorterUnit.pas).
  6. Записываем отсортированный массив строк обратно в файл.
  7. PROFIT!


Сортировку заказчик обязательно хотел сделать многопоточной, поэтому в качестве алгоритма сортировки была взята Merge Sort. (Спасибо тому гуру, который создал рабочую реализацию и выложил ее на Stackoverflow.)

Вторая задача — передача файла от одного приложения к другому — оказалась куда сложнее. Получить реализацию pipes на Delphi на основе примеров Microsoft — это одно, но сделать из нее рабочую передавалку файлов — совсем другое. В качестве программы-сервера Microsoft предлагает несколько вариантов:

  1. Multithreaded Pipe Server.
  2. Named Pipe Server Using Overlapped I/O.
  3. Named Pipe Server Using Completion Routines.


Как выяснилось в результате двухнедельных мучений, реализация механизма передачи файла на основе первого варианта сервера (Multithreaded Pipe Server) оказывается слишком сложной. Разумнее использовать второй вариант (Named Pipe Server Using Overlapped I/O), с ним реализация получается куда проще (правда, заказчик по каким-то своим причинам очень хотел именно первый вариант сервера). Но всё равно пришлось помучиться, чтобы довести всё это дело до ума. В результате родился передатчик файлов на основе pipes TCommunicationEndpointBase (CommunicationTest\SimpleCommunicationUnit.pas).

Вкратце передача файлов работает так:

  1. Создаем сервер, то есть создаем named pipe.
  2. Создаем клиент, который подключается к этому named pipe.
  3. Крутим цикл «посылаем запрос — ждем ответ — читаем ответ» на клиенте и на сервере.
  4. Большие файлы посылаем частями и потом собираем файл из этих кусочков.
  5. По окончании передачи файлов закрываем соединение.


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

Да, еще там до кучи лежит оптимизированная реализация функции StringReplace (BlitzTest\StringReplaceCustomUnit.pas). Может, кому пригодится.

Любые комментарии (в том числе и откровенная ругань) приветствуются.

Если вдруг (ну, а вдруг?) кого-то заинтересуют другие мои репозитории, то могу и о них пару слов написать. Если, конечно, этот текст вообще опубликуют.

© Habrahabr.ru