int fd; fd = open( "tiedosto.txt", O_RDONLY );Ensimmäinen parametri on avattava tiedosto, toisena operaation tyyppi O_RDONLY, O_WRONLY tai O_RDWR. Kun tiedosto avataan kirjoittamista varten, näyttää operaatio seuraavalta:
fd = open( "tiedosto.txt", O_WRONLY | O_CREAT, 0600 );Toiseen parametriin on lisätty |:llä määre O_CREAT, joka tarkoittaa, että tiedosto luodaan jos se ei jo ole olemassa. Kolmas parametri on tiedoston oikeudet, tässä tapauksessa 0600 eli omistajalle read- ja write-oikeudet ja muille ei mitään oikeuksia.
Katso tarkemmin man 2 open.
Seuraavassa testataan onnistuminen ja epäonnistuessa kutsutaan perror-funktiota, joka tulostaa konsolille virheen syyn sekä käyttäjän määräämän tekstin.
fd = open( "tiedosto.txt", O_WRONLY | O_CREAT, 0600 ); if ( fd == -1 ){ perror("virhe openissa"); return 0; }Virhetilanteessa asettaa järjestelmä automaattisesti virheen tyypin ilmoittavan arvon globaaliin muuttujaan errno. Esim. open:in yhteydessä virhetilanteen sattuessa errno voi saada seuraavia arvoja (openin man-sivulta):
EEXIST pathname already exists and O_CREAT and O_EXCL were used. EISDIR pathname refers to a directory and the access requested involved writing (that is, O_WRONLY or O_RDWR is set). EACCES The requested access to the file is not allowed, or one of the directories in pathname did not allow search (execute) permis- sion, or the file did not exist yet and write access to the par- ent directory is not allowed. ENAMETOOLONG pathname was too long. ENOENT O_CREAT is not set and the named file does not exist. Or, a directory component in pathname does not exist or is a dangling symbolic link. EMFILE The process already has the maximum number of files open. ENFILE The limit on the total number of files open on the system has been reached. ...errno-muuttujan arvot ovat oikeastaan kokonaislukuja mutta niihin viitataan aina C-standardikirjastoissa määriteltyjen symboolisten vakioiden kautta. Komentojen käyttämät errno-arvon vakiot on määritelty kunkin komennon man-sivulla, samaan tyyliin kun yllä oleva listaus openin man-sivulta. errno-muuttuja saadaan käyttöön liittämällä ohjelmaan includella errno.h-otsikkotiedosto.
Virheen tyypin voi siis tarkastaa errno:n avulla tai vaihtoehtoisesti voidaan käyttää funktiota perror tulostamaan virheestä kertova ilmoitus ruudulle.
Kun tiedostoa ei enää tarvita, suljetaan tiedosto:
close( fd );Tiedostosta lukeminen tapahtu read-käskyllä. Hieman lyhennelty ote man-sivulta (huom. kyseessä sektion 2 man sivu):
#include < unistd.h> ssize_t read(int fd, void *buf, size_t count); DESCRIPTION read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf. RETURN VALUE On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal. On error, -1 is returned, and errno is set appropriately. In this case it is left unspecified whether the file position (if any) changes.Eli readille annetaan parametrina tiedostokuvaaja, muistiosoite, johon tieto tulee ja luettavien tavujen määrä. Jos tiedosto on lopussa, palauttaa operaatio arvonaan nollan. Paluuarvon tyyppi on ssize_t, joka on usein sama kuin int.
Ohjelma 2-1.c, joka lukee tiedoston sisällön.
Tiedostoon kirjoittaminen tapahtuu write-kutsulla. Ote man-sivulta:
#include < unistd.h> ssize_t write(int fd, const void *buf, size_t count); DESCRIPTION write() writes up to count bytes to the file referenced by the file descriptor fd from the buffer starting at buf. RETURN VALUE On success, the number of bytes written are returned (zero indicates nothing was written). On error, -1 is returned, and errno is set appropriately.Ohjelma 2-2.c, joka kirjoittaa käyttäjän syöttämän datan tiedostoon. Ohjelmoija on ollut laiska, eikä viitsi tarkastaa writen onnistumista. Tarkistus on kuitenkin syytä tehdä tuotantokäyttöön tarkoitetussa koodissa.
Komennolla write(1, "teksti", 6 ) siis voidaan kirjoittaa näytölle ja komennolla read(0, buf, sizeof(buf)) voidaan lukea näppäimistöltä syötettyä dataa. Yleensä käyttäjän kanssa kommunikointi kannattaa hoitaa toisin, esim. printf- ja scanf-funktioita käyttämällä. Myöhemmin kuitenkin tulemme huomaamaan, että on erittäin hyödyllistä päästä käsiksi standard inputiin ja outputiin tiedostokuvaajien tasolla.
Ote lseekin man-sivulta:
#include < sys/types.h> #include < unistd.h> off_t lseek(int fildes, off_t offset, int whence); The lseek() function repositions the offset of the open file associated with the file descriptor fildes to the argument offset according to the directive whence as follows: SEEK_SET The offset is set to offset bytes. SEEK_CUR The offset is set to its current location plus offset bytes. SEEK_END The offset is set to the size of the file plus offset bytes. RETURN VALUE Upon successful completion, lseek() returns the resulting offset loca- tion as measured in bytes from the beginning of the file. Otherwise, a value of (off_t)-1 is returned and errno is set to indicate the error.Kolmas parametri siis säätelee, miten operaatio toimii, eli siirretäänkö tiedosto-osoitinta suhteessa tiedoston alkuun, loppuun vai nykyiseen sijaintiin.
Ohjelma 2-5.c lukee tiedoston lopusta alkuun. Ensin selvitetään tiedoston koko siirtämällä tiedosto-osoitin tiedoston loppuun. Tämän jälkeen luetaan tavu kerrallaan alkaen tiedoston lopusta.
Stream I/O-ssa käytetään funktioita fopen, fclose, fread, fwrite, fgets, fputs, fprintf ym.
Seuraavassa esimerkkiohjelmia c-kurssin materiaalista.
Ohjelma esim7-1.c lukee tekstitiedostoa fgets-komennolla.
Ohjelma esim7-2.c kirjoittaa tiedostoon käyttäen fputs-komentoa ja ohjelma esim7-3.c kirjoittaa tiedostoon käyttäen fprintf-komentoa.
Jos tiedostoon kirjoitetaan muuta kuin tekstiä, tarvitaan fwriteä, ks. esim7-4.c ja näin kirjoitetun tiedoson lukeminen tapahtuu freadilla, ls. esim7-5.c
Suorituskykyä voi vertailla suorittamalla ohjelmat 2-6.c ja 2-7.c käyttäen Linuxin time-komentoa, joka mittaa suoritukseen kuluneen ajan. Ohjelmat lukevat ensimmäisenä komentoriviparametrina saamansa tiedoston sisällön käyttäen toisena parametrina annetun kokoisia paloja.
Joskus on tarvetta saada FILE-osoitinta vastaava tiedostokuvaaja. Tämä onnistuu komennolla fileno:
#include < stdio.h> int fileno(FILE *stream); DESCRIPTION The function fileno examines the argument stream and returns its inte- ger descriptor.Operaatio toisinpäin, eli tiedostokuvaajaa vastaavan FILE-osoittimen hankkiminen tapahtuu komennolla fdopen:
SYNOPSIS #include < stdio.h> FILE *fopen(const char *path, const char *mode); The fdopen function associates a stream with the existing file descrip- tor, fildes. The mode of the stream (one of the values "r", "r+", "w", "w+", "a", "a+") must be compatible with the mode of the file descrip- tor.