Расширение набора базовых классов .NET Framework
Страница 4. Использование сжатого бинарного потока


 

Использование сжатого бинарного потока

Одной из часто возникающих задач является сохранение данных различного типа в бинарном потоке. В .NET Framework для этого используются классы: BinaryReader и BinaryWriter из пространства имен System.IO. В AcedUtils для этой цели предназначены классы AcedBinaryReader и AcedBinaryWriter, которые позволяют не только перенести информацию в бинарный массив, но также сжать ее методом, подобным используемому в популярной библиотеке ZLib, и защитить контрольной суммой Адлера. При необходимости, упакованный бинарный массив может быть зашифрован методом CAST5, используемым в программе PGP, и защищен односторонней хэш-функцией RipeMD-160. Пример:

private string _message;
private byte[] _binaryData;
private DateTime _time;
private byte[] SaveData(Guid guid)
{
AcedBinaryWriter bw = new AcedBinaryWriter();
bw.WriteString(_message);
bw.WriteByteArray(_binaryData);
bw.WriteDateTime(_time);
return bw.GetBytes(guid, true);
}
private void LoadData(Guid guid, byte[] bytes)
{
AcedBinaryReader br = new AcedBinaryReader(guid, bytes, 0, bytes.Length);
_message = br.ReadString();
_binaryData = br.ReadByteArray();
_time = br.ReadDateTime();
}
private void TestBinaryStream(Guid guid)
{
_message = "Hello world!";
_binaryData = new byte[1000000];
for (int i = 0; i < 1000000; i++)
_binaryData[i] = (byte)i;
_time = DateTime.Now;
byte[] m = SaveData(guid);
MessageBox.Show(m.Length.ToString());
_message = "";
_binaryData = null;
_time = new DateTime(0);
LoadData(guid, m);
MessageBox.Show(_message + " - " + _time.ToString());
}

Метод SaveData() помещает значения полей _message, _binaryData и _time в бинарный поток. Вызов bw.GetBytes() возвращает массив байт, содержащий данные потока. Позже, в методе LoadData(), когда надо прочитать данные из потока, этот массив передается как параметр в конструктор класса AcedBinaryReader. Потом значения соответствующих полей считываются из потока методами этого класса. Метод TestBinaryStream() инициализирует сохраняемые поля, в частности, в _binaryData помещается массив длиной 1000000 байт, состоящий из последовательных значений 0, 1, 2, …, 254, 255, 0, 1, … Затем этот метод вызывает SaveData() для сохранения полей в потоке. На экране показывается длина полученного массива байт. На всякий случай, поля обнуляются. Затем вызывается метод LoadData() для восстановления значений полей. В том, что значения считались правильно, можно убедиться по сообщению, выводимому на экран.

Метод TestBinaryStream() принимает параметр типа Guid. Этот параметр передается в методы SaveData() и LoadData(), а затем в метод AcedBinaryWriter.GetBytes() и в конструктор класса AcedBinaryReader. Guid здесь используется в качестве ключа шифрования. Если передается значение Guid.Empty, то шифрование и расчет односторонней хэш-функции не выполняется. Если Guid отличен от Guid.Empty, данные закрываются блочным шифром CAST5 в режиме CFB, а затем к ним добавляется 20-байтная сигнатура, рассчитанная методом RipeMD-160. Длина выходного массива, возвращаемого вызовом SaveData(Guid.Empty) может быть, например, 389 байт, а возвращаемого вызовом SaveData(Guid.NewGuid()) за счет сигнатуры будет на 20 байт больше, т.е. 409 байт.

Второй параметр метода AcedBinaryWriter.GetBytes() определяет, нужно ли сжимать данные, помещенные в выходной поток. Если в приведенном выше примере в методе SaveData() поменять значение параметра deflate с True на False, то длина выходного массива составит 1000044 или 1000064 байт. Зато, при этом повысится быстродействие, т.к. не нужно будет тратить время на упаковку/распаковку данных. Сжатие выполняется экземпляром класса AcedDeflator, распаковка - зкземпляром класса AcedInflator.

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