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.