l17.ppt
- Количество слайдов: 32
Організація С#-системи введення-виведення Лекція 16 1
План Поняття потоку Байтовий потік Символьний потік Двійкові потоки Перенаправлення стандартних потоків 2
Поняття потоку С#-программи виконують операції введення-виводу за допомогою потоків, які побудовані на ієрархії класів. Потік (stream) - це абстракція, яка генерує і приймає дані. За допомогою потоку можна читати дані з різних джерел (клавіатура, файл) і записувати в різні джерела (принтер, екран, файл). Не дивлячись на те, що потоки зв'язуються з різними фізичними пристроями, характер поведінки всіх потоків однаковий. Тому класи і методи введеннявиводу можна застосувати до багатьох типів пристроїв. 3
На найнижчому рівні ієрархії потоків введення -виводу знаходяться потоки, що оперують байтами. Це пояснюється тим, що багато пристроїв при виконанні операцій введеннявиводу орієнтовано на байти. Проте людина звикла оперувати символами, тому розроблені символьні потоки, які фактично є оболонками, що виконують перетворення байтових потоків в символьні і навпаки. Реалізовані потоки для роботи з int-, double-, short- значеннями, які також представляють оболонку для байтових потоків, але працюють не з самими значеннями, а з їх внутрішнім представленням у вигляді двійкових код. 4
Центральну частину потокової С#-системи займає клас Stream простору імен System. IO Клас Stream представляє байтовий потік і є базовим для решти всіх потокових класів. З класу Stream виведені такі байтові класи потоків як: File. Stream - байтовий потік, розроблений для файлового введення-виводу Buffered. Stream - вкладає в оболонку байтовий потік і додає буферизацію, яка у багатьох випадках збільшує продуктивність програми; Memory. Stream - байтовий потік, який використовує пам'ять для зберігання даних 5
Байтовий потік Щоб створити байтовий потік, пов'язаний з файлом, створюється об'єкт класу File. Stream. При цьому в класі визначено декілька конструкторів. Найчастіше використовується конструктор, який відкриває потік для читання і/або запису: File. Stream(string filename, File. Mode mode) 6
параметр filename визначає ім'я файлу, з яким буде пов'язаний потік введення-виводу даних; при цьому filename визначає або повний шлях до файлу, або ім'я файлу, який знаходиться в папці bin/debug вашого проекту. параметр mode визначає режим відкриття файлу, який може приймати одне з можливих значень, визначених File. Mode: 7
– File. Mode. Append - призначений для додавання даних в кінець файлу; – File. Mode. Create - для створення нового файлу, (якщо існує файл з таким же ім'ям, то він буде заздалегідь знищений); – File. Mode. Create. New - для створення нового файлу, при цьому файл з таким же ім'ям не має існувати; – File. Mоde. Open - для відкриття існуючого файлу; – File. Mode. Оpen. Or. Create - якщо файл існує, то буде відкритий, інакше буде створений новий – File. Mode. Truncate - відкриває існуючий файл, але усікає його довжину до нуля 8
Якщо файл не відкритий, то генерується одне з виключень: – File. Not. Found. Exception - файл неможливо відкрити унаслідок його відсутності, – IOException - файл неможливо відкрити із-за помилки введення-виводу, – Argument. Null. Exception - ім'ям файлу є nullзначення – Argument. Exception – не коректний параметр mode – Security. Exception - користувач не має прав доступу – Directory. Not. Found. Exception - некоректно заданий каталог. 9
Інша версія конструктора дозволяє обмежити доступ тільки зчитуванням або тільки записом: File. Stream(string filename, File. Mode mode, File. Access how) де: – параметри filename і mode мають ті ж призначення, – параметр how, визначає спосіб доступу до файлу ( може приймати одне із значень із File. Access): File. Access. Read - тільки читання; File. Access. Write - тільки запис; File. Access. Read. Write - і читання, і запис. 10
Після встановлення зв'язку байтового потоку з фізичним файлом внутрішній покажчик потоку встановлюється на початковий байт файлу. Для читання чергового байта з потоку, пов'язаного з фізичним файлом, використовується метод Read. Byte(). Після прочитання чергового байта внутрішній покажчик переміщається на наступний байт файлу. Якщо досягнутий кінець файлу, то метод Read. Byte() повертає значення -1. 11
Для побайтового запису даних до потоку використовується метод Write. Byte(). Після закінчення роботи з файлом його необхідно закрити. Для цього слід викликати метод Close (). При закритті файлу звільняються системні ресурси, раніше виділені для цього файлу, що дає можливість використовувати їх для роботи з іншими файлами. 12
Приклад використання класу File. Stream, для копіювання одного файлу в іншій. Створюєтьсяя текстовий файл txt у папці bin/debug поточного проекту і вноситьсяя до нього довільна інформаціяя: Нарешті закінчився цей карантин! Так мені вже набридло! : ) 13
14
15
Символьний потік Щоб створити символьний потік слід помістити об'єкт класу Stream (наприклад, File. Stream) "всередину" об'єкту класу Stream. Writer або об'єкту класу Stream. Reader. В цьому випадку байтовий потік буде автоматично перетворений в символьний. Клас Stream. Writer призначений для організації вихідного символьного потоку. В ньому визначено декілька конструкторів. Один з них записується таким чином: Stream. Writer(Stream stream); – де параметр stream визначає ім'я вже відкритого байтового потоку. 16
Наприклад, створити екземпляр класу Stream. Writer можна таким чином: Stream. Writer file. Out=new Stream. Writer (new File. Stream("text. txt", File. Mode. Create, File. Access. Write)); Цей конструктор генерує – виключення типу Argument. Exception, якщо потік stream не відкритий для виводу, – і виключення типу Argument. Null. Exception, якщо він (потік) має null-значение. 17
Інший вид конструктора дозволяє відкрити потік відразу через звернення до файлу: Stream. Writer(string name); – де параметр name визначає ім'я файлу, що відкривається. Наприклад, звернутися до даного конструктора можна таким чином: Stream. Writer file. Out=new Stream. Writer("c: tempt. txt"); 18
І ще один варіант конструктора Stream. Writer: Stream. Writer(string name, bool append. Flag); – де параметр name визначає ім'я файлу, що відкривається; параметр append. Flag може приймати значення true якщо потрібно додавати дані в кінець файлу, або false - якщо файл необхідно перезаписати. Наприклад: Stream. Writer file. Out=new Stream. Writer("t. txt", true); Для запису даних в потік file. Out можна звернутися до методу Write. Line. Це можна зробити таким чином: file. Out. Write. Line("test"); В даному випадку в кінець файлу t. txt буде дописано слово test. 19
Клас Stream. Reader призначений для організації вхідного символьного потоку. Один з його конструкторів виглядає таким чином: Stream. Reader(Stream stream); – де параметр stream визначає ім'я вже відкритого байтового потоку. – Цей конструктор генерує виключення типу Argument. Exception, якщо потік stream не відкритий для введення. Наприклад, створити екземпляр класу Stream. Writer можна таким чином: Stream. Reader file. In = new Stream. Reader(new File. Stream("text. txt", File. Mode. Open, File. Access. Read)); 20
Як і у випадку з класом Stream. Writer у класу Stream. Reader є і інший вид конструктора, який дозволяє відкрити файл безпосередньо: Stream. Reader (string name); – де параметр name визначає ім'я файлу, що відкривається. Звернутися до даного конструктора можна таким чином: Stream. Reader file. In=new Stream. Reader ("c: tempt. txt"); 21
У C# символи реалізуються кодуванням Unicode. Для обробки текстових файлів, що містять російський символи, створені, наприклад, в Блокноті, рекомендується викликати наступний вид конструктора Stream. Reader: Stream. Reader file. In=new Stream. Reader ("c: tempt. txt", Encoding. Get. Encoding(1251)); – Параметр Encoding. Get. Encoding(1251) визначає перетворення з коду Windows-1251 (одна з модифікацій коду ASCII, що містить російські символи) в Unicode. – Encoding. Get. Encoding(1251) реалізований в просторі імен System. Text. 22
Тепер для читання даних з потоку file. In можна скористатися методом Read. Line. – При цьому якщо буде досягнутий кінець файлу, то метод Read. Line поверне значення null. приклад, в якому дані з одного файлу копіюються в іншій, але вже з використанням класів Stream. Writer і Stream. Reader. static void Main() { Stream. Reader file. In = new Stream. Reader("text. txt", Encoding. Get. Encoding(1251)); Stream. Writer file. Out=new Stream. Writer("new. Text. txt", false); string line; while ((line=file. In. Read. Line())!=null) //доки потік не порожній { file. Out. Write. Line(line); } file. In. Close(); file. Out. Close(); } 23
Таким чином, даний спосіб копіювання одного файлу в іншій, надає той же результат, що і при використанні байтових потоків. Проте, його робота буде менш ефективною, оскільки витрачатиметься додатковий час на перетворення байтів в символи. Але символьні потоки маютьсвої переваги. – Наприклад, можна використовувати регулярні вирази для пошуку заданих фрагментів тексту у файлі. static void Main() { Stream. Reader file. In = new Stream. Reader("text. txt"); Stream. Writer file. Out=new Stream. Writer("new. Text. txt", false); string text=file. In. Read. To. End(); Regex r= new Regex(@"[-+]? d+"); Match integer = r. Match(text); while (integer. Success) { file. Out. Write. Line(integer); integer = integer. Next. Match(); } file. In. Close(); file. Out. Close(); } 24
Двійкові потоки Двійкові файли зберігають дані в тому ж вигляді, в якому вони представлені в оперативній пам'яті, тобто у внутрішньому представленні. Двійкові файли не застосовуються для перегляду, вони використовуються тільки для програмної обробки. Вихідний потік Binary. Writer підтримує довільний доступ, тобто є можливість виконувати запис в довільну позицію двійкового файлу. 25
Найбільш важливі методи потоку Binary. Writer: Base. Stream - Визначає базовий потік, з яким працює об'єкт Binary. Writer Close - Закриває потік Flush -Очищає буфер Seek –В становлює позицію в поточному потоці Write -Записує значення до поточного потоку 26
Найбільш важливі методи вихідного потоку Binary. Reader: Base. Stream -Визначає базовий потік, з яким працює об'єкт Binary. Reader Close - Закриває потік Peek. Char -Повертає наступний символ потоку без переміщення внутрішнього покажчика в потоці Read - Прочитує черговий потік байтів або символів і зберігає в масиві, передаваному у вхідному параметрі Read. Boolean, Read. Byte, Read. Int 32 тощо Прочитує з потоку дані певного типу 27
Двійковий потік відкривається на основі базового протоку (наприклад, File. Stream), при цьому двійковий потік перетворюватиме байтовий потік в значення int-, double-, short тощо Приклад формування двійкового файлу: static void Main() { //відкриваємо двійковий потік Binary. Writer f. Out=new Binary. Writer(new File. Stream("t. dat", File. Mode. Create)); //записуємо дані в двійковий потік for (int i=0; i<=100; i+=2) { f. Out. Write(i); } f. Out. Close(); //закриваємо двійковий потік } 28
Двійковий файл є видимим програмним шляхом, наприклад таким чином: static void Main() { File. Stream f=new File. Stream("t. dat", File. Mode. Open); Binary. Reader f. In=new Binary. Reader(f); long n=f. Length/4; //определяем кількість чисел в двійковому потоці int а; for (int i=0; i
Двійкові файли є файлами з довільним доступом Нумерація елементів в двійковому файлі ведеться з нуля. Довільний доступ забезпечує метод Seek(long new. Pos, Seek. Origin pos) – де параметр new. Pos визначає нову позицію внутрішнього покажчика файлу в байтах щодо вихідної позиції покажчика, яка визначається параметром pos. – У свою чергу параметр pos має бути заданий одним із значень Seek. Origin: – Seek. Origin. Begin - Пошук від початку файлу – Seek. Origin. Current -Пошук від поточної позиції покажчика – Seek. Origin. End - Пошук від кінця файлу 30
Перенаправлення стандартних потоків Трьома стандартними потоками, доступ до яких здійснюється через властивості Console. Out, Console. In і Console. Error, можуть користуватися всі програми, що працюють в просторі імен System. Властивість Console. Out відноситься до стандартного вихідного потоку. За замовчуванням це консоль. – Наприклад, при виклику методу Console. Write. Line() інформація автоматично передається в потік Console. Out. Властивість Console. In відноситься до стандартного вхідного потоку, джерелом якого за замовчуванням є клавіатура. – Наприклад, при введенні даних з клавіатури інформація автоматично передається потоку Console. In, до якого можна звернутися за допомогою методу Console. Read. Line(). 31
Властивість Console. Error відноситься до помилок в стандартному потоці, джерелом якого також за умовчанням є консоль. Проте ці потоки можуть бути перенаправлені на будь-який сумісний пристрій введеннявиводу, наприклад, на роботу з фізичними файлами. Перенаправити стандартний потік можна за допомогою методів Set. In(), Set. Out() і Set. Error(), які є членами класу Console: – – – static void Setln(Text. Reader input) static void Set. Out(Text. Writer output) static void Set. Error(Text. Writer output) 32


