Tiedostoon kirjoittaminen

Windows-ympäristössä voidaan tiedostoon kirjoittaa useilla eri tavoilla ja sisällöllä riippuen siitä millaisessa kontekstissa ohjelmaa suoritetaan. Tässä vaiheessa opintojaksoa harjoittellaan tiedostoon kirjoittamista konsoliohjelmasta käsin. Opintojakson edetessä tutustutaan tiedostojen käsittelyyn myös graafisen käyttöliittymän sisältävien ohjelmien kautta.

Tarkoituksena on myös jatkaa poikkeuksien käsittelyjen toteuttamista ohjelmaan. Tiedostojen käsittelyn yhteydessä voi esiintyä useita erilaisia poikkeuksellisia tilanteita.

Tekstin kirjoittaminen tiedostoon

Alla olevissa esimerkeissä kirjoitetaan tiedostoon tekstimuotoista tietoa ja demonstroidaan samalla poikkeuksien käsittelyä.

Esimerkki: Tiedostoon kirjoittaminen 1

Kirjoitetaan tiedostoon, joka sijaitsee luodun projektin toteuttavan exe-tiedoston kanssa samassa kansiossa.


    static void Main(string[] args)
    {
        System.IO.StreamWriter outputFile = new System.IO.StreamWriter("test.txt");
        outputFile.WriteLine("Here is a sample text to file.");
        outputFile.Close();    
    }
    

Tiedostoon kirjoittaminen ja sulkeminen onnistuu, jos mitään poikkeusta ei tapahdu. Jos kuitenkin poikkeuksia tapahtuu riveillä 4 tai 5, silloin tiedosto jää sulkematta.

Esimerkki: Tiedostoon kirjoittaminen 2

Kokeillaan kirjoittaa tiedostoon, joka on C:-aseman juuressa. Esimerkkitapauksessa C-asema on kirjoitussuojattu, jolloin ohjelmaa suoritettaessa aiheutuu UnauthorizedAccessException-tyyppinen poikkeus.


    static void Main(string[] args)
    {
        System.IO.StreamWriter outputFile = new System.IO.StreamWriter(@"c:\test.txt");
        outputFile.WriteLine("Here is a sample text to file.");
        outputFile.Close();
    }
    

Ohjelman suoritus pysähtyy riville 4 ja aiheuttaa sovelluksessa UnauthorizedAccessException-tyyppisen poikkeuksen. (kuvakaappaus)

Yllä olevissa ohjelmointikoodeissa mahdolliset poikkeukset voivat aiheutua seuraavista ohjelmointikäskyistä, joten näiden metodien dokumentaatiota on tutkittava:
* StreamWriter()-konstruktori kutsusta : Exceptions
* WriteLine()-metodin käytöstä: Exceptions
* Close()-metodin käytöstä: Exceptions

Esimerkki: Tiedostoon kirjoittaminen 3

Alla olevassa esimerkissä on käsitelty muutamia poikkeuksia. Huomaan kuinka catch-lauseita voi olla useita, jos ohjelmassa halutaan eritellä mikä tietty poikkeuksellinen tilanne on tapahtunut.


    static void Main(string[] args)
    {
        System.IO.StreamWriter outputFile = null;
        try
        {
            outputFile = new System.IO.StreamWriter(@"c:\test.file");
            outputFile.WriteLine("Here is a sample text to file.");
        }
        catch (UnauthorizedAccessException)
        {
            Console.WriteLine("Can't open file for writing (UnauthorizedAccessException)");
        }
        catch (ArgumentNullException)
        {
            Console.WriteLine("Opened stream is null (ArgumentNullException)");
        }
        catch (ArgumentException)
        {
            Console.WriteLine("Opened stream is not writable (ArgumentException)");
        }
        catch (IOException)
        {
            Console.WriteLine("An IO error happend (IOException)");
        }
        catch (Exception)
        {
            Console.WriteLine("Some other exception happend (Exception)");
        }
        finally
        {
            // check for null because OpenWrite might have failed
            if (outputFile != null)
            {
                outputFile.Close();
            }
        }
    }
    

Esimerkki: Tiedostoon kirjoittaminen 4

Yleisesti ei kuitenkaan ole tarve eritellä kaikkia poikkeuksia mitä voi tapahtua. Tällöin voidaan käyttää poikkeuksien Exception-yliluokkaa hoitamaan tilanne. Huomaa kuinka poikkeuksen käsittelijässä on otettu myös olio käyttöön, jota kautta poikkeukseen liittyvä viesti saadaan esitettyä käyttäjälle. Alla olevassa esimerkissä ohjelmaa on ajettu tilanteessa, jossa c-levyasema on ollut kirjoitussuojattu.


    static void Main(string[] args)
    {
        System.IO.StreamWriter outputFile = null;
        try
        {
            outputFile = new System.IO.StreamWriter(@"c:\test.file");
            outputFile.WriteLine("Here is a sample text to file.");
        }
        catch (Exception ex)
        {
            //Console.WriteLine("Some exception happened!");
            Console.WriteLine(ex.Message); // Access to the path 'c:\test.file' is denied.
        }
        finally
        {
            // check for null because OpenWrite might have failed
            if (outputFile != null)
            {
                outputFile.Close();
            }
        }
    }
    

Esimerkki: Tiedostoon kirjoittaminen 5

Alla olevassa esimerkissä tiedosto kirjoitetaan käyttöjärjestelmässä olevaan "My Documents" -kansioon. Ohjelmoinnissa on käytetty myös using-lausetta, joka rajaa StreamWriter-luokan olion näkymään ja toimimaan ainoastaan using-lauseen määrittämien {}-sulkujen sisälle. Tämän jälkeen sille kutsutaan automaattisesti Dispose()-metodia, joka vaputtaa ko. olion käyttämät resurssit välittömästi. Objekti on myös "read-only" tilassa ja siihen siis voida enää tehdä määrittelyjä, vaan sitä voidaan ainoastaan käyttää (using).


    static void Main(string[] args)
    {
        // find my documents folder
        string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        // a few sample lines
        string[] lines = { "First line", "Second line", "Third line" };
        // write the string array to a new file named "WriteLines.txt".
        // IDisposable object use using, so resources will be disposed after using {}
        using (StreamWriter outputFile = new StreamWriter(mydocpath + @"\WriteLines.txt")) // escape sequences are ignored
        {
            foreach (string line in lines)
            {
                outputFile.WriteLine(line);
            }
        }
    }
    

Esimerkki: Tiedostoon kirjoittaminen 6

Tässä esimerkissä esitellään tekstin kirjoittamista tiedostoon WriteAllLines()-metodilla. Tiedosto kirjoitetaan käyttöjärjestelmässä olevaan "My Documents" -kansioon. WriteAllLines()-metodi tekee ko. tiedoston, kirjoittaa kokoelmana määritellyt merkkijonot tiedostoon omille rivilleen ja sulkee tiedoston.


    static void Main(string[] args)
    {
        string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        string[] lines = { "First line", "Second line", "Third line" };
        File.WriteAllLines(mydocpath + @"\WriteAllLines.txt", lines);
    }
    

Esimerkki: Tiedostoon lisääminen (kirjoittaminen) olemassaolevaan tiedostoon.

File.AppendText-metodilla voidaan lisätä tekstiä olemassa olevaan tiedostoon. Tässä esimerkissä lisätään kolme tekstiriviä olemassa olevaan tekstitiedostoon. Tiedosto luodaan jollei sitä ole.

<


    

Tekstin lukeminen tiedostosta

Alla olevissa esimerkeissä luetaan tekstia tiedostosta ja demonstroidaan samalla poikkeuksien käsittelyä.

Esimerkki: Tiedostosta lukeminen 1

Alla olevassa esimerkissä luetaan koko tekstitiedoston sisältö kerralla ja tulostetaan konsolille.


    static void Main(string[] args)
    {
        string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        try {
            string text = System.IO.File.ReadAllText(mydocpath + @"\WriteLines.txt");
            System.Console.WriteLine("Contents of test.txt:\n" + text);
        } catch (FileNotFoundException)
        {
            Console.WriteLine("File not found (FileNotFoundException)");
        }
    }
    

Esimerkkitulostus: (riippuu tiedoston sisällöstä)


    Contents of test.txt:
    First line
    Second line
    Third line
    

Esimerkki: Tiedostosta lukeminen 2

Alla olevassa esimerkissä luetaan koko tekstitiedoston sisältö kerralla string[]-taulukkoon ja käydään foreach()-lauseella läpi alkiokerrallaan.


    static void Main(string[] args)
    {
        string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        try
        {
            string[] lines = System.IO.File.ReadAllLines(mydocpath + @"\WriteLines.txt");
            foreach (string line in lines)
            {
                Console.WriteLine(line);
            }
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine("File not found (FileNotFoundException)");
        }
    }
    

Esimerkkitulostus on samanlainen kuin edellisessä esimerkissä.

Olioiden kirjoittaminen/lukeminen tiedostoon

Alla olevassa esimerkissä käydään läpi olion tallentaminen tiedostoon. Ohjelmasta on jätetty pois mahdollisten poikkeusten käsittely.

Ensimmäiseksi haluttu olio täytyy sarjallistaa, jotta se voidaan tallentaa tiedostoon. Sarjallistaminen (Serialization) on prosessi, jossa olion tiedot muutetaan tavumuotoiseksi virraksi (stream of byte), jotta ne voidaan siirtää tiedostoon. Päätarkoituksena on tallentaa olion tila, jotta se saadaan myöhemmin lukea takaisin ohjelman käyttöön siinä tilassa, jossa se tallennettaessa oli. Luettaessa olion tila muutetaan takaisin varsinaiseen oliomuotoon (Deserialization).

Person-luokka

Person-luokka voidaan sarjallistaa käyttämällä [Serializable]-määrettä luokan edessä. Tällöin Person-luokan oliot toteuttavat sarjallistamisen ja ne voidaan kirjoittaa tiedostoon.


    

Person-luokan käyttäminen

Pääohjelmassa luodaan olio Person-luokasta, kirjoitetaan ja luetaan levyltä.


    

Esimerkkitulostus:


    Jukka Husso
    

Useampien Person-luokan olioden tallentaminen/lukeminen

Useasti tulee tilanne, jossa pitää useampia luokan edustajia tallentaa/lukea levyltä. Tällöin voisi käyttää jotain toistorakennetta yhden olion kerrallaan kirjoittamiseen/lukemiseen levyltä. Onneksemme voimme kirjoittaa tietorakenteita levylle ja tätä kautta saada koko kokoelma kerralla levylle ja takaisin.


    

Esimerkkitulostus:


    Kirsi Kerneli
    Matti Konsoli
    Teppo Terävä
    

Lisätietoa:
File and Stream I/O (C# Programming Guide)
Serialization (C# Programming Guide)