How to read a binary file correctly
I have a Book collection that contains a list of books. I create a binary file and write this data to it. There are no problems with recording, the file is created and contains all the data I entered. The question is, how do I correctly read this data from a binary file, so that I can then view it?
// Если файла не существует, то создаем
if (!File.Exists(_path + "\\Books.bin"))
{
_books.Add(new Books
{
BookName = "Книга 1",
Author = "Автор 1",
PageCount = 200,
Year = 2000
});
_books.Add(new Books
{
BookName = "Книга 2",
Author = "Автор 2",
PageCount = 400,
Year = 2010
});
_books.Add(new Books
{
BookName = "Книга 3",
Author = "Автор 3",
PageCount = 820,
Year = 2005
});
using (var fileStream = new FileStream(_path + "\\Books.bin", FileMode.Create))
{
using (BinaryWriter writer = new BinaryWriter(fileStream))
{
foreach (var book in _books)
{
writer.Write(book.BookName);
writer.Write(book.Author);
writer.Write(book.PageCount);
writer.Write(book.Year);
}
writer.Close();
}
}
}
// Читаем файл
using (BinaryReader reader = new BinaryReader(File.Open(_path + "\\Books.bin", FileMode.Open)))
{
}
3 answers
In the response @Rekssel, the reading is terminated by checking PeekChar()
. One of the two common ways: read until we meet the end marker.
Another way: at the beginning, we write down the length of the data. When reading, respectively, we first read this length.
// Запись
using (var fileStream = new FileStream(path, FileMode.Create))
using (var writer = new BinaryWriter(fileStream))
{
writer.Write(_books.Count);
foreach (var book in _books)
{
writer.Write(book.BookName);
writer.Write(book.Author);
writer.Write(book.PageCount);
writer.Write(book.Year);
}
}
// Чтение
using (var fileStream = new FileStream(path, FileMode.Open))
using (var reader = new BinaryReader(fileStream))
{
int count = reader.ReadInt32();
_books = new List<Books>(count);
for (int i = 0; i < count; i++)
{
_books.Add(new Books
{
BookName = reader.ReadString(),
Author = reader.ReadString(),
PageCount = reader.ReadInt32(),
Year = reader.ReadInt32()
});
}
}
The disadvantage of this method is that when writing, you need to know the length of the data, and this is not always known, for example, we have a data source IEnumerable
or IQueryable
.
The advantage of this method is that when reading you can immediately select a buffer of the desired length. At the same time, there will be no unnecessary reallocations in the future.
I will assume that so:
using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open)))
{
while (reader.PeekChar() > -1)
{
_books.Add(new Books
{
BookName = reader.ReadString(),
Author = reader.ReadString(),
PageCount = reader.ReadInt32(),
Year = reader.ReadInt32()
});
}
}
Or so:
using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open)))
{
while (reader.PeekChar() > -1)
{
Books book = new Books();
book.BookName = reader.ReadString();
book.Author = reader.ReadString();
book.PageCount = reader.ReadInt32();
book.Year = reader.ReadInt32();
_books.Add(book);
}
}
Use BinaryFormatter.
For example:
For the record:
BinaryFormatter formatter = new BinaryFormatter();
using (FileStream fs = new FileStream("books.bin", FileMode.OpenOrCreate))
{
formatter.Serialize(fs, "ваш_объект");
}
For reading:
BinaryFormatter formatter = new BinaryFormatter();
using (FileStream fs = new FileStream("books.bin", FileMode.OpenOrCreate))
{
"тип_вашего_объекта" obj = ("тип_вашего_объекта")formatter.Deserialize(fs);
}