Operacje na plikach

Plik

  • plik zawiera ciąg bajtów
  • strumień danych - dane w plikach odczytujemy lub zapisujemy sekwencyjnie
  • nazwa i ścieżka do pliku
    • bezwzględna
      C:\Users\Marek\Pulpit\plik.txt
    • względna
      plik.txt
      ..\Pulpit\plik.jpg
  • przestrzeń nazw System.IO
    zawiera klasy i narzędzia do odczytu i zapisu plików (strumieni danych)

Operacje na strumieniach

  • otwieranie strumieni: tworzenie plików lub dostęp do istniejących plików
    • podstawowa klasa FileStream niskopoziomowy dostęp do plików
      Inne: MemoryStream, NetworkStream, …
    • otwieranie w trybie do odczytu, zapisu, dodawania
    • strumienie tekstowe i binarne
  • odczyt - pobieranie sekwencji danych ze strumienia
  • zapis - wysyłanie sekwencji danych do strumienia
  • przeszukiwanie - szukanie i ustawienie aktualnej pozycji w strumieniu
  • zamykanie strumienia - metoda Close(), brak zamknięcia strumienia może spowodować utratę danych lub uszkodzenie pliku

Pliki tekstowe i binarne

  • StreamWriter - zapis plików tekstowych
  • StreamReader - odczyt plików tekstowych
  • BinaryWriter - zapis danych binarnych
  • BinaryReader - odczyt danych binarnych

StreamReader

Otworzenie strumienia do odczytu pliku tekstowego

var reader = new StreamReader("C:\\Users\\Marek\\Pulpit\\plik.txt")
Metoda Opis
ReadLine odczyt linii tekstu
Read odczyt pojedynczego znaku
ReadToEnd odczyt całego pliku
Peek podejrzyj kolejny znak
Close zamknięcie strumienia
Własność Opis
EndOfStream True, gdy koniec strumienia

Otwieranie pliku

// Utworzenie obiektu czytającego z pliku 
StreamReader reader = new StreamReader("tekst.txt");

// Tu operacje czytania sekwencji danych

// Zamknięcie strumienia 
reader.Close();

Ścieżki w systemie Windows

Ścieżka bezwzględna rozpoczyna się od numeru nośnika

string nazwa_pliku = "C:\\Temp\\work\\test.txt";

To samo z użyciem @, który wyłącza znaki specjalne w łańcuchu

string nazwa_pliku = @"C:\Temp\work\test.txt";

Uwaga na przenośność: unikaj ścieżek bezwzględnych

Ścieżka względna określana względem katalogu roboczego (bieżącego)

string nazwa_pliku = "test.txt";
string nazwa_pliku2 = "Dokumenty\\tekst.txt";
string nazwa_pliku3 = @"..\..\Dokumenty\tekst.txt";

Katalog roboczy

System.IO.Directory.GetCurrentDirectory();

Odczyt pliku linia po linii

StreamReader reader = new StreamReader(plik);
    
int i=1;
while(!reader.EndOfStream)
{
    string linia = reader.ReadLine() ?? "";
    Console.WriteLine("{0} : {1}", i, linia);
}
reader.Close();

Instrukcja using

using automatycznie zamyka strumień i zwalnia wszystkie zasoby po zakończeniu obsługi strumienia

using( obiekt_strumienia ) 
{ 
    // operacje na strumieniu   
} 

Przykład

string plik = "plik.txt";

using(StreamReader reader = new StreamReader(plik))
{
    int i=1;
    while(!reader.EndOfStream)
    {
        string linia = reader.ReadLine() ?? "";
        Console.WriteLine("{0} : {1}", i, linia);
    }
}

Obsługa błędów

  • każda operacja na plikach może zakończyć sie niepowodzeniem, np.: zła ścieżka, brak uprawnień, brak miejsca na nośniku, itp.
  • using - zawsze używaj aby automatycznie zwalniać zasoby
  • wyjątki: IOException, FileNotFoundException, DirectoryNotFoundException, …
  • File.Exists() i inne metody sprawdzające system plików

Przykład

string tekst = "";

try
{
    var reader = new StreamReader("plik.txt");
    using( reader )
    {
        tekst = sr.ReadToEnd();
    }
}
catch(FileNotFoundException)
{
    Console.WriteLine("Nie znaleziono pliku: {0}", plik);
}
catch(IOException)
{
    Console.WriteLine("Wystąpił błąd wejścia/wyjścia");
}

Ćwiczenie

Napisz program, który odczyta sekwencje liczb rzeczywistych zapisanych w pliku tekstowym i wyznaczy sumę, wartość średnią wartość minimalną i wartość maksymalną.
Nazwę pliku do odczytu podaje użytkownik na początku działania programu. Zabezpiecz program przed błędami takimi jak:

  • niepoprawna nazwa pliku lub brak dostępu do pliku
  • niepoprawny format danych zawartych w pliku. Zakładamy, że plik zawiera w każdej linii jedną liczbę rzeczywistą.

Przykładowy plik wejściowy: liczby-pl.txt lub liczby-en.txt

StreamWriter

Tworzenie nowego pliku

var writer = new StreamWriter(@"C:\Users\Marek\Pulpit\plik.txt" )

Uwaga: jeśli plik istnieje to aktualna zawartość zostanie skasowana.

Dopisywanie do istniejącego pliku

var writer = new StreamWriter(@"C:\Users\Marek\Pulpit\plik.txt", true )
Metoda Opis
Write zapis łańcucha znakowego
WriteLine zapis łańcucha ze znakiem nowej linii
Close zamknięcie strumienia

Przykład

using(var sw = new StreamWriter("plik.txt"))
{
    sw.WriteLine("Witaj świecie");
    sw.WriteLine("Liczba PI wynosi {0,10:F5}", Math.PI);
}

Ćwiczenie

Napisz program, który zapisze do pliku tekstowego sekwencję K liczb wylosowanych spośród liczb całkowitych od 1 do N. Wartości K, N oraz nazwę pliku podaje użytkownik.

Przydatna klasa System.Random() - generator liczb losowych.

Metoda Opis
Next() zwraca losową wartość całkowitą dodatnią
Next(10) zwraca losowa wartość całkowiąa mniejszą niż 10
NextDouble() zwraca losową wartość rzeczywistą z zakresu [0, 1)

Przydatne narzędzia

  • File - udostępnia statyczne metody do tworzenia, kopiowania, usuwania plików oraz funkcje pomocnicze tworzenia obiektów FileStream
  • FileInfo - klasa udostępniająca podobne funkcje co File.
  • Directory - zestaw metod do tworzenia, przenoszenia i listowania folderów
  • DirectoryInfo - klasa udostępniająca podobne metody co Directory
  • Path - zestaw metod do operacji na ścieżkach

Klasa File

Metoda Opis
Copy, Move, Delete kopiowanie, przenoszenie, usuwanie plików
CreateText, OpenText Tworzenie i otwieranie plików tekstowych
ReadAllLines, ReadAllBytes, ReadAllText Odczyt zawartości pliku
WriteAllLines, WriteAllBytes, WriteAllText Zapis zawartości pliku
Exists czy wskazany plik istnieje

Klasa Directory

Metoda Opis
CreateDirectory, Move, Delete tworzenie, przenoszenie, usuwanie folderów
GetFiles, GetDirectories zwraca tablicę nazw plików (podkatalogów) wskazanego folderu
Exists czy wskazany folder istnieje

BinaryReader

Klasa BinaryReader odczyt wartości w postaci binarnej

Metoda Opis
Read odczyt sekwencji N bajtów do tablicy
ReadInt, ReadChar, ReadDouble Odczyt wartości określonego typu

Klasa BinaryWriter zapis wartości w postaci binarnej

Metoda Opis
Write zapis pojedynczej wartości lub sekwencji N bajtów z tablicy

Zadanie 6: Odwracanie linii

Napisz program, który odwraca kolejność znaków w poszczególnych liniach pewnego pliku tekstowym. Nazwę pliku podaje użytkownik na początku działania programu. Jeżeli wskazany plik istnieje to po wykonaniu programu zawartość tego pliku zostaje zamieniona w taki sposób, że każda kolejna linia tekstu posiada odwróconą kolejność znaków.

Przykładowo, jeśli plik zawiera tekst

Ala ma kota 
a Ewa ma psa.

to jego zawartośc zamienia się w

atok am alA
.asp am awE a

Jeżeli podany przez użytkownika plik nie istnieje lub operacje na plikach nie powiodły się to program wypisuje stosowany komunikat błędu i kończy swoje działanie.

Adres do zadania w Moodle: https://moodle.umk.pl/mod/assign/view.php?id=126250