|
Разработка программы сжатия и восстановления файлов с помощью фиксированного блочного кода постоянного смещения
Разработка программы сжатия и восстановления файлов с помощью фиксированного блочного кода постоянного смещения
3 Содержание Краткое описание работы программы Код программы Результаты тестирования приложения Краткое описание работы программыИспользуемые компоненты среды Delphi:1. SaveDialog, OpenDialog. Копомненты необходимые для чтения и сохранения файлов, а так же получения названия файла и его пути до него.2. Button - компонент кнопка.3. ListBox - компонент, состоящий из строк, хранит кодовые слова.4. ProgressBar - компонент, необходимый для отслеживания этапов выполнения программы.5. Label - компонент для вывода строковых данных.Краткое описание работы приложения:1. При нажатии кнопки Button1 “Считать для сжатия” происходит получение имени считываемого файла и пути до него. Измеряется размер файла (функция FileSize). Полностью очищаются Label.2. При нажатии кнопки Button2 “Проверить” происходит обнуление всех необходимых для работы переменных. Запускается процесс считывания (по-байтово) и анализа сжимаемого файла, в результате которого высчитывается средняя длинна кодового слова. Она необходима для определения возможности сжатия. В зависимости от полученного результата выводится сообщение о том, что файл можно сжимать, в противном случае, что нельзя. Так же формируется массив частот повторений символов в файле, необходимый для соотнесения кодовых слов и символов в файле.3. При нажатии Button3 “Сжать” происходит побайтовое считывание сжимаемого файла с помощью команды BlockRead. Далее происходит соотнесение считанного байта кодовому слову. Алгоритм соотнесения основан на частоте появлений символов в файле. Чем чаще данный символ встречается в файле, тем меньшей длинны ему присваивается кодовое слово. Запись нового файла производится с помощью команды BlockWrite так же по-байтово. Новому файлу присваивается новое расширение. Когда файл полностью считан, выполняется проверка на наличие оставшихся битов. Если таковые имеются, то пустое пространство забивается нулями до тех пор, пока количество битов не будет равно 8.4. При нажатии Button4 “Считать для восстановления” происходит получение имени сжатого файла, пути до него.5. При нажатии Button5 “Восстановить" происходит побайтового считывание файла. Алгоритм разжатия состоит из двух этапов. На первом этапе происходит считывание файла блоками размером в 1 байт. Производится запись считанных байтов в специальную переменную. Когда длина переменной составляет 16 символов или более, начинается анализ считанной информации. Производится проверка на соответствие кодовым словам и последующая запись полученных значений в новый файл. На втором этапе производится проверка на остаток и удаление лишних данных (случай, когда было выполнено дополнение нулями при сжатии).Код программы:unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ComCtrls;typeTForm1 = class (TForm)ListBox1: TListBox;OpenDialog1: TOpenDialog;SaveDialog1: TSaveDialog;Button1: TButton;Button2: TButton;Button3: TButton;Label1: TLabel;ProgressBar1: TProgressBar;Button4: TButton;Button5: TButton;Label3: TLabel;Label4: TLabel;Label2: TLabel;Label5: TLabel;Label6: TLabel;Label7: TLabel;Label8: TLabel;SaveDialog2: TSaveDialog;OpenDialog2: TOpenDialog;procedure Button1Click (Sender: TObject);procedure FormCreate (Sender: TObject);procedure Button2Click (Sender: TObject);procedure Button3Click (Sender: TObject);procedure Button4Click (Sender: TObject);procedure Button5Click (Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm1: TForm1;f,f1,f2,f3: file;buff: byte;conR,conW: string;a: array [0.255] of real; // массив вероятностейword: array [0.255] of string; // массив кодовых словl: array [0.255] of byte; // массив длин кодовых словe: array [0.255] of real; // массив номеров элементовinf: array [0.255] of integer; // массив служебной информацииi,j,k,size,prog,buff1,buff3,check,dop: integer;sl,sum,sort,sort1,buff2: real;implementation{$R *.dfm}procedure TForm1.Button1Click (Sender: TObject);beginif OpenDialog1.Execute thenAssignFile (f,OpenDialog1.FileName); // считываем имя файла и путь до негоReset (f,1); // открываем файл для чтения и измененияsize: =FileSize (f); // измеряем размер файлаLabel4.Caption: =IntToStr (size) + ' байт';// выводим размер файла в Label4Label2.Caption: ='';Label6.Caption: ='';Label8.Caption: ='';end;procedure TForm1.Button2Click (Sender: TObject);begin ProgressBar1.Position: =0; // обнуляем ProgressBarprog: =0; // обнуляем счетчик для Progress Barsl: =0; // обнуляем переменную средней длинныsum: =0; // обнуляем счетчик повторений символовsort: =0; // обнуляем переменные для сортировки массива номеров элементовsort1: =0;buff: =0;for i: =0 to 255 dobegine [i]: =i; // производим обнуление элементов массивов кодовых слов, длин кодовых слов, вероятностей и номеров элементов.l [i]: =0;word [i]: ='';a [i]: =0;end;while not EOF (f) do // считываем файл до его окончанияbeginBlockRead (f,buff,1); // считываем блоки в 1 байтa [buff]: =a [buff] +1; // записываем этот байт в массивprog: =prog+1;ProgressBar1.Position: =round ( (prog/size) *100);end;for i: =0 to 255 dobeginword [i]: =ListBox1. Items.Strings [i]; // записываем кодовые слова из ListBox1 в массив кодовых словif a [i] <>0 then // проверяем наличие байта в массивеbeginsum: = sum+a [i]; // считаем количество повторений данного байтаend;end;CloseFile (f); // закрываем файл после чтенияfor i: =0 to 255 dobeginfor j: =0 to 254 dobeginif (a [j] < a [j+1]) thenbeginsort: =a [j]; // производим сортировку массива номеров элементовsort1: =e [j];a [j]: =a [j+1];a [j+1]: =sort;e [j]: =e [j+1];e [j+1]: =sort1;end;end;end;for k: =0 to 255 dobeginif a [k] <>0 then // проверяем наличие элементов в массивеbegina [k]: =a [k] /sum; // считаем у появления символаl [k]: =length (word [k]); // высчитываем длину кодовых словsl: =sl+l [k] *a [k]; // получаем значение средней длинныend;end;Label2.Caption: =FloatToStr (sl); // выводим значение средней длиныif sl < 8 then // проверяем значение средней длиныbeginButton3.Enabled: =true; // активируем кнопку “Сжать”showmessage ('Сжатие возможно');end;if sl > 8 thenbeginshowmessage ('Сжатие невозможно');end;end;procedure TForm1.Button3Click (Sender: TObject);beginSaveDialog1.FileName: =OpenDialog1.FileName+'.gop';// задаем новое расширение для сжатого файлаSaveDialog1.DefaultExt: ='gop';if SaveDialog1.Execute thenbeginAssignFile (f1, SaveDialog1.FileName);Rewrite (f1,1); // открываем файл для записиend;buff1: =0;i: =0;while i <> 256 do // записываем служебную информацию в новый файл.beginbuff1: =StrToInt (FloatToStr (e [i]));BlockWrite (f1,buff1,1);Reset (f,1);i: =i+1;end;buff1: =0;seek (f1,256); // осуществляем переход на 256-ой байт в файлеProgressBar1.Position: =0;prog: =0;while not EOF (f) do // считываем файл до его окончанияbeginBlockRead (f,buff,1); // считываем блоки размером 1 байтbuff1: =buff1+1;prog: =prog+1;for i: =0 to 255 dobeginif buff=e [i] then // проверяем совпаденияbeginconR: =conR+word [i]; // записываем соответствующее кодовое словоif length (conR) >=8 then // проверяем длину переменнойbeginconW: =copy (conR,1,8); // копируем первые 8 символовbuff2: = ( (strtoint (conW [1])) *128) + ( (strtoint (conW [2])) *64) + ( (strtoint (conW [3])) *32) + ( (strtoint (conW [4])) *16) + ( (strtoint (conW [5])) *8) + ( (strtoint (conW [6])) *4) + ( (strtoint (conW [7])) *2) + (strtoint (conW [8]));// переводим скопрированную информацию в десятичное числоbuff3: =strtoint (floattostr (buff2));BlockWrite (f1,buff3,1); // записываем результат в новый файлDelete (conR,1,8); // удаляем первые 8 символовend;if (EOF (f) =true) and (conR<>'') and (length (conR) <8) then// проверяем наличие остаткаbegink: =0;check: =length (conR); // вычисляем длину остаткаdop: =8-check; // вычисляем количество необходимых для заполнения битовwhile k<>dop do // цикл дополнения нулямиbeginconR: =conR+'0'; // дописываем нулиk: =k+1;end;conW: =copy (conR,1,8); // копируем данныеbuff2: = ( (strtoint (conW [1])) *128) + ( (strtoint (conW [2])) *64) + ( (strtoint (conW [3])) *32) + ( (strtoint (conW [4])) *16) + ( (strtoint (conW [5])) *8) + ( (strtoint (conW [6])) *4) + ( (strtoint (conW [7])) *2) + (strtoint (conW [8]));// переводим скопированную информацию в десятичное числоbuff3: =strtoint (floattostr (buff2));BlockWrite (f1,buff3,1); // записываем полученные значенияend;end;end;ProgressBar1.Position: =Round ( (prog/size) *100);end;Label6.Caption: =Inttostr (FileSize (f1)) + ' байт';// выводим размер полученного файлаLabel8.Caption: =IntToStr (Round (100- (FileSize (f1) *100/size))) + ' %';// считаем процент сжатия файлаShowMessage ('Файл успешно сжат');CloseFile (f); // закрываем файлыCloseFile (f1);conR: =''; // обнуляем переменныеconW: ='';Button3.Enabled: =false;end;procedure TForm1.Button4Click (Sender: TObject);beginif OpenDialog2.Execute thenAssignFile (f2,OpenDialog2.FileName); // считываем имя файла и путь до негоReset (f2,1); // открываем файл для чтения и записиsize: =FileSize (f2); // запоминаем размер файлаLabel4.Caption: =IntToStr (size) + ' байт';Label2.Caption: ='';Label6.Caption: ='';Label8.Caption: ='';Button5.Enabled: =true;for i: =0 to 255 dobeginBlockRead (f2,buff,1);inf [i]: =buff; // задаем соответствие по служебной информацииword [i]: =ListBox1. Items.Strings [i]; // считываем массив кодовых словend;end;function IntToBin (n: Integer): String; // перевод из десятичного значения в двоичноеvarm: integer;beginResult: ='';while n<>0 dobeginif n and 1=0 then Result: ='0'+Result else Result: ='1'+Result;n: =n shr 1;end;if length (result) <8 thenbeginfor m: =1 to 8-length (result) do result: ='0'+result;end;end;procedure TForm1.Button5Click (Sender: TObject);beginif SaveDialog2.Execute thenbeginProgressBar1.Position: =0;prog: =0;AssignFile (f3, SaveDialog2.FileName); // считываем имя файла и путь до негоReWrite (f3,1); // открываем файл для записиconR: =''; // обнуляем рабочие переменныеconW: ='';seek (f2,256); // переходим на 256-ой байтform1.Refresh;While not EOF (f2) do // считываем файл до его окончанияbeginif length (conR) <16 then // проверяем длину рабочей переменнойbeginBlockRead (f2,buff,1); // считываем файл по 1 байтуconR: =conR+IntToBin (buff); // переводим считанный байт в двоичное числоprog: =prog+1;end;if length (conR) >=16 then // проверяем длину переменнойДальнейший код основан на проверке определенных элементов кодовых слов. Так как кодовые слова имеющие смещение отличаются от предыдущих кодовых слов без смещения появлением в начале кодового слова дополнительных нулей, то необходимо проверять всего два элемента в кодовом слове. Поэтому массив разбивается на промежутки, что ускоряет поиск подходящих кодовых слов. Для первых 6 элементов массива кодовых слов достаточно одного условия проверки.beginif conR [1] ='1' thenbeginconW: =copy (conR,1,2); // копируем кодовое словоfor i: =0 to 1 dobeginif word [i] =conW then // сравниваем массив кодовых слов в заданном промежутке с выделенным кодовым словомbeginBlockWrite (f3, inf [i],1); // записываем полученный элемент в файлDelete (conR,1,2); // удаляем кодовое словоbreak; // прерываем циклend;end;endelseif conR [2] ='1' thenbeginconW: =copy (conR,1,4);for i: =2 to 5 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,4);Break;end;end;endelseif (conR [2] ='0') and (conR [3] ='1') thenbeginconW: =copy (conR,1,6);for i: =6 to 13 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,6);Break;end;end;endelseif (conR [3] ='0') and (conR [4] ='1') thenbeginconW: =copy (conR,1,8);for i: =14 to 29 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,8);Break;end;end;endelseif (conR [4] ='0') and (conR [5] ='1') thenbeginconW: =copy (conR,1,10);for i: =30 to 61 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,10);Break;end;end;endelseif (conR [5] ='0') and (conR [6] ='1') thenbeginconW: =copy (conR,1,12);for i: =62 to 125 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,12);Break;end;end;endelseif (conR [6] ='0') and (conR [7] ='1') thenbeginconW: =copy (conR,1,14);for i: =126 to 253 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,14);Break;end;end;endelseif (conR [7] ='0') and (conR [8] ='1') thenbeginconW: =copy (conR,1,16);for i: =254 to 255 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,16);Break;end;end;end;if (EOF (f2) = true) and (length (conR) >1) then// проверяем остатокbeginfor j: =1 to length (conR) do // считаем длину остаткаbeginif conR='' then break;Проверка на остаток производится аналогично предыдущей процедуре. Поиск кодовых слов в остатке производится путем проверки определенных элементов кодовых слов. Сравнение и запись идентичны.if conR [1] ='1' thenbeginconW: =copy (conR,1,2);for i: =0 to 1 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);delete (conR,1,2);break;end;end;endelseif (conR [1] ='0') and (conR [2] ='1') thenbeginconW: =copy (conR,1,4);for i: =2 to 5 dobeginif word [i] =conW thenbeginblockWrite (f3, inf [i],1);delete (conR,1,4);break;end;end;endelseif (conR [2] ='0') and (conR [3] ='1') thenbeginconW: =copy (conR,1,6);for i: =6 to 13 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,6);break;end;end;endelseif (conR [3] ='0') and (conR [4] ='1') thenbeginconW: =copy (conR,1,8);for i: =14 to 29 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,8);break;end;end;endelseif (conR [4] ='0') and (conR [5] ='1') thenbeginconW: =copy (conR,1,10);for i: =30 to 61 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,10);break;end;end;endelseif (conR [5] ='0') and (conR [6] ='1') thenbeginconW: =copy (conR,1,12);for i: =62 to 125 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,12);break;end;end;endelseif (conR [6] ='0') and (conR [7] ='1') thenbeginconW: =copy (conR,1,14);for i: =126 to 253 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,14);break;end;end;endelseif (conR [7] ='0') and (conR [8] ='1') thenbeginconW: =copy (conR,1,16);for i: =254 to 255 dobeginif word [i] =conW thenbeginBlockWrite (f3, inf [i],1);Delete (conR,1,16);break;end;end;end;end;end;end;ProgressBar1.Position: =Round ( (prog/size) *100);end;Label6.Caption: =IntToStr (FileSize (f3)) + ' байт';ShowMessage ('Процедура завершена');end;CloseFile (f3);CloseFile (f2);end;procedure TForm1.FormCreate (Sender: TObject);beginfor i: =0 to 255 doa [i]: =0;e [i]: =i;end;end.Рис.1. Интерфейс программыРезультаты тестирования приложения:Работа приложения тестировалась на различных типах файлов. Использовались файлы графического, текстового, мультимедийного и других форматов. Все данные о процессах сжатия изложены в следующей таблице.|
Имя\тип файла | Размер до сжатия | Имя сжатого файла | Размер после сжатия | Сжатие | | 8bit org.bmp | 68,7 КБ | 8bit org.bmp.gop | 18,1 КБ | 73% | | 24bit org.bmp | 203 КБ | 24bitorg.bmp.gop | 54,1 КБ | 73% | | DOC org.doc | 1516 КБ | DOC org.doc.gop | 843 КБ | 45% | | RTF org.rtf | 711 КБ | RTF org.rtf.gop | 539 КБ | 24% | | TXT org.txt | 1 619 байт | TXT org.txt.gop | 1 392 байт | 14% | | midi org.mid | 40 075 байт | midi org.mid.gop | 36 551 байт | 9% | | Unit1 org.pas | 15 721 байт | Unit1 org.pas.gop | 9 068 байт | 42% | | |
Максимальный размер сжатия составляет 73-75%. В данной таблице отображены форматы файлов, которые можно было сжать. Однако некоторые форматы в связи со своей спецификой несут в себе определенные методы сжатия данных, что не позволяет приложению производить операции над ними. К таким форматам относятся: *.tiff, *.gif, *.wav, *.jpeg, *.avi, *.mp3, *.3gp, *.odt. Процент сжатия характеризуется длиной кодовых слов и смещением. В данном случае максимальный процент сжатия будет 75%, так как минимальная длина кодового слова равна 2. Сжатие файла происходит побайтово, следовательно заменяем кодовым словом из 2 бит блоки из 8 бит. Лучше всего подвергаются сжатию текстовые документы, менее сжимаемы и плохо сжимаемы мультимедия файлы.
|
|