示例#1
0
 private static void Compressing <T>(FilePart part)
 {
     //поток архивации
     using (MemoryStream ms = new MemoryStream())
     {
         using (GZipStream compressionStream = new GZipStream(ms, CompressionMode.Compress))
         {
             compressionStream.Write(part.data, 0, part.data.Length);
             part.data = ms.ToArray();
             //Console.WriteLine($"Block size: {part.data.Length} Byte"); //DEBUG
             processedParts.Enqueue(part);
         }
     }
 }
示例#2
0
 private static void Decompressing <T>(FilePart part)
 {
     //поток разархивации
     using (MemoryStream msi = new MemoryStream(part.data))
     {
         using (MemoryStream mso = new MemoryStream((int)parts))
         {
             using (GZipStream decompressionStream = new GZipStream(msi, CompressionMode.Decompress))
             {
                 decompressionStream.CopyTo(mso);
                 part.data = mso.ToArray();
                 //Console.WriteLine($"Block size: {part.data.Length} Byte");
                 processedParts.Enqueue(part);
             }
         }
     }
 }
示例#3
0
        static double parts;                                                                    //размер разбиения - 1 части

        public static int Run(string inputFile, string outputfile, Mode compressMode)
        {
            bool fileEnd = false;                            // флаг того что мы полностью считали исходный файл

            int maxThreads = Environment.ProcessorCount - 2; //Делаем количество "компрессных" потоков равными количиству ядер и -2 на чтение и запись

            if (maxThreads < 1)
            {
                maxThreads = 1;                 // на 2ух ядерном в любом  случае будет меделенно как не крути, просто подстраховка
            }
            #region ВЫЧИСЛЯЕМ РАЗМЕР БЛОКОВ
            double byteLeft = new FileInfo(inputFile).Length; //размер несчитанного файла
            if (byteLeft > 3.2e10 || byteLeft == 0)
            {
                ConsoleMesseges.FileSizeException(); return(1);
            }                                                                                          //

            double freeRam = new Microsoft.VisualBasic.Devices.ComputerInfo().AvailablePhysicalMemory; // доступная оперативка
            if (byteLeft <= freeRam / (maxThreads * 2))
            {
                parts = byteLeft / (maxThreads * 2);                                         //2 - это доп мемори стрим под каждый поток сжатия
            }
            else
            {
                parts = freeRam / (maxThreads * 2);
            }
            if (parts > 2147483646)
            {
                parts = 2147483646;                     // размер блоков: не  больше чем позволяент инт 2147483647 байт ~ 2Гб
            }
            #region Прогрессбар
            double totalParts    = byteLeft / parts;
            double preparedParts = 1;
            var    progress      = new ProgressBar();
            progress.Report(0);
            Console.WriteLine($"Max Threads: {maxThreads}");
            Console.WriteLine($"Total Parts: {(int)totalParts}");
            #endregion

            /*---------------DEBUG---------------------*/
            //Console.WriteLine($"Operation   = Compress");
            //Console.WriteLine($"InputFile   = {inputFile}");
            //Console.WriteLine($"Outputfile  = {outputfile}");
            //Console.WriteLine($"Work Threads: {maxThreads}");
            //Console.WriteLine($"File size: {byteLeft / 1024 / 1024} Mb");
            //Console.WriteLine($"Free Ram: {freeRam / 1024 / 1024} Mb");
            //Console.WriteLine($"Block size: {parts} Byte");
            //Console.WriteLine($"Block size: {parts / 1024} Kb");
            //Console.WriteLine($"Block size: {parts / 1024 / 1024} Mb");
            /*---------------DEBUG---------------------*/
            #endregion


            #region ReadThread - поток для чтения исходного файла
            Thread readThread = new Thread(() =>
            {
                using (FileStream readStream = new FileStream(inputFile, FileMode.Open))
                {
                    if (compressMode == Mode.Compress)
                    {
                        while (byteLeft != 0)
                        {
                            if (threadsBreak)
                            {
                                break;
                            }
                            if (notProcessedParts.Count < maxThreads + 1) //не закидываем в оперативу больше чем нужно тредам, с запасным
                            {
                                byte[] buf = parts < byteLeft ? new byte[(int)parts] : new byte[(int)byteLeft];
                                readStream.Read(buf, 0, buf.Length);
                                FilePart f = new FilePart(buf);
                                //Console.WriteLine($"Чтение.. {f.partId} size: {f.data.Length} Byte");
                                notProcessedParts.Enqueue(f);
                                byteLeft -= buf.Length;
                            }
                        }
                    }

                    if (compressMode == Mode.Decompress)
                    {
                        byte[] sizeIdBytes = new byte[4];
                        long curentSeek    = 0;

                        readStream.Seek(-sizeIdBytes.Length, SeekOrigin.End);
                        readStream.Read(sizeIdBytes, 0, sizeIdBytes.Length);
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(sizeIdBytes);
                        }
                        parts = BitConverter.ToInt32(sizeIdBytes, 0); // размер разжатой 1ой пачки
                        //Console.WriteLine($"part: {parts}\n");

                        readStream.Seek(-sizeIdBytes.Length - 4, SeekOrigin.End);
                        readStream.Read(sizeIdBytes, 0, sizeIdBytes.Length);
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(sizeIdBytes);
                        }
                        int partsCount = BitConverter.ToInt32(sizeIdBytes, 0); // количество сжатых блоков в файле

                        for (int i = partsCount; i > 0; i--)
                        {
                            if (threadsBreak)
                            {
                                break;
                            }
                            while (notProcessedParts.Count > maxThreads + 1)
                            {
                                Thread.Sleep(5);
                            }

                            readStream.Seek((-8 * i) - 8, SeekOrigin.End);  //чтение карты

                            readStream.Read(sizeIdBytes, 0, sizeIdBytes.Length);
                            if (BitConverter.IsLittleEndian)
                            {
                                Array.Reverse(sizeIdBytes);
                            }
                            int id = BitConverter.ToInt32(sizeIdBytes, 0);

                            readStream.Read(sizeIdBytes, 0, sizeIdBytes.Length);
                            if (BitConverter.IsLittleEndian)
                            {
                                Array.Reverse(sizeIdBytes);
                            }
                            int dataLenght = BitConverter.ToInt32(sizeIdBytes, 0);
                            //Console.WriteLine($"part {i} : id = {id}; dat = {dataLenght}");

                            byte[] buf = new byte[dataLenght];
                            readStream.Seek(curentSeek, SeekOrigin.Begin); //чтение частей
                            readStream.Read(buf, 0, dataLenght);
                            curentSeek += dataLenght;
                            FilePart f  = new FilePart(id, buf);
                            //Console.WriteLine($"Чтение.. {f.partId} size: {f.data.Length} Byte\n");
                            notProcessedParts.Enqueue(f);
                        }
                    }
                }
                fileEnd = true; //файл дочитан
            });
            #endregion


            #region WriteThread - поток для записи сжатого файла
            Thread writeThread = new Thread(() =>
            {
                using (FileStream writeStream = new FileStream(outputfile, FileMode.Create))
                {
                    if (compressMode == Mode.Compress)
                    {
                        byte[] partOfMap         = new byte[4];
                        Queue <byte[]> sizeAndId = new Queue <byte[]>(); //сохраняем в нее размер сжатых пачек и их айди для дальнейшей записи в "карту" файла.
                        while (true)
                        {
                            if (threadsBreak)
                            {
                                break;
                            }
                            if (fileEnd && notProcessedParts.Count == 0 && processedParts.Count == 0 && workerThreads == 0)
                            {
                                break;
                            }
                            if (processedParts.Count != 0)
                            {
                                if (processedParts.TryDequeue(out FilePart f))
                                {
                                    partOfMap = BitConverter.GetBytes(f.partId);
                                    if (BitConverter.IsLittleEndian)
                                    {
                                        Array.Reverse(partOfMap);                                  // это id
                                    }
                                    sizeAndId.Enqueue(partOfMap);

                                    partOfMap = BitConverter.GetBytes(f.data.Length);
                                    if (BitConverter.IsLittleEndian)
                                    {
                                        Array.Reverse(partOfMap);                                  // потом сжатый размер
                                    }
                                    sizeAndId.Enqueue(partOfMap);

                                    writeStream.Write(f.data, 0, f.data.Length);
                                    //Console.WriteLine($"Запись.. {f.partId}"); //DEBUG
                                    f.Dispose();

                                    progress.Report(preparedParts / totalParts);     //прогрессбар
                                    preparedParts++;
                                }
                            }
                        }

                        partOfMap = BitConverter.GetBytes(sizeAndId.Count / 2);         // предпоследние 4 байта будет количество всех сжатых 4х байтных пачек содержащих id
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(partOfMap);
                        }
                        //Console.WriteLine($"Vsego id and size: {sizeAndId.Count}"); //DEBUG
                        sizeAndId.Enqueue(partOfMap);

                        partOfMap = BitConverter.GetBytes((int)parts);         // последние 4 байта размер 1ой распакованной части
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(partOfMap);
                        }
                        sizeAndId.Enqueue(partOfMap);

                        while (sizeAndId.Count != 0)
                        {
                            byte[] a = sizeAndId.Peek();
                            writeStream.Write(sizeAndId.Dequeue(), 0, 4);
                        }
                    }


                    if (compressMode == Mode.Decompress)
                    {
                        while (true)
                        {
                            if ((fileEnd && notProcessedParts.Count == 0 && processedParts.Count == 0 && workerThreads == 0) || threadsBreak)
                            {
                                break;
                            }
                            if (processedParts.Count != 0)
                            {
                                if (processedParts.TryDequeue(out FilePart f))
                                {
                                    writeStream.Seek((int)parts * (f.partId - 1), SeekOrigin.Begin);

                                    writeStream.Write(f.data, 0, f.data.Length);
                                    //Console.WriteLine($"Запись.. {f.partId}");
                                    f.Dispose();
                                    progress.Report(preparedParts / totalParts);     //прогрессбар
                                    preparedParts++;
                                }
                            }
                        }
                    }
                    threadsDone.Set();
                }
            });
            #endregion

            readThread.Start();
            writeThread.Start();

            #region Workthreads
            for (int i = 0; i < maxThreads; i++)
            {
                Thread workThread = new Thread(() =>
                {
                    lock (workerThreadsLocker) workerThreads++;

                    while (true)
                    {
                        if (threadsBreak)
                        {
                            break;
                        }
                        if (fileEnd && notProcessedParts.Count == 0)
                        {
                            break;
                        }
                        if (notProcessedParts.Count != 0)
                        {
                            if (notProcessedParts.TryDequeue(out FilePart f))
                            {
                                //Console.WriteLine($"Сжатие - {f.partId}"); //DEBUG
                                if (compressMode == Mode.Compress)
                                {
                                    Compressing <FilePart>(f);
                                }
                                else if (compressMode == Mode.Decompress)
                                {
                                    Decompressing <FilePart>(f);
                                }
                            }
                        }
                    }
                    lock (workerThreadsLocker) workerThreads--;
                });
                workThread.Start();
            }
            #endregion

            if (threadsBreak)
            {
                progress.Dispose(); return(1);
            }
            else
            {
                threadsDone.WaitOne();
                progress.Dispose();
                if (compressMode == Mode.Compress)
                {
                    Console.WriteLine("Compressing Done!");
                }
                if (compressMode == Mode.Decompress)
                {
                    Console.WriteLine("Decompressing Done!");
                }
            }
            return(0);
        }