Приклади застосування класу FileStream без використання додаткових потоків (декораторів, адаптерів)
Перед вивченням даної теми рекомендується ознайомитись з наступними темами:
- Поняття потоку. Архітектура потоків у C#. Потоки з опорними сховищами. Потоки з декораторами. Адаптери потоків
- Ієрархія потоків з опорними сховищами. Клас FileStream
Клас FileStream може бути застосований автономно без використання додаткових потоків адаптерів чи декораторів. Для цього у класі є всі необхідні засоби (методи). Основні методи клас успадковує від базового класу Stream.
Зміст
- 1. Приклад читання/запису числа типу double у файл. Використання FileStream
- 2. Приклад запису/читання масиву чисел типу int[]
- 3. Приклад запису/читання масиву рядків string[]
- 4. Приклад запису/читання масиву екземплярів класу Car (Автомобіль)
- 5. Приклад перезаписування у файлі значень масиву типу double[], які лежать на парних позиціях (0, 2, 4, …). Демонстрація використання методу Seek()
- Зв’язані теми
Пошук на інших ресурсах:
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
⇑
Зв’язані теми
- Ієрархія потоків з опорними сховищами. Клас FileStream
- Клас FileStream. Додаткові опції запису/читання. Зчислення FileOptions. Приклади
⇑