Двоичные файлы с прямым доступом к записям
Для сохранения данных в файле и выборочного доступа к записям (на ввод и вывод).
Примечание. Для реализации прямого доступа к записям необходимо иметь способ определения адреса записи в файле. Адресом является смещение до первого байта требуемой записи от начала файла. Первый байт файла имеет смещение 0.
Существует два основных способа решения этой задачи.
1. Все записи файла имеют одинаковую (известную) длину.
В этом случае нет смысла использовать какую-либо дополнительную информацию о месторасположении записей.
1) Для обеспечения одинаковых размеров всех записей необходимо:
• чтобы значения строковой переменной во всех записях имели одинаковую длину. Для этого необходимо каждое значение дополнить пробелами до требуемого размера (см. метод PadRight (int);).
• во-вторых, чтобы все символы – русские и английские – кодировались одинаковым количеством байтов (например, по 2 байта), необходимо в классе кодировки выбрать Unicode.
2) При определении адреса требуемой записи, необходимо учесть, что размер каждой строки в записи файла вдвое больше числа ее символов (Unicode – 2 байта), плюс один байт на каждую строку записи. В этом байте хранится длина строки.
Для ввода-вывода рекомендуется использовать двоичный поток. Поиск требуемых записей может быть организован как на диске, так и в оперативной памяти.
1.1 Поиск требуемых записей, выполняется на диске
Примечание. Это случай, когда файл невозможно целиком прочитать в память или когда количество операций ввода-вывода невелико.
int kurs = 1; //4 байта
string fio = "Иванов "; //15 символов -> 31 б.
fs = new FileStream ("testdata", FileMode.Create);
dataOut = new BinaryWriter (fs, Encoding.Unicode);
dataOut.Write (kurs);
dataOut.Write (fio);
kurs = 2;
fio = "Smit ";
dataOut.Write (kurs);
dataOut.Write (fio);
kurs = 3;
fio = "Григорьева ";
dataOut.Write (kurs);
dataOut.Write (fio);
dataOut.Close();
fs = new FileStream ("testdata", FileMode.Open);
dataIn = new BinaryReader(fs, Encoding.Unicode);
fs.Seek(35, SeekOrigin.Begin); //указатель на 2-ю запись
// Длина записи = 4+(15*2)+1 = 35
kurs = dataIn.ReadInt32(); // читаем вторую запись
fio = dataIn.ReadString();
1.2 Все операции с файлом выполняются в оперативной памяти
Примечание. Если необходимо осуществлять выборочное чтение большого количества записей из небольшого двоичного файла (Size < 2 Гб), то предпочтительнее будет прочитать весь файл последовательно в оперативную память, в массивы переменных, входящих в состав записей. Совокупность всех элементов массивов с одинаковым индексом относятся к одному объекту.
Постоянная длина записей позволяет определить их количество:
int n = (int)fs.Length / 35; // количество записей
Прямой файл всегда может быть прочитан последовательно:
int[ ] kursAr = new int[n] ;
string[ ] fioAr = new string[n];
. . .
for (int i = 0; i < n; i++)
{
kursAr[i] = dataIn.ReadInt32(); // (i+1) - я
fioAr[i] = dataIn.ReadString(); // запись
}
2. Все записи двоичного файла имеют разную длину.
Такая ситуация, как правило, возникает из-за наличия строковых полей, имеющих разную длину.
Вместо того чтобы обеспечивать постоянство длины записей, при их выводе в файл запоминаются адреса записей в дополнительном (индексном) файле.
Если все адреса записывать в файл индексов в двоичном формате как переменную одного из целых типов (byte, ushort, uint или ulong), то такой файл будет файлом с прямым доступом. Техника работы с файлом прямого доступа была описана выше.
После определения адреса требуемой записи выполняется позиционирование в файле данных и выполнение операций считывания двоичных данных записи.
Данный подход можно использовать для прямого доступа к сериализованным объектам.
Недостатком такого подхода является то, что при модификации строковых полей записи, как правило, изменяется их длина, поэтому модифицировать можно только нестроковые поля (или обеспечивать постоянство длины строк в сериализованных объектах).
Читать двоичный файл в байтовый массив методом ReadAllBytes() или другим байтовым методом, а затем организовывать выборку данных из этого массива, кажется простой задачей. Но отображение байтов на типы данных – это непростые алгоритмы.
Таким образом, для прямого доступа к записям файл должен быть, как правило, двоичным.
Если прямой доступ не требуется, файл может быть любым – и текстовым, и двоичным.
Если файл должен просматриваться в текстовом редакторе файл должен быть текстовым.
ИНТЕРФЕЙСЫ
Дата добавления: 2019-02-08; просмотров: 1086;