C Language
Filer och I / O-strömmar
Sök…
Syntax
- #include <stdio.h> / * Inkludera detta för att använda någon av följande avsnitt * /
- FIL * fopen (const char * sökväg, const char * -läge); / * Öppna en ström på filen vid sökvägen med det angivna läget * /
- FIL * freopen (const char * sökväg, const char * mode, FILE * stream); / * Öppna en befintlig ström på filen vid sökvägen igen med det angivna läget * /
- int fclose (FILE * stream); / * Stäng en öppnad ström * /
- size_t fread (void * ptr, size_t size, size_t nmemb, FILE * stream); / * Läs på de flesta nmemb element av storlek bytes vardera från strömmen och skriva dem i ptr. Returnerar antalet lästa element. * /
- size_t fwrite (const void * ptr, size_t size, size_t nmemb, FILE * stream); / * Write nmemb element av storlek bytes vardera från ptr till strömmen. Returnerar antalet skriftliga element. * /
- int fseek (FIL * ström, lång offset, int varifrån); / * Ställ in markören för strömmen i förskjutning , i förhållande till den offset som berättas från varifrån , och returnerar 0 om det lyckades. * /
- long ftell (FILE * stream); / * Återgå offset för den aktuella markörpositionen från början av strömmen. * /
- void rewind (FILE * stream); / * Ställ markörens position till början av filen. * /
- int fprintf (FIL * fel, const char * fmt, ...); / * Skriver printf-formatsträng på fel * /
- FIL * stdin; / * Standardinmatningsström * /
- FIL * stdout; / * Standard utgångsström * /
- FIL * stderr; / * Standardfelström * /
parametrar
Parameter | detaljer |
---|---|
const char * -läge | En sträng som beskriver öppningsläget för den filstödda strömmen. Se anmärkningar för möjliga värden. |
int varifrån | Kan vara SEEK_SET att ställa in från början av filen, SEEK_END att ställa in från dess slut, eller SEEK_CUR att ställa in relativt det aktuella markörvärdet. Obs: SEEK_END är inte portabel. |
Anmärkningar
Mode strängar:
fopen()
i fopen()
och freopen()
kan vara ett av dessa värden:
-
"r"
: Öppna filen i skrivskyddad läge med markören inställd på början av filen. -
"r+"
: Öppna filen i läs-skrivläge, med markören inställd på början av filen. -
"w"
: Öppna eller skapa filen i skrivskyddsläge, med dess innehåll trunkerat till 0 byte. Markören är inställd på början av filen. -
"w+"
: Öppna eller skapa filen i läs-skrivläge, med dess innehåll trunkerat till 0 byte. Markören är inställd på början av filen. -
"a"
: Öppna eller skapa filen i skrivskyddsläge med markören inställd på slutet av filen. -
"a+"
: Öppna eller skapa filen i läs-skrivläge, med läsmarkören inställd på början av filen. Utsignalen läggs dock alltid till i slutet av filen.
Var och en av dessa fillägen kan ha en b
tillagd efter den initiala bokstaven (t.ex. "rb"
eller "a+b"
eller "ab+"
). b
betyder att filen ska behandlas som en binär fil istället för en textfil på de system där det finns skillnad. Det gör ingen skillnad på Unix-liknande system; det är viktigt på Windows-system. (Dessutom tillåter Windows fopen
en tydlig t
istället för b
att indikera 'textfil' - och många andra plattformspecifika alternativ.)
-
"wx"
: Skapa en textfil i skrivskyddsläge. Filen kanske inte finns . -
"wbx"
: Skapa en binär fil i skrivskyddsläge. Filen kanske inte finns .
x
, om det finns, måste vara det sista tecknet i lägessträngen.
Öppna och skriv till fil
#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;
}
Detta program öppnar filen med namn som anges i argumentet till main, som standard till output.txt
om inget argument ges. Om en fil med samma namn redan finns kasseras dess innehåll och filen behandlas som en ny tom fil. Om filerna inte redan finns fopen()
det.
Om fopen()
misslyckas av någon anledning returnerar det ett NULL
värde och ställer in det globala errno
värdet. Detta innebär att programmet kan testa det returnerade värdet efter fopen()
perror()
och använda perror()
om fopen()
misslyckas.
Om fopen()
lyckas returnerar det en giltig FILE
pekare. Den här pekaren kan sedan användas för att referera till den här filen tills fclose()
kallas på den.
fputs()
skriver den givna texten till den öppnade filen och ersätter allt tidigare innehåll i filen. På samma sätt som fopen()
fputs()
funktionen fputs()
också in errno
värdet om det misslyckas, men i detta fall returnerar funktionen EOF
att indikera misslyckandet (annars ger det ett icke-negativt värde).
fclose()
spolar alla buffertar, stänger filen och frigör minnet som FILE *
pekar på. fputs()
indikerar färdigställning precis som fputs()
gör (även om det returnerar '0' om det lyckas), ställer också in errno
värdet vid errno
.
fprintf
Du kan använda fprintf
på en fil precis som du kan göra på en konsol med printf
. Till exempel för att hålla reda på vinster, förluster och band som du kanske skriver
/* 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);
}
En sidoanteckning: Vissa system (ökänt, Windows) använder inte vad de flesta programmerare skulle kalla "normala" linjeavslut. Medan UNIX-liknande system använder \ n för att avsluta rader, använder Windows ett par tecken: \ r (vagnretur) och \ n (radmatning). Denna sekvens kallas vanligtvis CRLF. Men när du använder C behöver du inte oroa dig för dessa mycket plattformsberoende detaljer. AC-kompilator krävs för att konvertera varje instans av \ n till rätt plattformsslutt. Så en Windows-kompilator konverterar \ n till \ r \ n, men en UNIX-kompilator skulle behålla den som den är.
Kör processen
#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;
}
Detta program kör en process ( netstat
) via popen()
och läser alla standardutgångar från processen och återger den till standardutgången.
Obs: popen()
finns inte i standard C-biblioteket , men det är snarare en del av POSIX C )
Hämta rader från en fil med getline ()
POSIX C-biblioteket definierar funktionen getline()
. Denna funktion tilldelar en buffert för att hålla radinnehållet och returnerar den nya raden, antalet tecken i raden och buffertens storlek.
Exempelprogram som får varje rad från 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;
}
Inmatningsfil 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.
Produktion
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:
I exemplet kallas getline()
initialt utan någon buffert tilldelad. Under det första samtalet fördelar getline()
en buffert, läser den första raden och placerar radens innehåll i den nya bufferten. Vid efterföljande samtal uppdaterar getline()
samma buffert och omfördelar endast bufferten när den inte längre är stor nog för att passa hela linjen. Den tillfälliga bufferten frigörs sedan när vi är klara med filen.
Ett annat alternativ är getdelim()
. Det här är samma som getline()
förutom att du anger linjen som slutar karaktär. Detta är endast nödvändigt om det sista tecknet i raden för din filtyp inte är '\ n'. getline()
fungerar även med Windows-textfiler eftersom multibytesraden slutar ( "\r\n")
'\ "\r\n")
' 'fortfarande det sista tecknet på raden.
Exempel på implementering av 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
Öppna och skriva till en binär fil
#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;
}
Detta program skapar och skriver text i binär form genom fwrite
funktionen till filen output.bin
.
Om en fil med samma namn redan finns kasseras dess innehåll och filen behandlas som en ny tom fil.
En binär ström är en ordnad sekvens av tecken som på ett transparent sätt kan spela in interna data. I det här läget skrivs byte mellan programmet och filen utan någon tolkning.
För att skriva heltal bärbart måste det vara känt om filformatet förväntar sig dem i stort eller lite endianformat och storleken (vanligtvis 16, 32 eller 64 bitar). Bitskiftning och maskering kan sedan användas för att skriva ut byte i rätt ordning. Heltal i C garanteras inte att två har komplementrepresentation (även om nästan alla implementeringar gör det). Lyckligtvis en omvandling till osignerad garanteras att använda tvåor komplement. Koden för att skriva ett signerat heltal till en binär fil är därför lite förvånande.
/* 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;
}
De andra funktionerna följer samma mönster med mindre ändringar för storlek och byteordning.
fscanf ()
Låt oss säga att vi har en textfil och att vi vill läsa alla ord i den filen för att göra några krav.
file.txt :
This is just
a test file
to be used by fscanf()
Detta är huvudfunktionen:
#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++;
}
}
Utgången kommer att vara:
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()
Läs rader från en fil
stdio.h
huvudet definierar fgets()
-funktionen. Denna funktion läser en rad från en ström och lagrar den i en specificerad sträng. Funktionen slutar läsa text från strömmen när antingen n - 1
tecken läses, det nya linjetecknet ( '\n'
) läses eller slutet på filen (EOF) nås.
#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);
}
}
Ringa programmet med ett argument som är en sökväg till en fil som innehåller följande text:
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.
Kommer att resultera i följande utgång:
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]:
Detta mycket enkla exempel tillåter en fast maxlinjelängd, så att längre linjer effektivt räknas som två linjer. fgets()
kräver att samtalskoden tillhandahåller minnet som ska användas som destination för den rad som läses.
POSIX gör getline()
-funktionen tillgänglig som istället internt tilldelar minne för att förstora bufferten efter behov för en linje av valfri längd (så länge det finns tillräckligt med minne).