Задача
Написать консольную программу на C#, предназначенную для поблочного сжатия и расжатия файлов с помощью System.IO.Compression.GzipStream. Программа должна эффективно распараллеливать и синхронизировать обработку блоков в многопроцессорной среде и уметь обрабатывать файлы, размер которых превышает объем доступной оперативной памяти. Параметры программы, имена исходного и результирующего файлов должны задаваться в командной строке следующим образом: GZiper.exe compress/decompress [имя исходного файла] [имя результирующего файла]
Реализация
Для синхронизации работы нескольких потоков было принято решение использовать паттерн Producer/Consumer. В программе используется статический класс Ziper, имеющий два основных метода: Compress(inFile, outFile) и Decompress(inFile, outFile), которые в качестве аргументов принимают имена входного и выходного файлов соответственно. Для считывания файла ziper использует класс Reader, запуская в отдельном потоке его основной метод Read(readStream), принимающий на вход принимает поток для считывания файла. Данный метод считывает файл блоками(размером в 1мб при сжатии), присуждая каждому порядковый номер, нужный для корректной записи файла, и передаёт их в очередь на сжатие. В целях экономии ресурсов очередь ограничена по максимальному количеству блоков в очереди (100 максимум) и по остатку оперативной памяти (минимум 512мб). Для сжатия и разжатия ziper использует статический класс ArchiverThreadManager, который контроллирует количество сжимающих или разжимающих потоков. Контроль осуществляется на основании загруженности процессора, количеству блоков в очереди на сжатие и максимальному количеству потоков равному количеству ядер. Для каждого потока менеджер инициализирует новый экземпляр класса Archiver, который берёт блок из очереди, сжитает или разжимает и отдаёт блок в очередь на запись. Для записи на диск ziper использует класс Writer, запуская в отдельном потоке его основной метод Write(writeStream), принимающий на вход принимает поток для записи файла. Данный метод берёт сжатые или разжатые блоки из очереди и записывает их в исходном порядке. При сжатии в первые четыре байта файла записывает ключ, далее в два байта количество блоков и далее перед каждым блоком в три байта записывается длинна сжатого блока. Это нужно для корректной работы программы. При разжатии программа проверяет ключ, считывает общее количество блоков и далее обрабатывает блоки. Также для доступа к ресурсам компьютера используется класс PcPerformance, который обновляет данные о процессоре и оперативной памяти определенный интервал времени. При запуске проходит валидация данных на наличие доступа к чтению/записи, остатку свободного места на диске (на худший случай требуется 105% размера от исходного файла) и на ряд остальных очевидных вещей.