/// <summary> /// Метод для потока чтения. Чтение и генерация задач сжатия происходит в 1 поток, что даёт максимальную нагрузку на диск /// </summary> /// <param name="obj"> /// Дескриптор файла для чтения /// </param> private void ReadingThread(object obj) { FileDescriptor readFile = obj as FileDescriptor; _fileLength = readFile.GetDescription.Length; try { using (FileStream fileToBeDecompressed = readFile.GetDescription.OpenRead()) { // Читать блоки архива, пока не закончится файл while (fileToBeDecompressed.Position < _fileLength && !_cancellationToken.IsCancellationRequested) { _position = fileToBeDecompressed.Position; // Защита от переполнения памяти if (_compressTaskPool.TaskCount() > _maxTasks * _cores) { Thread.Sleep(_sleep); continue; } ITaskInfo task = _taskFactory.CreateReadTaskInfo(_batchCount, 0); _compressTaskPool.AddTask(_taskFactory.CreateProcessTaskInfo(_batchCount++, task.Execute(fileToBeDecompressed) as byte[])); } _isReading = false; #if DEBUG Console.WriteLine("End of reading"); #endif } } catch (Exception exc) { Console.WriteLine("Error on file reading"); #if DEBUG Console.WriteLine(exc); #endif } }
/// <summary> /// Запустить сжатие заданного файла и сохранить по указанному пути /// </summary> /// <param name="readFile"> /// Дескриптор файла для чтения /// </param> /// <param name="writeFile"> /// Дескриптор файла для записи /// </param> public bool ProcessFile(FileDescriptor readFile, FileDescriptor writeFile) { _readTaskPool = new QueueTaskPool(); _compressTaskPool = new QueueTaskPool(); _writeTaskPool = new HashtableTaskPool(); /// Длина исходного файла Int64 _fileLength = readFile.GetDescription.Length; // Количество целых кусков _batchCount = _fileLength / _readBlockSize; // Длина последнего куска _lastPiece = _fileLength % _readBlockSize; // Общее количество кусков с учётом последнего _totalCount = _batchCount; if (_lastPiece > 0) { _totalCount++; } try { // Запуск потока чтения Thread readingThread = new Thread(ReadingThread); readingThread.Start(readFile); // Запустить потоки распаковки for (int i = 0; i < _cores; ++i) { Thread compressingThread = new Thread(CompressingThread); compressingThread.Start(); } // Запустить поток записи Thread writingThread = new Thread(WritingThread); writingThread.Start(writeFile); // Запуск потока генерации задач Thread generatorThread = new Thread(GeneratorThread); generatorThread.Start(); // Наблюдатель - ждёт, пока не завершится последний кусок и обновляет прогресс while (_lastWritedBlock < _totalCount && !_cancellationToken.IsCancellationRequested) { #if !DEBUG Console.Clear(); #endif Console.WriteLine("Press Ctrl+C for cancellation"); // Здесь должно высылаться оповещение контроллеру, чтобы тот обновил на GUI прогресс бар (W.I.P.) =] Console.WriteLine("Progress: {0}%", Math.Truncate(_lastWritedBlock / (double)_totalCount * 100)); Thread.Sleep(500); } if (_cancellationToken.IsCancellationRequested) { Console.WriteLine("Compression cancelled"); return(false); } #if !DEBUG Console.Clear(); #endif Console.WriteLine("Compression completed"); return(true); } catch (Exception exc) { Console.WriteLine("Can't process threads"); #if DEBUG Console.WriteLine(exc); #endif return(false); } }
public static void Decompress(string open_path, string save_path) { try { // Токен для отмены процесса CancellationTokenSource cancellationToken = new CancellationTokenSource(); Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs args) { args.Cancel = true; cancellationToken.Cancel(); }; // Контейнеры для описаний файлов FileDescriptor open = new FileDescriptor(open_path); FileDescriptor save = new FileDescriptor(save_path + open.GetDescription.Name.Replace(".gz", "")); if (!File.Exists(open_path)) { Console.WriteLine("Source file is not exist"); throw new Exception(); } if (!Directory.Exists(save_path)) { Console.WriteLine("Dir is not exist"); throw new Exception(); } if (save.GetDescription.DirectoryName == ".gz") { Console.WriteLine("Destination file extension is GZip"); throw new Exception(); } if (open.GetDescription.Extension != ".gz") { Console.WriteLine("Source file extension is not GZip"); throw new Exception(); } DecompressorTaskFactory factory = new DecompressorTaskFactory(); Decompressor progamMode = new Decompressor(cancellationToken.Token, factory, Environment.ProcessorCount, Environment.ProcessorCount); #if DEBUG var timer = new Stopwatch(); timer.Start(); #endif // Запуск распаковки bool result = progamMode.ProcessFile(open, save); cancellationToken.Dispose(); #if DEBUG timer.Stop(); Console.WriteLine(timer.Elapsed.TotalSeconds); Console.ReadKey(); #endif // Если процесс отменён, то удалить получившийся файл if (!result) { if (File.Exists(save.GetDescription.FullName)) { File.Delete(save.GetDescription.FullName); } } } catch (Exception exc) { #if DEBUG Console.WriteLine(exc); #endif Console.ReadKey(); } }
public static void Compress(string open_path, string save_path) { try { // Токен для отмены процесса CancellationTokenSource cancellationToken = new CancellationTokenSource(); Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs args) { args.Cancel = true; cancellationToken.Cancel(); }; // Контейнеры для описаний файлов FileDescriptor open = new FileDescriptor(open_path); FileDescriptor save = new FileDescriptor(save_path + open.GetDescription.Name + ".gz"); // Обработка исключений if (!File.Exists(open_path)) { Console.WriteLine("Source file is not exist"); throw new Exception(); } if (open.GetDescription.Extension == ".gz") { Console.WriteLine("Source file extension is GZip"); throw new Exception(); } if (!Directory.Exists(save_path)) { Console.WriteLine("Dir is not exist"); throw new Exception(); } CompressionTaskFactory factory = new CompressionTaskFactory(); Compressor progamMode = new Compressor(cancellationToken.Token, factory, 56636, Environment.ProcessorCount, Environment.ProcessorCount); #if DEBUG // Замерить время сжатия var timer = new Stopwatch(); timer.Start(); #endif // Запуск сжатия bool result = progamMode.ProcessFile(open, save); cancellationToken.Dispose(); #if DEBUG timer.Stop(); Console.WriteLine(timer.Elapsed.TotalSeconds); Console.ReadKey(); #endif // Если процесс отменён, то удалить архив if (!result) { if (File.Exists(save.GetDescription.FullName)) { File.Delete(save.GetDescription.FullName); } } else { // Вывести уровень сжатия Console.WriteLine("Compression level: " + Math.Truncate(save.GetDescription.Length / (double)open.GetDescription.Length * 100) + "%"); } } catch (Exception exc) { #if DEBUG Console.WriteLine(exc); Console.ReadKey(); #endif } }