Как правильно считывать бинарный файл

202
16 июля 2021, 13:20

У меня есть коллекция Book, в которой содержаться список книг. Я создаю бинарный файл и записываю в него эти данные. С записью проблем нет, файл создается и содержит все введенные мною данные. Вопрос, а как правильно считывать эти данные из бинарного файла, что бы я потом мог их просмотреть?

// Если файла не существует, то создаем
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)))
{
}
Answer 1

В ответе @Rekssel чтение прекращается с помощью проверки PeekChar(). Один из двух общепринятых способов: читаем, пока не встретим маркер конца.

Другой способ: в начале записываем длину данных. При чтении, соответственно, сперва считываем эту длину.

// Запись
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()
        });
    }
}

Недостаток этого способа в том, что при записи нужно знать длину данных, а это не всегда известно, допустим, у нас источник данных IEnumerable или IQueryable.

Достоинство этого способа в том, что при чтении можно сразу выделить буфер нужной длины. При этом не будет лишних переаллокаций в дальнейшем.

Answer 2

Предположу, что так:

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()
        });
    }
}

Или так:

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);
    }
}
Answer 3

Используйте BinaryFormatter.

Например:

Для записи:

BinaryFormatter formatter = new BinaryFormatter();
using (FileStream fs = new FileStream("books.bin", FileMode.OpenOrCreate))
{
    formatter.Serialize(fs, "ваш_объект");
}

Для считывания:

BinaryFormatter formatter = new BinaryFormatter();
using (FileStream fs = new FileStream("books.bin", FileMode.OpenOrCreate))
{
    "тип_вашего_объекта" obj = ("тип_вашего_объекта")formatter.Deserialize(fs);
}
READ ALSO
Отловить открытие папки в проводнике

Отловить открытие папки в проводнике

Можно как-то отловить открытие папки в проводнике на c# и передать путь в мою программу? Пытаюсь создать свой клон китайского clover'a

283
Как, на C#, посмотреть температуру &ldquo;железа&rdquo;?

Как, на C#, посмотреть температуру “железа”?

Я пробовал через using SystemManagement;

198
Извлечение данных из БД с помощью PDO и ООП PHP

Извлечение данных из БД с помощью PDO и ООП PHP

Набрался сил и начал изучать ООПИдет тяжело

187