int open(char *path, int flags[, int mode]);
int close(int fd);
int read(int fd, char *buf, int size);
int write(int fd, char *buf, int size);
off_t lseek(int fd, off_t offset, int whence);
Il existe 5 appels systèmes principaux pour manipuler des fichiers.
fopen
qui appelle open)
man 2 open)OPEN(2) BSD System Calls Manual OPEN(2)
NAME
open -- open or create a file for reading or writing
SYNOPSIS
#include <fcntl.h>
int open(const char *path, int oflag, ...);
DESCRIPTION
The file name specified by path is opened for reading and/or writing, as specified by the argument oflag; the file descriptor is returned to the calling process.
The oflag argument may indicate that the file is to be created if it does not exist (by specifying the O_CREAT flag). In this case, open requires a third argument mode_t mode; the file is created with mode mode as described in chmod(2) and modified by the process' umask value (see umask(2)).
int open(char *path, int flags[, int mode]);
#include <fcntl.h>
main() {
int fd;
fd = open("test.txt", O_WRONLY | O_TRUNC);
printf("%d\n", fd);
}
L'appel open sert à demander l'accès à un fichier
path indique le chemin du fichierflags indique comment on veut manipuler le fichiermode définit les permissions à donner en cas de création d'un nouveau fichierO_RDONLY open for reading only
O_WRONLY open for writing only
O_RDWR open for reading and writing
O_NONBLOCK do not block on open or for data to become available
O_APPEND append on each write
O_CREAT create file if it does not exist
O_TRUNC truncate size to 0
O_EXCL error if O_CREAT and the file exists
...
flags est un ou bit-à-bit de valeurs/usr/include/sys/fcntl.hint close(int fd);
#include <fcntl.h>
#include <unistd.h>
main() {
int fd1, fd2;
fd1 = open("test.txt", O_RDONLY);
if (fd1 < 0) {
exit(1);
}
fd2 = open("test.txt", O_RDONLY);
if (fd2 < 0) {
exit(1);
}
if (close(fd1) < 0) {
exit(1);
}
}
L'appel close permet de libérer un descripteur de fichier
int read(int fd, char *buf, int size);
int main() {
char *b;
int fd, sz;
b = malloc(sizeof(char) * 11);
fd = open("test.txt", O_RDONLY);
if (fd < 0) {
exit(1);
}
do {
sz = read(fd, b, 10);
b[sz] = '\0';
printf("lu: %s\n", b);
} while (sz == 10);
close(fd);
}
L'appel read sert à lire des octets dans un fichier
fd est le descripteur du fichier à lirebuf est un pointeur vers un tableau où mettre les caractères lussize est le nombre d'octets à liresize si on est en fin de fichier)int write(int fd, char *buf, int size);
int main() {
int fd, sz;
char *txt;
fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
exit(1);
}
txt = "Bonjour\n";
sz = write(fd, txt, 8);
close(fd);
}
L'appel write permet d'écrire des octets dans un fichier
fd est le descripteur du fichier où écrirebuf est un pointeur vers un tableau de caractères à écriresize correspond au nombre de caractères du tableau buf à écriresize) ou -1 en cas d'erreurint main() {
char *c;
int fd, sz;
c = malloc(sizeof(char) * 10);
fd = open("test.txt", O_RDWR | O_APPEND);
if (fd < 0) {
exit(1);
}
while(1) {
sz = read(fd, c, 10);
write(fd, c, sz);
if (sz < 10) break;
}
close(fd);
}
Les fichiers ouverts sont tous associés à un pointeur de fichier qui indique un emplacement dans le fichier
read ou write, la lecture et l'écriture se font au niveau du pointeurint main() { int fd1, fd2; fd1 = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC); fd2 = open("test.txt", O_WRONLY); write(fd1, "un ", 3); write(fd2, "deux ", 5); write(fd1, "trois ", 6); } ⟶ deutroisint main() { int fd1, fd2; fd1 = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC | O_APPEND); fd2 = open("test.txt", O_WRONLY | O_APPEND); write(fd1, "un ", 3); write(fd2, "deux ", 5); write(fd1, "trois ", 6); } ⟶ un deux trois
On peut ouvrir plusieurs fois un même fichier (même en écriture)
O_APPEND restent à la fin du fichiermain() {
char c;
while (read(0, &c, 1) == 1) {
write(1, &c, 1);
}
}
Les trois premiers descripteurs de fichiers sont automatiquement attribués à chaque processus :
stdin)stdout)stderr)On peut directement utiliser ces descripteurs de fichiers sans avoir à utiliser open.
int main() {
char c[10];
int fd, sz;
fd = open("test.txt", O_RDWR);
if (fd < 0) exit(1);
int rp = 0;
int wp = lseek(fd, 0, SEEK_END);
do {
lseek(fd, rp, SEEK_SET);
sz = read(fd, c, 10);
rp = lseek(fd, 0, SEEK_CUR);
lseek(fd, wp, SEEK_SET);
write(fd, c, sz);
wp = lseek(fd, 0, SEEK_CUR);
} while (sz == 10);
close(fd);
}
lseek permet de déplacer manuellement le pointeur de fichier
fd désigne le descripteur de fichieroffset indique le nombre d'octets de déplacementwhence permet de décrire la référence du déplacement
SEEK_SET début du fichierSEEK_CUR position actuelleSEEK_END fin du fichierIl est possible de déplacer le curseur au-delà de la fin du fichier
int main() {
FILE *fpin, *fpout;
int i=0;
fpin = fopen("test.txt", "r");
fpout = fopen("res.txt", "w");
char s[80];
while(fgets(s, 80, fpin)) {
fprintf(fpout, "ligne %d: %s", i, s);
i++;
}
fclose(fpin);
fclose(fpout);
}
En général, on n'appelle pas directement les appels systèmes mais on utilise des fonctions de la librairie C qui les appellent indirectement :
fopen, fclosefgetc, fgets, fscanf, etc.fputc, fprintf, fputs, etc.
Ces fonctions manipulent les fichiers par l'intermédiaire de pointeurs de fichiers (file pointers) de type FILE* (structure contenant un descripteur de fichier, et des informations
supplémentaires)