C Language
ファイルと入出力ストリーム
サーチ…
構文
- #include <stdio.h> / *以下のセクションのいずれかを使用するには、これをインクルードします。* /
- FILE * fopen(const char * path、const char * mode); / *指定されたモードの パスでファイル上のストリームを開く* /
- FILE * freopen(const char *パス、const char *モード、FILE *ストリーム); / *指定されたモードでパス上のファイル上の既存のストリームを再オープンする* /
- int fclose(FILE *ストリーム); / *開いているストリームを閉じる* /
- size_t fread(void * ptr、size_t size、size_t nmemb、FILE * stream); / * ストリームからそれぞれsizeバイトの最大nmemb個の要素を読み込み、 ptrに書き込みます。読み込まれた要素の数を返します。 * /
- size_t fwrite(const void * ptr、size_t size、size_t nmemb、FILE * stream); / * sizeバイトのnmemb要素をそれぞれptrからストリームに書き込みます 。書き込まれた要素の数を返します。 * /
- int fseek(FILE *ストリーム、long offset、int whence); / *オフセットwhenceで語っに対する、 オフセットするストリームのカーソルを設定し、それが成功した場合は0を返します。 * /
- 長いftell(FILE *ストリーム); / *ストリームの先頭から現在のカーソル位置のオフセットを返します。 * /
- void rewind(FILE *ストリーム); / *カーソル位置をファイルの先頭に設定します。 * /
- int fprintf(FILE * fout、const char * fmt、...); / * foutにprintf形式の文字列を書き込みます* /
- FILE * stdin; / *標準入力ストリーム* /
- FILE * stdout; / *標準出力ストリーム* /
- FILE * stderr; / *標準エラーストリーム* /
パラメーター
パラメータ | 詳細 |
---|---|
const char *モード | ファイルバックアップされたストリームの開始モードを表す文字列。可能な値については備考を参照してください。 |
int whence | することができSEEK_SET ファイルの先頭から設定するには、 SEEK_END その終了、またはから設定するSEEK_CUR 現在のカーソルの値を基準に設定します。注: SEEK_END は移植性がありません。 |
備考
モード文字列:
fopen()
およびfreopen()
モード文字列は、次のいずれかの値になります。
-
"r"
:カーソルをファイルの先頭に設定して、読み取り専用モードでファイルを開きます。 -
"r+"
:ファイルを読み書きモードで開き、カーソルをファイルの先頭に設定します。 -
"w"
:書き込み専用モードでファイルを開くか作成します。内容は0バイトに切り捨てられます。カーソルはファイルの先頭に設定されます。 -
"w+"
:読み書きモードでファイルを開くか作成します。内容は0バイトに切り捨てられます。カーソルはファイルの先頭に設定されます。 -
"a"
:カーソルをファイルの最後に設定して、書き込み専用モードでファイルを開くか作成します。 -
"a+"
:読み書きモードでファイルを開くか作成し、読み込みカーソルをファイルの先頭に設定します。ただし、出力は常にファイルの末尾に追加されます。
これらのファイルモードのそれぞれには、最初の文字の後にb
追加することができます(例: "rb"
または"a+b"
または"ab+"
)。 b
は、違いがあるシステム上のテキストファイルではなく、ファイルをバイナリファイルとして扱うことを意味します。 Unixのようなシステムでは違いはありません。 Windowsシステムでは重要です。 (また、Windowsのfopen
では、 b
代わりに明示的なt
使用して 'テキストファイル'を指定できます。
-
"wx"
:書き込み専用モードでテキストファイルを作成します。 ファイルが存在しない可能性があります 。 -
"wbx"
:書き込み専用モードでバイナリファイルを作成します。 ファイルが存在しない可能性があります 。
x
が存在する場合、 x
はモード文字列の最後の文字でなければなりません。
ファイルを開いてファイルに書き込む
#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;
}
このプログラムはmainに引数で与えられた名前でファイルを開き、引数が与えられていなければoutput.txt
デフォルトにします。同じ名前のファイルがすでに存在する場合、その内容は破棄され、ファイルは新しい空のファイルとして扱われます。ファイルがまだ存在しない場合は、 fopen()
呼び出しによってファイルが作成されます。
fopen()
呼び出しが何らかの理由で失敗すると、 NULL
値をerrno
、グローバルerrno
変数値をerrno
ます。これは、プログラムがfopen()
呼び出しの後に戻り値をテストし、 fopen()
が失敗した場合にperror()
を使用できることを意味します。
fopen()
呼び出しが成功すると、有効なFILE
ポインタを返します。 fclose()
が呼び出されるまで、このポインタを使用してこのファイルを参照することができます。
fputs()
関数は、指定されたテキストを開いたファイルに書き込んで、ファイルの以前の内容を置き換えます。 fopen()
と同様に、 fputs()
関数は失敗した場合にもerrno
値を設定しerrno
が、この場合関数は失敗を示すEOF
を返します(そうでない場合は負ではない値を返します)。
fclose()
関数はバッファをフラッシュし、ファイルを閉じ、 FILE *
指すメモリを解放します。戻り値はfputs()
同じように完了を示しますfputs()
成功した場合は '0'を返します)。失敗した場合はerrno
も設定しerrno
。
fprintf
fprintf
は、 printf
したコンソールと同じように、ファイル上で使用できます。例えば、あなたが書くかもしれないゲームの勝利、損失、および関係を記録する
/* 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);
}
副注記:システム(悪意のあるのはWindows)は、ほとんどのプログラマが「通常の」行末と呼ぶものを使用しません。 UNIX系システムは\ nを使って行を終了しますが、\ r(改行)と\ n(改行)のペアが使用されます。このシーケンスは一般にCRLFと呼ばれます。ただし、Cを使用するたびに、これらの高度にプラットフォームに依存する詳細を心配する必要はありません。 \ nのすべてのインスタンスを正しいプラットフォーム行末に変換するには、ACコンパイラが必要です。したがって、Windowsコンパイラは\ nを\ r \ nに変換しますが、UNIXコンパイラはそのまま使用します。
プロセスを実行する
#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;
}
このプログラムはpopen()
を介してプロセス( netstat
)を実行し、プロセスからのすべての標準出力を読み込み、標準出力にエコーします。
注意: popen()
は標準Cライブラリには存在しませんが、むしろPOSIX Cの一部です)
getline()を使ってファイルから行を取得する
POSIX Cライブラリはgetline()
関数を定義します。この関数は、行の内容を保持するバッファを割り当て、新しい行、行の文字数、およびバッファのサイズを返します。
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;
}
入力ファイル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.
出力
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:
この例では、最初にgetline()
が呼び出され、バッファは割り当てられません。この最初の呼び出しの間、 getline()
はバッファを割り当て、最初の行を読み取り、その行の内容を新しいバッファに入れます。後続の呼び出しでは、 getline()
は同じバッファを更新し、バッファ全体が行全体に収まるようになったときにのみバッファを再割り当てします。一時バッファは、ファイルが終了すると解放されます。
別のオプションはgetdelim()
です。これは、行末の文字を指定する以外はgetline()
と同じです。これは、ファイルタイプの行の最後の文字が '\ n'でない場合にのみ必要です。末尾のマルチバイト行( "\r\n")
'\ "\r\n")
は行の最後の文字なので、 getline()
はWindowsのテキストファイルでも機能します。
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
バイナリファイルを開いて書き込む
#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;
}
このプログラムはバイナリ形式のテキストを作成し、 fwrite
関数を介してファイルoutput.bin
書き込みます。
同じ名前のファイルがすでに存在する場合、その内容は破棄され、ファイルは新しい空のファイルとして扱われます。
バイナリストリームは、内部データを透過的に記録できる順序付けられた文字列です。このモードでは、バイトはプログラムとファイルの間に何も解釈されずに書き込まれます。
整数を移植可能に書くには、ファイル形式がビッグエンディアン形式かリトルエンディアン形式か、サイズ(通常は16,32,64ビット)であるかどうかを知る必要があります。ビットシフトとマスキングを使用して、バイトを正しい順序で書き出すことができます。 Cの整数は、2の補数表現を持つことは保証されていません(ほとんどすべての実装が行いますが)。幸いにも、符号なしへの変換では 2の補数を使用することが保証されます。したがって、符号付き整数をバイナリファイルに書き込むためのコードは少し驚くべきものです。
/* 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;
}
他の関数は、サイズとバイトオーダーの変更を加えて同じパターンに従います。
fscanf()
テキストファイルがあり、いくつかの要件を満たすために、そのファイルのすべての単語を読みたいとしましょう。
file.txt :
This is just
a test file
to be used by fscanf()
これが主な機能です:
#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++;
}
}
出力は次のようになります。
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()
ファイルから行を読み込む
stdio.h
ヘッダはfgets()
関数を定義します。この関数は、ストリームから行を読み込み、指定された文字列に格納します。この関数は、 n - 1
文字のいずれかを読み込んだり、改行文字( '\n'
)を読み込んだり、ファイルの終わり(EOF)に達したときに、ストリームからテキストの読み込みを停止します。
#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);
}
}
次のテキストを含むファイルへのパスである引数を指定してプログラムを呼び出します。
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.
結果は次のようになります。
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]:
この非常に単純な例では、固定長の行の長さが許されているので、長い行は2行として有効にカウントされます。 fgets()
関数は、呼び出したコードが、読み込まれた行の宛先として使用されるメモリを提供することを要求します。
POSIXはgetline()
関数を使用可能にします。代わりに、十分なメモリがある限り、任意の長さの行に必要に応じてバッファを拡大するために内部的にメモリを割り当てます。