C Language
Fichiers et flux d'E / S
Recherche…
Syntaxe
- #include <stdio.h> / * Inclure ceci pour utiliser l'une des sections suivantes * /
- FILE * fopen (const char * path, const char * mode); / * Ouvre un flux sur le fichier au chemin avec le mode spécifié * /
- FILE * freopen (const char * path, const char * mode, FILE * stream); / * Rouvre un flux existant sur le fichier au chemin avec le mode spécifié * /
- int fclose (flux FILE *); / * Fermer un flux ouvert * /
- size_t fread (void * ptr, taille_t taille, size_t nmemb, flux FILE *); / * Lit à la plupart des éléments nmemb de taille chacun des octets du flux et les écrit dans ptr . Renvoie le nombre d'éléments de lecture. * /
- size_t fwrite (const void * ptr, taille_t taille, size_t nmemb, flux FILE *); / * Ecrit des éléments nmemb de taille chacun de ptr dans le flux . Renvoie le nombre d'éléments écrits. * /
- int fseek (flux FILE *, offset long, int dont); / * Réglez le curseur du flux pour compenser, par rapport au décalage dit par où, et retourne 0 si elle a réussi. * /
- long ftell (flux FILE *); / * Renvoie le décalage de la position actuelle du curseur depuis le début du flux. * /
- annuler le rembobinage (flux FILE *); / * Définit la position du curseur au début du fichier. * /
- int fprintf (FILE * fout, const char * fmt, ...); / * Ecrit la chaîne de format printf sur fout * /
- FICHIER * stdin; / * Flux d'entrée standard * /
- FILE * stdout; / * Flux de sortie standard * /
- FICHIER * stderr; / * Flux d'erreur standard * /
Paramètres
Paramètre | Détails |
---|---|
mode const char * | Une chaîne décrivant le mode d'ouverture du flux sauvegardé. Voir les remarques pour les valeurs possibles. |
d'où | Peut être SEEK_SET à définir depuis le début du fichier, SEEK_END à définir depuis sa fin ou SEEK_CUR à définir par rapport à la valeur actuelle du curseur. Remarque: SEEK_END est non portable. |
Remarques
Chaînes de mode:
Les chaînes de mode dans fopen()
et freopen()
peuvent être l'une de ces valeurs:
-
"r"
: ouvre le fichier en mode lecture seule, le curseur étant placé au début du fichier. -
"r+"
: Ouvrez le fichier en mode lecture-écriture, avec le curseur défini au début du fichier. -
"w"
: Ouvrez ou créez le fichier en mode écriture seule, son contenu étant tronqué à 0 octet. Le curseur est défini au début du fichier. -
"w+"
: Ouvrez ou créez le fichier en mode lecture-écriture, avec son contenu tronqué à 0 octet. Le curseur est défini au début du fichier. -
"a"
: Ouvrez ou créez le fichier en mode écriture seule, le curseur étant placé à la fin du fichier. -
"a+"
: ouvrez ou créez le fichier en mode lecture-écriture, le curseur de lecture étant placé au début du fichier. La sortie, cependant, sera toujours ajoutée à la fin du fichier.
Chacun de ces modes peut avoir un b
ajouté après la lettre initiale (par exemple "rb"
ou "a+b"
ou "ab+"
). Le b
signifie que le fichier doit être traité comme un fichier binaire au lieu d'un fichier texte sur les systèmes où il y a une différence. Cela ne fait aucune différence sur les systèmes de type Unix. c'est important sur les systèmes Windows. (De plus, Windows fopen
permet un t
explicite au lieu de b
pour indiquer «fichier texte» - et de nombreuses autres options spécifiques à la plate-forme.)
-
"wx"
: Créez un fichier texte en mode écriture seule. Le fichier n'existe peut-être pas . -
"wbx"
: Créez un fichier binaire en mode écriture seule. Le fichier n'existe peut-être pas .
Le x
, s'il est présent, doit être le dernier caractère de la chaîne de mode.
Ouvrir et écrire dans un fichier
#include <stdio.h> /* for perror(), fopen(), fputs() and fclose() */
#include <stdlib.h> /* for the EXIT_* macros */
int main(int argc, char **argv)
{
int e = EXIT_SUCCESS;
/* Get path from argument to main else default to output.txt */
char *path = (argc > 1) ? argv[1] : "output.txt";
/* Open file for writing and obtain file pointer */
FILE *file = fopen(path, "w");
/* Print error message and exit if fopen() failed */
if (!file)
{
perror(path);
return EXIT_FAILURE;
}
/* Writes text to file. Unlike puts(), fputs() does not add a new-line. */
if (fputs("Output in file.\n", file) == EOF)
{
perror(path);
e = EXIT_FAILURE;
}
/* Close file */
if (fclose(file))
{
perror(path);
return EXIT_FAILURE;
}
return e;
}
Ce programme ouvre le fichier avec le nom donné dans l'argument à main, par défaut à output.txt
si aucun argument n'est donné. Si un fichier portant le même nom existe déjà, son contenu est supprimé et le fichier est traité comme un nouveau fichier vide. Si les fichiers n'existent pas déjà, l'appel fopen()
le crée.
Si l'appel fopen()
échoue pour une raison quelconque, il renvoie une valeur NULL
et définit la valeur de la variable errno
globale. Cela signifie que le programme peut tester la valeur renvoyée après l'appel à fopen()
et utiliser perror()
si fopen()
échoue.
Si l'appel fopen()
réussit, il renvoie un pointeur FILE
valide. Ce pointeur peut alors être utilisé pour référencer ce fichier jusqu'à ce que fclose()
soit appelé.
La fonction fputs()
écrit le texte donné dans le fichier ouvert, remplaçant tout contenu précédent du fichier. Comme pour fopen()
, la fonction fputs()
définit également la valeur errno
si elle échoue, bien que dans ce cas la fonction retourne EOF
pour indiquer l'échec (sinon, elle renvoie une valeur non négative).
La fonction fclose()
vide les tampons, ferme le fichier et libère la mémoire pointée par FILE *
. La valeur de retour indique l'achèvement de la même manière que fputs()
(bien qu'elle renvoie "0" si elle réussit), définissant également la valeur errno
en cas d'échec.
fprintf
Vous pouvez utiliser fprintf
sur un fichier comme vous le feriez sur une console avec printf
. Par exemple, pour garder une trace des gains, des pertes et des cravates, vous pouvez écrire
/* saves wins, losses and, ties */
void savewlt(FILE *fout, int wins, int losses, int ties)
{
fprintf(fout, "Wins: %d\nTies: %d\nLosses: %d\n", wins, ties, losses);
}
Une note de côté: certains systèmes (Windows, notoirement) n'utilisent pas ce que la plupart des programmeurs appellent des fins de ligne "normales". Bien que les systèmes de type UNIX utilisent \ n pour terminer les lignes, Windows utilise une paire de caractères: \ r (retour chariot) et \ n (saut de ligne). Cette séquence est communément appelée CRLF. Cependant, chaque fois que vous utilisez C, vous n'avez pas à vous soucier de ces détails hautement dépendants de la plate-forme. Le compilateur AC est requis pour convertir chaque instance de \ n en une terminaison de ligne correcte. Ainsi, un compilateur Windows convertirait \ n en \ r \ n, mais un compilateur UNIX le conserverait tel quel.
Exécuter le processus
#include <stdio.h>
void print_all(FILE *stream)
{
int c;
while ((c = getc(stream)) != EOF)
putchar(c);
}
int main(void)
{
FILE *stream;
/* call netstat command. netstat is available for Windows and Linux */
if ((stream = popen("netstat", "r")) == NULL)
return 1;
print_all(stream);
pclose(stream);
return 0;
}
Ce programme exécute un processus ( netstat
) via popen()
et lit toute la sortie standard du processus et fait écho à la sortie standard.
Note: popen()
n'existe pas dans la bibliothèque C standard , mais il fait plutôt partie de POSIX C )
Récupère les lignes d'un fichier en utilisant getline ()
La bibliothèque POSIX C définit la fonction getline()
. Cette fonction alloue un tampon pour contenir le contenu de la ligne et renvoie la nouvelle ligne, le nombre de caractères de la ligne et la taille du tampon.
Exemple de programme qui obtient chaque ligne de example.txt
:
#include <stdlib.h>
#include <stdio.h>
#define FILENAME "example.txt"
int main(void)
{
/* Open the file for reading */
char *line_buf = NULL;
size_t line_buf_size = 0;
int line_count = 0;
ssize_t line_size;
FILE *fp = fopen(FILENAME, "r");
if (!fp)
{
fprintf(stderr, "Error opening file '%s'\n", FILENAME);
return EXIT_FAILURE;
}
/* Get the first line of the file. */
line_size = getline(&line_buf, &line_buf_size, fp);
/* Loop through until we are done with the file. */
while (line_size >= 0)
{
/* Increment our line count */
line_count++;
/* Show the line details */
printf("line[%06d]: chars=%06zd, buf size=%06zu, contents: %s", line_count,
line_size, line_buf_size, line_buf);
/* Get the next line */
line_size = getline(&line_buf, &line_buf_size, fp);
}
/* Free the allocated line buffer */
free(line_buf);
line_buf = NULL;
/* Close the file now that we are done with it */
fclose(fp);
return EXIT_SUCCESS;
}
Fichier d'entrée example.txt
This is a file
which has
multiple lines
with various indentation,
blank lines
a really long line to show that getline() will reallocate the line buffer if the length of a line is too long to fit in the buffer it has been given,
and punctuation at the end of the lines.
Sortie
line[000001]: chars=000015, buf size=000016, contents: This is a file
line[000002]: chars=000012, buf size=000016, contents: which has
line[000003]: chars=000015, buf size=000016, contents: multiple lines
line[000004]: chars=000030, buf size=000032, contents: with various indentation,
line[000005]: chars=000012, buf size=000032, contents: blank lines
line[000006]: chars=000001, buf size=000032, contents:
line[000007]: chars=000001, buf size=000032, contents:
line[000008]: chars=000001, buf size=000032, contents:
line[000009]: chars=000150, buf size=000160, contents: a really long line to show that getline() will reallocate the line buffer if the length of a line is too long to fit in the buffer it has been given,
line[000010]: chars=000042, buf size=000160, contents: and punctuation at the end of the lines.
line[000011]: chars=000001, buf size=000160, contents:
Dans l'exemple, getline()
est initialement appelée sans tampon alloué. Lors de ce premier appel, getline()
alloue un tampon, lit la première ligne et place le contenu de la ligne dans le nouveau tampon. Lors d'appels ultérieurs, getline()
met à jour le même tampon et ne réalloue le tampon que lorsqu'il n'est plus assez grand pour s'adapter à toute la ligne. Le tampon temporaire est alors libéré lorsque nous en avons fini avec le fichier.
Une autre option est getdelim()
. C'est la même chose que getline()
sauf que vous spécifiez le caractère de fin de ligne. Ceci n'est nécessaire que si le dernier caractère de la ligne pour votre type de fichier n'est pas "\ n". getline()
fonctionne même avec les fichiers texte Windows car avec la fin de la ligne multi-octets ( "\r\n")
'" est toujours le dernier caractère de la ligne.
Exemple d'implémentation de getline()
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#if !(defined _POSIX_C_SOURCE)
typedef long int ssize_t;
#endif
/* Only include our version of getline() if the POSIX version isn't available. */
#if !(defined _POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200809L
#if !(defined SSIZE_MAX)
#define SSIZE_MAX (SIZE_MAX >> 1)
#endif
ssize_t getline(char **pline_buf, size_t *pn, FILE *fin)
{
const size_t INITALLOC = 16;
const size_t ALLOCSTEP = 16;
size_t num_read = 0;
/* First check that none of our input pointers are NULL. */
if ((NULL == pline_buf) || (NULL == pn) || (NULL == fin))
{
errno = EINVAL;
return -1;
}
/* If output buffer is NULL, then allocate a buffer. */
if (NULL == *pline_buf)
{
*pline_buf = malloc(INITALLOC);
if (NULL == *pline_buf)
{
/* Can't allocate memory. */
return -1;
}
else
{
/* Note how big the buffer is at this time. */
*pn = INITALLOC;
}
}
/* Step through the file, pulling characters until either a newline or EOF. */
{
int c;
while (EOF != (c = getc(fin)))
{
/* Note we read a character. */
num_read++;
/* Reallocate the buffer if we need more room */
if (num_read >= *pn)
{
size_t n_realloc = *pn + ALLOCSTEP;
char * tmp = realloc(*pline_buf, n_realloc + 1); /* +1 for the trailing NUL. */
if (NULL != tmp)
{
/* Use the new buffer and note the new buffer size. */
*pline_buf = tmp;
*pn = n_realloc;
}
else
{
/* Exit with error and let the caller free the buffer. */
return -1;
}
/* Test for overflow. */
if (SSIZE_MAX < *pn)
{
errno = ERANGE;
return -1;
}
}
/* Add the character to the buffer. */
(*pline_buf)[num_read - 1] = (char) c;
/* Break from the loop if we hit the ending character. */
if (c == '\n')
{
break;
}
}
/* Note if we hit EOF. */
if (EOF == c)
{
errno = 0;
return -1;
}
}
/* Terminate the string by suffixing NUL. */
(*pline_buf)[num_read] = '\0';
return (ssize_t) num_read;
}
#endif
Ouvrir et écrire dans un fichier binaire
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
result = EXIT_SUCCESS;
char file_name[] = "outbut.bin";
char str[] = "This is a binary file example";
FILE * fp = fopen(file_name, "wb");
if (fp == NULL) /* If an error occurs during the file creation */
{
result = EXIT_FAILURE;
fprintf(stderr, "fopen() failed for '%s'\n", file_name);
}
else
{
size_t element_size = sizeof *str;
size_t elements_to_write = sizeof str;
/* Writes str (_including_ the NUL-terminator) to the binary file. */
size_t elements_written = fwrite(str, element_size, elements_to_write, fp);
if (elements_written != elements_to_write)
{
result = EXIT_FAILURE;
/* This works for >=c99 only, else the z length modifier is unknown. */
fprintf(stderr, "fwrite() failed: wrote only %zu out of %zu elements.\n",
elements_written, elements_to_write);
/* Use this for <c99: *
fprintf(stderr, "fwrite() failed: wrote only %lu out of %lu elements.\n",
(unsigned long) elements_written, (unsigned long) elements_to_write);
*/
}
fclose(fp);
}
return result;
}
Ce programme crée et écrit du texte sous la forme binaire via la fonction fwrite
dans le fichier output.bin
.
Si un fichier portant le même nom existe déjà, son contenu est supprimé et le fichier est traité comme un nouveau fichier vide.
Un flux binaire est une séquence ordonnée de caractères pouvant enregistrer de manière transparente des données internes. Dans ce mode, les octets sont écrits entre le programme et le fichier sans aucune interprétation.
Pour écrire des entiers de manière portable, il faut savoir si le format de fichier les attend au format big ou little-endian, et à la taille (généralement 16, 32 ou 64 bits). Le décalage et le masquage des bits peuvent alors être utilisés pour écrire les octets dans le bon ordre. Les nombres entiers dans C ne sont pas garantis d'avoir une représentation de complément à deux (bien que presque toutes les implémentations le soient). Heureusement une conversion non signée est garantie à utiliser complément à deux. Le code pour écrire un entier signé dans un fichier binaire est donc un peu surprenant.
/* write a 16-bit little endian integer */
int fput16le(int x, FILE *fp)
{
unsigned int rep = x;
int e1, e2;
e1 = fputc(rep & 0xFF, fp);
e2 = fputc((rep >> 8) & 0xFF, fp);
if(e1 == EOF || e2 == EOF)
return EOF;
return 0;
}
Les autres fonctions suivent le même schéma avec des modifications mineures de la taille et de l'ordre des octets.
fscanf ()
Disons que nous avons un fichier texte et que nous voulons lire tous les mots de ce fichier, afin de satisfaire certaines exigences.
fichier.txt :
This is just
a test file
to be used by fscanf()
Ceci est la fonction principale:
#include <stdlib.h>
#include <stdio.h>
void printAllWords(FILE *);
int main(void)
{
FILE *fp;
if ((fp = fopen("file.txt", "r")) == NULL) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
printAllWords(fp);
fclose(fp);
return EXIT_SUCCESS;
}
void printAllWords(FILE * fp)
{
char tmp[20];
int i = 1;
while (fscanf(fp, "%19s", tmp) != EOF) {
printf("Word %d: %s\n", i, tmp);
i++;
}
}
Le résultat sera:
Word 1: This
Word 2: is
Word 3: just
Word 4: a
Word 5: test
Word 6: file
Word 7: to
Word 8: be
Word 9: used
Word 10: by
Word 11: fscanf()
Lire les lignes d'un fichier
L'en-tête stdio.h
définit la fonction fgets()
. Cette fonction lit une ligne d'un flux et la stocke dans une chaîne spécifiée. La fonction arrête de lire le texte du flux lorsque n - 1
caractères sont lus, le caractère de nouvelle ligne ( '\n'
) est lu ou la fin du fichier (EOF) est atteinte.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LENGTH 80
int main(int argc, char **argv)
{
char *path;
char line[MAX_LINE_LENGTH] = {0};
unsigned int line_count = 0;
if (argc < 1)
return EXIT_FAILURE;
path = argv[1];
/* Open file */
FILE *file = fopen(path, "r");
if (!file)
{
perror(path);
return EXIT_FAILURE;
}
/* Get each line until there are none left */
while (fgets(line, MAX_LINE_LENGTH, file))
{
/* Print each line */
printf("line[%06d]: %s", ++line_count, line);
/* Add a trailing newline to lines that don't already have one */
if (line[strlen(line) - 1] != '\n')
printf("\n");
}
/* Close file */
if (fclose(file))
{
return EXIT_FAILURE;
perror(path);
}
}
Appel du programme avec un argument qui est un chemin vers un fichier contenant le texte suivant:
This is a file
which has
multiple lines
with various indentation,
blank lines
a really long line to show that the line will be counted as two lines if the length of a line is too long to fit in the buffer it has been given,
and punctuation at the end of the lines.
Entraînera la sortie suivante:
line[000001]: This is a file
line[000002]: which has
line[000003]: multiple lines
line[000004]: with various indentation,
line[000005]: blank lines
line[000006]:
line[000007]:
line[000008]:
line[000009]: a really long line to show that the line will be counted as two lines if the le
line[000010]: ngth of a line is too long to fit in the buffer it has been given,
line[000011]: and punctuation at the end of the lines.
line[000012]:
Cet exemple très simple permet une longueur de ligne maximale fixe, de sorte que les lignes plus longues seront effectivement comptabilisées comme deux lignes. La fonction fgets()
nécessite que le code appelant fournisse la mémoire à utiliser comme destination pour la ligne lue.
POSIX met à disposition la fonction getline()
qui alloue en interne de la mémoire pour agrandir le tampon selon les besoins pour une ligne de longueur quelconque (tant qu'il y a suffisamment de mémoire).