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)))
{

}
Author: Sanvirtus, 2019-09-11

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.

 4
Author: Alexander Petrov, 2019-09-11 16:10:12

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);
    }
}
 2
Author: Rekssel, 2019-09-11 10:30:27

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);
}
 2
Author: Макс Жуков, 2019-09-11 11:55:31