Не могу записать корректно данные в бинарный файл
Ошибка "Необработанное исключение: System.IO.EndOfStreamException: невозможно прочитать данные за пределами конца потока." Ошибка возникает в LoadTeachers()" в фрагменте teacher.Name Сохранение
string path = "Teachers.bin";
public void SaveTeachers(List<Teacher> teachers)
{
using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(path)))
{
foreach (Teacher teacher in teachers)
{
bw.Write(teacher.Id);
bw.Write(teacher.Surname);
bw.Write(teacher.Name);
bw.Write(teacher.Middlename);
bw.Write(teacher.YearOfTheBirth);
bw.Write(teacher.Disciplines.Length);
for (int i = 0; i < teacher.Disciplines.Length; i++)
bw.Write(teacher.Disciplines[i]);
bw.Write(teacher.Groups.Length);
for (int i = 0; i < teacher.Groups.Length; i++)
bw.Write(teacher.Groups[i]);
bw.Write(teacher.Login);
bw.Write(teacher.Password);
}
}
}
Загрузка данных с файла
public List<Teacher> LoadTeachers()
{
using (BinaryReader br = new BinaryReader(File.OpenRead("Teachers.bin")))
{
List<Teacher> teachers = new List<Teacher>();
while (br.PeekChar() > -1)
{
Teacher teacher = new Teacher();
teacher.Id = br.ReadInt32();
teacher.Surname = br.ReadString();
teacher.Name = br.ReadString();
teacher.Middlename = br.ReadString();
teacher.YearOfTheBirth = br.ReadInt32();
teacher.Disciplines = new string[br.ReadInt32()];
for (int i = 0; i < teacher.Disciplines.Length; i++)
teacher.Disciplines[i] = br.ReadString();
teacher.Groups = new string[br.ReadInt32()];
for (int i = 0; i < teacher.Groups.Length; i++)
teacher.Groups[i] = br.ReadString();
teacher.Login = br.ReadString();
teacher.Password = br.ReadString();
teachers.Add(teacher);
}
return teachers;
}
}
Вызов
Teacher t = new Teacher();
t.SetAll();
List<Teacher> teachers = new List<Teacher>();
teachers.Add(new Teacher
{
Id = t.Id,
Surname = t.Surname,
Name = t.Name,
Middlename = t.Middlename,
YearOfTheBirth = t.YearOfTheBirth,
Disciplines = t.Disciplines,
Groups = t.Groups,
Login = t.Login,
Password = t.Password
});
t.SaveTeachers(teachers);
List<Teacher> loadedTeachers = t.LoadTeachers();
foreach (Teacher teacher in loadedTeachers)
Console.WriteLine(teacher);
Ответы (2 шт):
Метод File.OpenWrite открывает файл и помещает указатель в начало потока. Таким образом при записи вы затираете ранее записанные данные.
При этом, если раньше данных было больше, чем записано теперь, то кусок старых данных остаётся в файле. И метод PeekChar, дойдя до этих данных, обнаруживает их. В итоге методы ReadInt32, ReadString пытаются их читать. Отсюда и ошибки.
Вы хотите дописывать в файл, значит нужно установить указатель в конец потока.
using (var fileStream = File.OpenWrite(path))
{
fileStream.Seek(0, SeekOrigin.End);
using (BinaryWriter bw = new BinaryWriter(fileStream))
{
...
}
}
FileStream нужно обязательно диспозить (освобождать), поэтому нужно заключить его в using. Сделайте это и в методе чтения:
using (var fileStream = File.OpenRead(path))
using (BinaryReader br = new BinaryReader(fileStream))
{
....
}
Можно использовать метод File.Open, в котором можно указать параметр FileMode.Append - это автоматически установит указатель в конец потока. И делать Seek вручную уже не нужно.
using (var fileStream = File.Open(path, FileMode.Append))
using (BinaryWriter bw = new BinaryWriter(fileStream))
{
...
}
При этом желательно задать и другие параметры: FileAccess.Write, FileShare.None - тогда поток будет в точности соответствовать тому, который возвращается методом File.OpenWrite.
Решение нужно было использовать FileStream
using (BinaryWriter bw = new BinaryWriter(new FileStream(path, FileMode.Append, FileAccess.Write)))
using (BinaryReader br = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read)))