logo

C での入出力システム コール |作成、開く、閉じる、読み取り、書き込み

システム コールは、プログラムが直接アクセスできないサービスを提供するために、プログラムがシステム カーネルに対して行う呼び出しです。たとえば、モニターやキーボードなどの入出力デバイスへのアクセスを提供します。 create、open、read、write などの入出力システム コールには、C プログラミング言語で提供されるさまざまな関数を使用できます。

I/O システム コールに進む前に、いくつかの重要な用語について知っておく必要があります。



重要な用語

ファイル記述子とは何ですか?

ファイル記述子は、プロセスの開いているファイルを一意に識別する整数です。

ファイル記述子テーブル: ファイル 記述子テーブルは、要素がファイル テーブル エントリへのポインタであるファイル記述子である整数配列インデックスのコレクションです。オペレーティング システムには、プロセスごとに 1 つの一意のファイル記述子テーブルが提供されます。



ファイルテーブルエントリ: ファイル テーブル エントリは、開いているファイルのメモリ内サロゲート構造であり、ファイルを開く要求を処理するときに作成され、これらのエントリはファイルの位置を維持します。

C のファイル テーブル エントリ

標準ファイル記述子 : プロセスが開始されると、そのプロセス ファイル記述子テーブルの fd(ファイル記述子) 0、1、2 が自動的に開きます。(デフォルトでは) これら 3 つの fd はそれぞれ、名前付きファイルのファイル テーブル エントリを参照します。 /dev/tty



/dev/tty : 端末のメモリ内サロゲート。

Javaオブジェクトからのjson

ターミナル : キーボード/ビデオ画面の組み合わせ。

標準ファイル記述子

stdin から読み取り => fd 0 から読み取り : キーボードから文字を書き込むたびに、stdin から fd 0 まで読み取られ、/dev/tty という名前のファイルに保存されます。
標準出力に書き込む => fd 1 に書き込む : ビデオ画面への出力が表示されるたびに、それは /dev/tty という名前のファイルからのものであり、fd 1 を介して画面の stdout に書き込まれます。
stderr に書き込む => fd 2 に書き込む : ビデオ画面にエラーが表示されます。これは、FD 2 を介して画面内の stderr に書き込まれたファイルからも発生します。

入出力システムコール

基本的に、合計 5 種類の I/O システム コールがあります。

1.C作成

create() 関数は、C で新しい空のファイルを作成するために使用されます。create() 関数を使用して、作成するファイルの権限と名前を指定できます。内部で定義されています ヘッダー ファイルと引数として渡されるフラグは内部で定義されます ヘッダファイル。

C の create() の構文

int   create  (char *  filename  , mode_t   mode  );>

パラメータ

  • ファイル名: 作成したいファイルの名前
  • モード: は、新しいファイルの権限を示します。

戻り値

  • 最初の未使用のファイル記述子を返します (0、1、2 fd が予約されているため、プロセスで最初に使用する場合は通常 3)
  • エラーの場合は -1 を返す

OS での C create() の仕組み

  • ディスク上に新しい空のファイルを作成します。
  • ファイルテーブルエントリを作成します。
  • 最初の未使用のファイル記述子がファイル テーブル エントリを指すように設定します。
  • 使用されたファイル記述子を返します。失敗した場合は -1 を返します。

2.Cオープン

C の open() 関数は、読み取り、書き込み、またはその両方のためにファイルを開くために使用されます。ファイルが存在しない場合は作成することもできます。内部で定義されています ヘッダー ファイルと引数として渡されるフラグは内部で定義されます ヘッダファイル。

C の open() の構文

int   open   (const char*   Path  , int   flags  );>

パラメーター

  • パス: 開きたいファイルへのパス。
    • 使用 絶対パス から始まる / あなたがいるとき ない 同じディレクトリで作業する Cソースファイルとして。
    • 使用 相対パス これは、拡張子付きのファイル名のみです。 同じディレクトリで作業する Cソースファイルとして。
  • フラグ: ファイルを開く方法を指定するために使用されます。次のフラグを使用できます。

フラグ

説明

O_RDONLY ファイルを読み取り専用モードで開きます。
O_WRONLY ファイルを書き込み専用モードで開きます。
O_RDWR ファイルを読み取りおよび書き込みモードで開きます。
O_CREATE ファイルが存在しない場合は作成します。
O_EXCL すでに存在する場合は作成を防止します。
O_ 追加 ファイルを開き、コンテンツの末尾にカーソルを置きます。
O_非同期 信号による入出力制御を可能にします。
O_CLOEXEC 開いているファイルに対して close-on-exec モードを有効にします。
O_NONBLOCK 開かれたファイルのブロックを無効にします。
O_TMPFILE 指定されたパスに名前のない一時ファイルを作成します。

OS での C open() の仕組み

  • ディスク上の既存のファイルを見つけます。
  • ファイルテーブルエントリを作成します。
  • 最初の未使用のファイル記述子がファイル テーブル エントリを指すように設定します。
  • 使用されたファイル記述子を返します。失敗した場合は -1 を返します。

C の open() の例

C




// C program to illustrate> // open system call> #include> #include> #include> #include> extern> int> errno>;> int> main()> {> >// if file does not have in directory> >// then file foo.txt is created.> >int> fd = open(>'foo.txt'>, O_RDONLY | O_CREAT);> >printf>(>'fd = %d '>, fd);> >if> (fd == -1) {> >// print which type of error have in a code> >printf>(>'Error Number % d '>,>errno>);> >// print program detail 'Success or failure'> >perror>(>'Program'>);> >}> >return> 0;> }>

>

>

出力

fd = 3>

3.C閉じる

C の close() 関数は、ファイル記述子の処理が完了したことをオペレーティング システムに伝え、ファイル記述子が指すファイルを閉じます。内部で定義されています ヘッダファイル。

C の close() の構文

int close(int fd);>

パラメータ

  • FD:F 閉じるファイルのファイル記述子。

戻り値

  • 0 成功について。
  • -1 エラーで。

OS での C close() の仕組み

  • ファイル記述子テーブルの要素 fd によって参照されるファイル テーブル エントリを破棄します。
    – 他のプロセスがそれを指していない限り!
  • ファイル記述子テーブルの要素 fd を次のように設定します。 ヌル

例 1: C の close()

C




// C program to illustrate close system Call> #include> #include> #include> int> main()> {> >int> fd1 = open(>'foo.txt'>, O_RDONLY);> >if> (fd1 <0) {> >perror>(>'c1'>);> >exit>(1);> >}> >printf>(>'opened the fd = % d '>, fd1);> >// Using close system Call> >if> (close(fd1) <0) {> >perror>(>'c1'>);> >exit>(1);> >}> >printf>(>'closed the fd. '>);> }>

>

>

出力

opened the fd = 3 closed the fd.>

例 2:

C




1 ~ 100 のローマ字番号
// C program to illustrate close system Call> #include> #include> int> main()> {> >// assume that foo.txt is already created> >int> fd1 = open(>'foo.txt'>, O_RDONLY, 0);> >close(fd1);> > >// assume that baz.tzt is already created> >int> fd2 = open(>'baz.txt'>, O_RDONLY, 0);> > >printf>(>'fd2 = % d '>, fd2);> >exit>(0);> }>

>

>

出力

fd2 = 3>

ここで、このコードでは最初に open() が返します。 3 なぜなら、メインプロセスが作成されると、fd 0、1、2 すでに取られています 標準入力 標準出力、 そして 標準エラー 。したがって、最初の未使用のファイル記述子は次のようになります。 3 ファイル記述子テーブル内。その後、close() システムコールでこれらが解放されます 3 ファイル記述子を設定してから、 3 ファイル記述子として ヌル 。したがって、2 番目の open() を呼び出したとき、最初の未使用の fd も 3 。したがって、このプログラムの出力は次のようになります 3

4.C読み取り

ファイル記述子 fd で示されたファイルから、read() 関数は指定されたバイト数を読み取ります。 cnt で示されるメモリ領域への入力 バフ 。 read() が成功すると、ファイルのアクセス時間が更新されます。 read() 関数もヘッダー ファイル内で定義されます。

C の read() の構文

size_t   read   (int   fd  , void*   buf  , size_t   cnt  );>

パラメーター

  • FD: データを読み取るファイルのファイル記述子。
  • バフ: データを読み取るバッファ
  • cnt: バッファの長さ

戻り値

  • return 成功時に読み取られたバイト数
  • ファイルの終わりに達すると 0 を返します
  • エラーの場合は -1 を返します
  • 信号割り込みで -1 を返す

注意事項

  • バフ オーバーフローのため、指定されたサイズ以上の長さの有効なメモリ位置を指す必要があります。
  • fd fd が NULL の場合、読み取りでエラーが発生するため、読み取り操作を実行するには、open() から返される有効なファイル記述子である必要があります。
  • cnt は要求された読み取りバイト数であり、戻り値は実際に読み取られたバイト数です。また、場合によっては、read システム コールが cnt よりも少ないバイトを読み取る必要があることがあります。

C での read() の例

C




// C program to illustrate> // read system Call> #include> #include> #include> int> main()> {> >int> fd, sz;> >char>* c = (>char>*)>calloc>(100,>sizeof>(>char>));> >fd = open(>'foo.txt'>, O_RDONLY);> >if> (fd <0) {> >perror>(>'r1'>);> >exit>(1);> >}> >sz = read(fd, c, 10);> >printf>(>'called read(% d, c, 10). returned that'> >' %d bytes were read. '>,> >fd, sz);> >c[sz] =>' '>;> >printf>(>'Those bytes are as follows: % s '>, c);> >return> 0;> }>

>

>

出力

called read(3, c, 10). returned that 10 bytes were read. Those bytes are as follows: 0 0 0 foo.>

foob​​ar.txt が 6 つの ASCII 文字 foobar で構成されているとします。それでは、次のプログラムの出力は何でしょうか?

C




// C program to illustrate> // read system Call> #include> #include> #include> #include> int> main()> {> >char> c;> >int> fd1 = open(>'sample.txt'>, O_RDONLY, 0);> >int> fd2 = open(>'sample.txt'>, O_RDONLY, 0);> >read(fd1, &c, 1);> >read(fd2, &c, 1);> >printf>(>'c = %c '>, c);> >exit>(0);> }>

>

パンダのイテロウ
>

出力

c = f>

記述子 fd1 そして fd2 それぞれに独自のオープン ファイル テーブル エントリがあるため、各記述子には独自のファイル位置があります。 foob​​ar.txt 。したがって、からの読み取りは、 fd2 の最初のバイトを読み取ります foob​​ar.txt 、出力は次のようになります c = f 、 ない c = o

5.C書き込み

cnt バイトを buf から fd に関連付けられたファイルまたはソケットに書き込みます。 cnt は INT_MAX (limits.h ヘッダー ファイルで定義) を超えてはなりません。 cnt がゼロの場合、write() は他のアクションを試行せずに単に 0 を返します。

write() も内部で定義されています ヘッダファイル。

C の write() の構文

size_t   write   (int   fd  , void*   buf  , size_t   cnt  );>

パラメーター

  • FD: ファイル記述子
  • バフ: データを書き込むバッファ。
  • cnt: バッファの長さ。

戻り値

  • 成功時に書き込まれたバイト数を返します。
  • ファイルの終わりに達すると 0 を返します。
  • エラーの場合は -1 を返します。
  • 信号割り込みで -1 を返します。

C書き込みの注意点

  • 書き込み操作のためにファイルを開く必要があります
  • バフ buf サイズが cnt より小さい場合、buf がオー​​バーフロー状態を引き起こすため、少なくとも cnt で指定された長さである必要があります。
  • cnt は要求された書き込みバイト数であり、戻り値は実際に書き込まれたバイト数です。これは次のような場合に起こります。 fd cnt よりも書き込むバイト数が少なくなります。
  • write() がシグナルによって中断された場合、その影響は次のいずれかになります。
    • write() がまだデータを書き込んでいない場合、-1 を返し、errno を EINTR に設定します。
    • write() がデータの書き込みに成功した場合、中断される前に書き込んだバイト数を返します。

C での write() の例

C




// C program to illustrate> // write system Call> #include> #include> main()> {> int> sz;> int> fd = open(>'foo.txt'>, O_WRONLY | O_CREAT | O_TRUNC, 0644);> if> (fd <0)> {> >perror>(>'r1'>);> >exit>(1);> }> sz = write(fd,>'hello geeks '>,>strlen>(>'hello geeks '>));> printf>(>'called write(% d, 'hello geeks ', %d).'> >' It returned %d '>, fd,>strlen>(>'hello geeks '>), sz);> close(fd);> }>

>

>

乱数Cコード

出力

called write(3, 'hello geeks
', 12). it returned 11>

ここで、コードの実行後にファイル foo.txt を見ると、 こんにちは、オタクの皆さん 。 foo.txt ファイルにすでにコンテンツが含まれている場合、システム呼び出しによる書き込みによってコンテンツが上書きされ、以前のコンテンツはすべて削除されます。 削除されました そしてだけ こんにちは、オタクの皆さん コンテンツはファイルに含まれます。

例: printf 関数を使用せずにプログラムから hello world を出力します。

C




// C program to illustrate> // I/O system Calls> #include> #include> #include> #include> int> main(>void>)> {> >int> fd[2];> >char> buf1[12] =>'hello world'>;> >char> buf2[12];> >// assume foobar.txt is already created> >fd[0] = open(>'foobar.txt'>, O_RDWR);> >fd[1] = open(>'foobar.txt'>, O_RDWR);> >write(fd[0], buf1,>strlen>(buf1));> >write(1, buf2, read(fd[1], buf2, 12));> >close(fd[0]);> >close(fd[1]);> >return> 0;> }>

>

>

出力

hello world>

このコードでは、buf1 配列の文字列 こんにちは世界 最初に stdin fd[0] に書き込まれ、その後、この文字列が buf2 配列の stdin に書き込まれます。その後、buf2 配列に stdout に書き込み、出力を出力します。 こんにちは世界