
- •10.3. Файлы прямого доступа
- •10.3.1. Запись в двоичный файл
- •10.3.2. Чтение двоичного файла
- •Создать поток FileStream;
- •Методом Close(), освободив промежуточный буфер, закрыть файл;
- •Методом Close(), закрыть файловый поток.
- •10.3.3. Запись строки в файл прямого доступа
- •Методом Close(), закрыть файловый поток.
- •10.3.4. Чтение строки из файла прямого доступа
- •Cоздать поток FileStream;
- •Методом Close(), закрыть файловый поток.
- •10.3.5. Запись и чтение массива
- •10.3.6. Запись и чтение типизированного файла
- •10.3.7. Пример бд «Студенты»
- •10.4. Другие классы для работы с файлами
- •10.4.1. Классы File и Directory
- •10.4.2. Класс FileInfо
- •10.4.3. Класс DirectoryInfо
10.3.6. Запись и чтение типизированного файла
Понятия типизированный файл в C# нет, но можно смоделировать это понятие. Рассмотрим процесс записи и чтения полей класса Group, имеющего два поля: ID – целого типа и Name – типа string. Так как мы хотим сохранить механизм прямого доступа, то поле Name должно иметь фиксированную длину. Поэтому введем класс короткой строки ShortString, у объектов которого свойство s всегда имеет длину Len:
Листинг 11.16. Класс короткой строки ShortSting
class ShortSting
{
public int Len;
string fs; // поле fs
public string s { // свойство s
get { return fs; }
set {fs = value; fs = fs.PadRight(Len);}
}
// Конструктор
public ShortSting(int val, string st)
{
Len = val;
s = st;
}
}
Если длина строки короче Len, то метод PadRight() дополняет ее справа пробелами.
Класс Group содержит в себе три поля (name, ID, size), конструктор Group() и три метода Write(), Read() и Output():
Листинг 10.17. Поля и методы класса Group
class Group
{
public ShortSting Name;
public int ID;
int size;
Char[] charData;
byte[] byData;
byte[] byByte;
public Group(int ID, string st)
// конструктор
public void Write(FileStream aFile, int adr)
// метод записи
public void Read(FileStream aFile, int adr)
// метод чтения
public void Output(FileStream aFile)
// метод вывода
}
В конструкторе Group(int ID, string st) заполняется два поля, ID и Name, и вычисляется размер size записываемых полей структуры:
size = sizeof(int) + 2*this.Name.Len;
При вычислении учитывается, что для строки необходимо в два раза байт больше.
Листинг 10.18. Конструктор класса Group
public Group(int ID, string st)
{
this.ID = ID;
this.Name = new ShortSting(20,st);
size = sizeof(int) + 2*this.Name.Len;
byData = new byte[size];
charData = new char[Name.Len];
}
Метод записи готовит для записи массив byData[] и записывает его. Для каждого поля (ID и name) используется вспомогательный массив byByte[], в который методом BitConverter.GetBytes() заносятся данные простых типов и методом GetBytes() для строки. Затем массив byByte[] копируется в основной массив byData[] методом byByte.CopyTo(byData, ofs):
Листинг 10.19. Метод записи
public void Write(FileStream aFile, int adr)
{
int ofs = 0;
charData = Name.s.ToCharArray();
int offset;
if (adr != -1)
offset = adr*size;
else
offset = (int)aFile.Length;
byByte = BitConverter.GetBytes(ID);
byByte.CopyTo(byData, ofs);
ofs += 4;
byByte = new byte[2 * charData.Length];
Encoder e =
Encoding.Unicode.GetEncoder();
e.GetBytes(charData, 0, charData.Length,
byByte, 0, true);
byByte.CopyTo(byData, ofs);
aFile.Seek(offset, SeekOrigin.Begin);
aFile.Write(byData, 0, size);
aFile.Flush();
}
Метод чтения читает данные в массив byData[], методами типа BitConverter.ToInt32() конвертирует часть массива в простые данные, методом GetChars() конвектирует часть массива в массив charData[], который далее используется для заполнения строки name:
Листинг 10.20. Метод чтения
public void Read(FileStream aFile, int adr)
{
aFile.Seek(adr * size, SeekOrigin.Begin);
aFile.Read(byData, 0, size);
int ofs = 0;
ID = BitConverter.ToInt32(byData, ofs);
ofs += 4;
Decoder d = Encoding.Unicode.GetDecoder();
d.GetChars(byData,ofs,2*Name.Len, charData, 0);
string s = "";
for (int i = 0; i < charData.Length; i++)
s += charData[i];
Name.s = s;
}
Метод вывода циклом for выводит все записи из файла на экран:
Листинг 10.21. Метод вывода
public void Output(FileStream aFile)
{
int L = (int)aFile.Length;
for (int i = 0; i < L / size; i++ )
{
this.Read(aFile, i);
Console.WriteLine(Name.s);
}
}
}
В методе Main() создается поток FileStream, делаются три новые записи в конец файла, замещается запись по адресу 2 и выводятся все записи.
Листинг 10.22. Метод Main() программы
class Program
{
static void Main(string[] args)
{
FileStream aFile =
new FileStream("Group.dat",FileMode.Open);
Group group = new Group(1, "1 группа");
group.Write(fw, -1);
group = new Group(2, "2 группа");
group.Write(fw, -1);
group = new Group(3, "3 группа");
group.Write(fw, -1);
group = new Group(4, "4 группа");
group.Write(fw, 2);
group.Output(aFile);
aFile.Close();
Console.ReadKey();
}
}