Энциклопедия Turbo Pascal. Главы 5-8
Страница 21. Восемь в семь


Восемь в семь

     Большинство современных компьютеров используют размеры  бай-
та,  которые являются степенью двойки. Заглавные и строчные буквы
и знаки пунктуации составляют приблизительно 63 кодов, что требу-
ет  6 бит для представления байта (6-битовый байт может принимать
значения от 0 до 63).  Однако, большинство компьютеров использует
8-битовый байт;  таким образом 25% байта тратится зря в текстовых
файлах.  Следовательно,  можно упаковать 4  символа  и  3  байта.
Единственная проблема состоит в том,  что в коде ASCII существует
более 63 различных символов.  Это означает, что некоторые необхо-
димые  символы требуют по крайней мере 7 бит.  Можно использовать
представление не в коде ASCII, но это нежелательно. Самый простой
вариант - это упаковка 8 символов в 7 байт, основывающийся на том
факте,  что ни буквы,  ни знаки пунктуации не используют восьмого
бита в байте.  Следовательно,  вы можете использовать восьмой бит
каждого из семи байт для запоминания восьмого символа. Данный ме-
тод экономит 12,5% памяти. Однако, многие компьютеры, включая IBM
PC,  используют весь 8-битовый байт для представления специальных
и графических символов. Кроме того, некоторые текстовые процессо-
ры используют восьмой бит для задания команд текстовой обработки.
Следовательно, использование данного типа упаковки данных возмож-
но только с файлами типа ASCII,  которые не  используют  восьмого
бита.

     Для демонстрации того, как это происходит, рассмотрим следу-
ющие 8 символов, представленные как 8-битовые байты:

     байт 1   0111 0101
     байт 2   0111 1101
     байт 3   0010 0011
     байт 4   0101 0110
     байт 5   0001 0000
     байт 6   0110 1101
     байт 7   0010 1010
     байт 8   0111 1001

     Как вы видите,  восьмой байт всегда равен 0.  Так происходит
всегда, кроме случая, когда восьмой бит используется для контроля
четности. Самый простой способ сжатия 8 символов в 7 байт состоит
в том, чтобы распределить 7 значащих бит байта 1 в семь неисполь-
зуемых  восьмых битовых позиций байтов 2-8.  Семь оставшихся байт
будут выглядеть следующим образом:

     байт 2   1111 1101
     байт 3   1010 0011
     байт 4   1101 0110
     байт 5   0001 0000
     байт 6   1110 1101
     байт 7   0010 1010
     байт 8   1111 1001
                             байт 1 - читать вниз

     Для восстановления  байта 1 вы собираете вместе восьмые биты
каждого из 7 байт.

     Данный метод сжимает любой текстовый  файл  на  1/8  или  на
12,5%.  Это весьма существенная экономия. Например, если вы пере-
давали исходный текст вашей любимой программы другу по телефонной
линии  на  большое  расстояние,  то вы сократите расходы на 12,5%
(напомним,  что объектный и исполнительные коды программы требуют
всех 8 бит).

     Следующая программа  осуществляет  сжатие  текстового файла,
используя описанный метод:

     { данная программа сжимает 8 байт в семь }
     program compress_file;
     type
       str80 = string[80];

     var
       inf, outf: str80;
       ch: char;
       t: integer;

     procedure compress(inf, outf: str80);
     var
       infile, outfile: file of byte;
       ch, ch2: byte;

       done: boolean;

     begin
       assign(infile, inf);
       reset(infile);
       assign(outfile, outf);
       rewrite(outfile);

       done := FALSE;
       repeat
         Read(infile, ch);
         if eof(infile) then
           done := TRUE
         else
         begin
           ch:=ch shl 1; {выдвижение свободного бита}
           for t := 0 to 6 do
           begin
              if eof(infile) then
              begin
                ch2 := 0;
                done := TRUE;
              end else Read(infile, ch2);
              ch2:=ch2 and 127; {сброс старшего бита }
              ch2:=ch2 or ((ch shl t) and 128); {pack bits}
              Write(outfile, ch2);
           end;
         end; {else}
       until done;

       WriteLn('file compressed'); 7
       close(infile); close(outfile);
     end; {compress}

     procedure decompress(inf, outf: str80);
     var
       infile, outfile:file of byte;
       ch, ch2: byte;
       s: array[1..7] of byte;
       done: boolean;

     begin
       assign(infile, inf);
       reset(infile);
       assign(outfile,outf);
       rewrite(outfile);

       done := FALSE;
       repeat
       ch := 0;
       for t := 1 to 7 do
       begin
         if eof(infile) then
           done := TRUE
         else
         begin
           Read(infile, ch2);
           s[t] := ch2 and 127; {сброс старшего бита}
           ch2 := ch2 and 128; {очистка младших битов}
           ch2 := ch2 shr t; {распаковка}
           ch := ch or ch2; {встраивание восьмого байта}
         end;
       end;
       Write(outfile, ch);
       for t := 1 to 7 do Write(outfile, s[t]);
       until done;

       WriteLn('file decompressed');
       close(infile); close(outfile);
     end; {decompress}

     begin
       Write('введите имя входного файла: ');
       ReadLn(inf);
       Write('введите имя выходного файла: ');
       ReadLn(outf);
       Write('сжатие или распаковка (C or D): ');
       ReadLn(ch);
       if upcase(ch)='C' then compress(inf, outf)
       else if upcase(ch)='D' then decompress(inf,outf);
     end.


     Данная программа  достаточно сложна,  так как различные биты
должны быть сдвинуты циклически.  Если вы помните,  что надо сде-
лать  с  первым  из каждых восьми байт то легче понять программу.
Для того,  чтобы программа работала правильно,  длина  сжимаемого
файла должна быть кратна 8. Это означает, что очень короткие фай-
лы (меньше 64 символов) будут длинее,  чем несжатая версия. Одна-
ко, на длинных файлах этого не произойдет.

 
« Предыдущая статья   Следующая статья »