C#. Примеры применения класса FileStream без использования дополнительных потоков




Примеры применения класса FileStream без использования дополнительных потоков (декораторов, адаптеров)

Перед изучением данной темы рекомендуется ознакомиться со следующими темами:

Класс FileStream может быть применен автономно без использования дополнительных потоков адаптеров или декораторов. Для этого в классе есть все необходимые средства (методы). Основные методы класс наследует от базового класса Stream.


Содержание


Поиск на других ресурсах:

1. Пример чтения/записи числа типа double в файл. Использование FileStream

В примере продемонстрировано использование средств класса FileStream и базового класса Stream для записи/чтения числа типа double в файл.

using System;
using System.IO;
using System.Text;

namespace ConsoleApp10
{
  class Program
  {
    static void Main(string[] args)
    {
      // Пример записи/чтения числа типа double в файл "file1.bin".
      // Методы Read(), Write() класса FileStream

      // 1. Запись в файл числа
      // 1.1. Создать файл с именем "file1.bin" для записи
      using (FileStream fs = new FileStream("file1.bin",
FileMode.Create, FileAccess.Write))
      {
        // 1.2. Указанное число
        double x = 2.55;

        // 1.3. Конвертувать x в массив byte[]
        byte[] bt = Encoding.Default.GetBytes(x.ToString());

        // 1.4. Запись числа x в файл
        fs.Write(bt, 0, bt.Length);
      }

      // 2. Считать число из файла - метод Read()
      using (FileStream fs2 = new FileStream("file1.bin", FileMode.Open, FileAccess.Read))
      {
        // 2.1. Объявить массив-буфер, в который будут считаны данные
        byte[] bt2 = new byte[10]; // 10 байт - достаточно для числа типа double

        // 2.2. Считать число из файла в массив bt2
        fs2.Read(bt2, 0, bt2.Length);

        // 2.3. Конвертировать bt2 в тип string - в строку st
        string st = Encoding.Default.GetString(bt2);

        // 2.4. Конвертировать st в x2 типа double
        double x2 = Convert.ToDouble(st);

        // 2.5. Вывести x2 для контроля
        Console.WriteLine("x2 = {0}", x2); // x2 = 2.55
      }
    }
  }
}

 

2. Пример записи/чтения массива чисел типа int[]

В примере продемонстрирована запись массива типа int[] в файл и его чтение. В программном коде используются методы Read(), Write() базового класса Stream. Поскольку методы Read(), Write() требуют представления данных в виде массива байт типа byte[], то для выполнения операций конвертирования используются возможности класса BitConverter.

using System;
using System.IO;

namespace ConsoleApp10
{
  class Program
  {
    static void Main(string[] args)
    {
      // Запись массива чисел типа int[] в файл "array.bin"
      using (FileStream fs = new FileStream("array.bin", FileMode.Create, FileAccess.Write))
      {
        // Массив, который нужно записать в файл
        int[] AI = { 1, 3, 8, 4, 2, 6 };

        // Дополнительный буфер типа byte[]
        byte[] AB;

        // Сначала нужно записать количество чисел в массиве,
        // для этого можно воспользоваться классом BitConverter.
        // Представить число AI.Length как последовательность байт
        AB = BitConverter.GetBytes(AI.Length);
        fs.Write(AB, 0, AB.Length);

        // Цикл поэлементной записи чисел массива
        for (int i = 0; i < AI.Length; i++)
        {
          AB = BitConverter.GetBytes(AI[i]);
          fs.Write(AB, 0, AB.Length);
        }
      }

      // Чтение массива чисел типа int[] из файла array.bin
      using (FileStream fs = new FileStream("array.bin", FileMode.Open, FileAccess.Read))
      {
        int[] AI2; // массив - результат
        byte[] AB2; // дополнительный буфер
        int count; // количество элементов в массиве AI2

        // Считать количество чисел
        AB2 = new byte[sizeof(int)]; // выделить память для числа типа int
        fs.Read(AB2, 0, AB2.Length);
        count = BitConverter.ToInt32(AB2, 0); // считать количество элементов в массиве AI2

        // Выделить память для массива AI2
        AI2 = new int[count];

        // Цикл поэлементного считывания чисел в массив AI2
        for (int i = 0; i < AI2.Length; i++)
        {
          // Использовать предварительно выделенную память для числа типа int
          fs.Read(AB2, 0, AB2.Length);
          AI2[i] = BitConverter.ToInt32(AB2, 0);
        }

        // Вывести массив AI2 для проверки
        for (int i = 0; i < AI2.Length; i++)
        {
          Console.Write("{0} ", AI2[i]);
        }
      }
    }
  }
}

Результат выполнения программы

1 3 8 4 2 6

 

3. Пример записи/чтения массива строк string[]

В примере продемонстрирована запись массива строк в файл и его чтение.

using System;
using System.IO;
using System.Text;

namespace ConsoleApp10
{
  class Program
  {
    static void Main(string[] args)
    {
      // Запись массива строк типа string[] в файл "strings.bin"
      using (FileStream fw = new FileStream("strings.bin", FileMode.Create, FileAccess.Write))
      {
        // Массив, который нужно записать в файл
        string[] AS = { "Delphi", "Java", "C#", "Python", "C++" };

        // Вспомогательный буфер типа byte[]
        byte[] AB;

        // Сначала нужно записать количество строк,
        // для этого можно воспользоваться классом BitConverter.
        AB = BitConverter.GetBytes(AS.Length);
        fw.Write(AB, 0, AB.Length);

        // Цикл записи строк
        for (int i = 0; i < AS.Length; i++)
        {
          // Сначала записать длину строки
          AB = BitConverter.GetBytes(AS[i].Length);
          fw.Write(AB, 0, AB.Length);

          // Чтобы записать строку, нужно использовать класс Encoding 
          // из пространства имен System.Text, потому что строку можно записывать
          // в разных системах кодировки.
          AB = Encoding.UTF8.GetBytes(AS[i]); // система кодировки UTF-8
          fw.Write(AB, 0, AB.Length);
        }
      }

      // Чтение строк типа string[] из файла "strings.bin"
      using (FileStream fr = new FileStream("strings.bin", FileMode.Open, FileAccess.Read))
      {
        string[] AS2; // массив - результат
        byte[] AB2; // вспомогательный буфер байт
        int count; // количество элементов в массиве AS2
        int len; // дополнительная переменная - длина строки

        // Прочитать количество строк - count
        AB2 = new byte[sizeof(int)]; // выделить память для числа типа int
        fr.Read(AB2, 0, AB2.Length);
        count = BitConverter.ToInt32(AB2, 0);

        // Выделить память для массива AS2
        AS2 = new string[count];

        // Цикл поэлементного чтения чисел в массив AS2
        for (int i = 0; i < AS2.Length; i++)
        {
          // Прочитать длину строки AS2[i] в байтах
          AB2 = new byte[sizeof(int)];
          fr.Read(AB2, 0, AB2.Length);
          len = BitConverter.ToInt32(AB2, 0); // len - длина строки AS2[i]

          // Прочитать строку AS2[i]
          AB2 = new byte[len]; // выделить память для len байт
          fr.Read(AB2, 0, AB2.Length); // прочитать в буфер AB2

          // конвертировать string <= byte[]
          AS2[i] = "";
          for (int j = 0; j < AB2.Length; j++)
            AS2[i] = AS2[i] + (char)AB2[j];
        }

        // Вывести массив AS2 для проверки
        for (int i = 0; i < AS2.Length; i++)
          Console.WriteLine(AS2[i]);
      }
    }
  }
}

Результат выполнения программы

Delphi
Java
C#
Python
C++

 

4. Пример записи/чтения массива экземпляров класса Car (автомобиль)

Условие задачи. Задан класс Car, который содержит следующие члены данных:

  • model – марка автомобиля;
  • volume – объем двигателя;
  • year – год выпуска.

Также класс Car содержит свойства доступа к членам данных и специальные функции класса:

  • конструктор;
  • свойства Model, Volume, Year.

Нужно реализовать запись массива экземпляров типа Car[] в файл и его считывание с последующим выводом результата.

Решение. Текст программы, решающий данную задачу следующий.

using System;
using System.IO;
using System.Text;

namespace ConsoleApp10
{
  // Класс, описывающий автомобиль
  class Car
  {
    // Внутренние члены данных класса
    private string model;
    private float volume;
    private int year;

    // Конструктор
    public Car(string model, float volume, int year)
    {
      this.model = model;
      this.volume = volume;
      this.year = year;
    }

    // Методы доступа
    public string Model
    {
      get { return model; }
      set { model = value; }
    }

    public float Volume
    {
      get { return volume; }
      set { volume = value; }
    }

    public int Year
    {
      get { return year; }
      set { year = value; }
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // Запись массива классов Car[] в файл "cars.bin"
      using (FileStream fw = new FileStream("cars.bin", FileMode.Create, FileAccess.Write))
      {
        // Массив, который нужно записать в файл
        Car[] cars = {
            new Car("Volvo", 2.8f, 2018),
            new Car("Renault", 0.9f, 2017),
            new Car("Audi", 12.2f, 2030)
        };

        // Вспомогательный буфер типа byte[]
        byte[] AB;

        // Сначала нужно записать количество элементов массива cars
        AB = BitConverter.GetBytes(cars.Length);
        fw.Write(AB, 0, AB.Length);

        // Цикл записи элементов массива cars
        for (int i = 0; i < cars.Length; i++)
        {
          // 1. Запись строки model
          // Сначала записать длину строки cars[i].Model
          AB = BitConverter.GetBytes(cars[i].Model.Length);
          fw.Write(AB, 0, AB.Length);

          // Чтобы записать строку, нужно использовать класс Encoding
          // из пространства имен System.Text
          AB = Encoding.Default.GetBytes(cars[i].Model);
          fw.Write(AB, 0, AB.Length);

          // 2. Запись объема двигателя
          AB = BitConverter.GetBytes(cars[i].Volume);
          fw.Write(AB, 0, AB.Length);

          // 3. Запись года выпуска
          AB = BitConverter.GetBytes(cars[i].Year);
          fw.Write(AB, 0, AB.Length);
        }
      }

      // Чтение массива типа Car[] из файла "cars.bin"
      using (FileStream fr = new FileStream("cars.bin", FileMode.Open, FileAccess.Read))
      {
        Car[] cars2; // массив - результат
        byte[] AB2;  // вспомогательный байтовый буфер
        int count;   // количество элементов в массиве cars2
        int len;     // дополнительная переменная - длина строки

        // Считать количество элементов в массиве cars2 - count
        AB2 = new byte[sizeof(int)]; // выделить память для числа типа int
        fr.Read(AB2, 0, AB2.Length);
        count = BitConverter.ToInt32(AB2, 0);

        // Выделить память для массива cars2
        cars2 = new Car[count];

        // Объявить дополнительные переменные, которые будут дублировать внутренние данные класса
        string model; // марка автомобиля
        float volume; // объем двигателя
        int year;     // год выпуска

        // Цикл поэлементного считывания экземпляров типа Car в массив cars2
        for (int i = 0; i < cars2.Length; i++)
        {
          // 1. Считать строку Model
          // Считать длину строки cars2[i].Model в байтах
          AB2 = new byte[sizeof(int)];
          fr.Read(AB2, 0, AB2.Length);
          len = BitConverter.ToInt32(AB2, 0); // len - длина строки cars2[i].Model

          // Считать строку
          AB2 = new byte[len]; // выделить память для len байт
          fr.Read(AB2, 0, AB2.Length); // считать в буфер AB2

          // конвертирование string <= byte[]
          model = "";
          for (int j = 0; j < AB2.Length; j++)
            model += (char)AB2[j];

          // 2. Считать объем двигателя volume
          AB2 = new byte[sizeof(float)];
          fr.Read(AB2, 0, AB2.Length);
          volume = BitConverter.ToSingle(AB2);

          // 3. Считать год выпуска year
          AB2 = new byte[sizeof(int)];
          fr.Read(AB2, 0, AB2.Length);
          year = BitConverter.ToInt32(AB2);

          // 4. Создать экземпляр класса cars2[i]
          cars2[i] = new Car(model, volume, year);
        }

        // Вывести массив cars2 для проверки
        for (int i = 0; i < cars2.Length; i++)
        {
          Console.WriteLine("Model = {0}, Volume = {1}, Year = {2}",
          cars2[i].Model, cars2[i].Volume, cars2[i].Year);
        }
      }
    }
  }
}

Результат выполнения программы

Model = Volvo, Volume = 2.8, Year = 2018
Model = Renault, Volume = 0.9, Year = 2017
Model = Audi, Volume = 12.2, Year = 2030

 

5. Пример перезаписи в файле значений массива типа double[], которые лежат на четных позициях (0, 2, 4, …). Демонстрация использования метода Seek()

В примере продемонстрирована перезапись данных непосредственно в файле. В качестве примера, записывается и считывается массив чисел типа double[]. Замещаются числа, которые лежат на четных позициях. Одновременное чтение данных из файла и их запись в файл возможно в режиме доступа FileAccess.ReadWrite.

using System;
using System.IO;

namespace ConsoleApp10
{
  class Program
  {
    static void Main(string[] args)
    {
      // Запись массива типа double[] в файл "doubles.bin"
      using (FileStream fw = new FileStream("doubles.bin", FileMode.Create, FileAccess.Write))
      {
        // Массив, который нужно записать в файл
        double[] AD = { 2.8, 3.3, 1.7, 3.8, 4.3, 6.1 };

        // Вспомогательный буфер типа byte[]
        byte[] AB;

        // Сначала нужно записать количество элементов массива AD
        AB = BitConverter.GetBytes(AD.Length);
        fw.Write(AB, 0, AB.Length);

        // Цикл записи элементов массива AD
        for (int i = 0; i < AD.Length; i++)
        {
          AB = BitConverter.GetBytes(AD[i]); // byte[] <= double
          fw.Write(AB, 0, AB.Length);        // fw <= byte[]
        }
      }

      // Перезаписать числа в файле, которые лежат на парных позициях
      using (FileStream fs = new FileStream("doubles.bin", FileMode.Open, FileAccess.ReadWrite))
      {
        // Считать количество элементов в массиве
        byte[] AB = new byte[sizeof(int)];
        fs.Read(AB, 0, AB.Length);
        int count = BitConverter.ToInt32(AB);

        // Цикл обхода элементов в файле,
        // елементы на нечетных позициях пропускаются

        for (int i = 1; i <= count; i++)
          // если нечетная позиция, то перемотать указатель записи/чтения в файле
          if (i % 2 == 1)
            fs.Seek(sizeof(double), SeekOrigin.Current); // пропустить число типа double
          else
          {
            // в парную позицию в файле записать случайное число от 0 до 10
            double num = (double)(new Random()).Next(0, 10);
            AB = BitConverter.GetBytes(num);
            fs.Write(AB, 0, AB.Length);
          }
      }

      // Чтение массива типа double[] из файла "doubles.bin"
      using (FileStream fr = new FileStream("doubles.bin", FileMode.Open, FileAccess.Read))
      {
        double[] AD2; // массив - результат
        byte[] AB2;   // вспомогательный буфер
        int count;    // количество элементов в массиве AD2

        // Считать количество элементов в массиве AD2 - count
        AB2 = new byte[sizeof(int)]; // выделить память для числа типа int
        fr.Read(AB2, 0, AB2.Length);
        count = BitConverter.ToInt32(AB2, 0);

        // Выделить память для массива AD2
        AD2 = new double[count];

        // Цикл поэлементного чтения чисел double из файла
        // и запись их в массив AD2
        for (int i = 0; i < AD2.Length; i++)
        {
          AB2 = new byte[sizeof(double)];
          fr.Read(AB2, 0, AB2.Length);
          AD2[i] = BitConverter.ToDouble(AB2);
        }

        // Вывести массив AD2
        for (int i = 0; i < AD2.Length; i++)
          Console.Write("{0:f1} ", AD2[i]);
      }
    }
  }
}

Результат выполнения программы

2.8 5.0 1.7 5.0 4.3 8.0

 


Связанные темы