logo

C의 입출력 시스템 호출 | 생성, 열기, 닫기, 읽기, 쓰기

시스템 호출은 프로그램이 직접 액세스할 수 없는 서비스를 제공하기 위해 시스템 커널에 수행하는 호출입니다. 예를 들어, 모니터 및 키보드와 같은 입력 및 출력 장치에 대한 액세스를 제공합니다. 생성, 열기, 읽기, 쓰기 등의 입출력 시스템 호출을 위해 C 프로그래밍 언어에서 제공하는 다양한 기능을 사용할 수 있습니다.

I/O 시스템 호출로 넘어가기 전에 몇 가지 중요한 용어에 대해 알아야 합니다.



중요한 용어

파일 설명자란 무엇입니까?

파일 설명자는 프로세스의 열린 파일을 고유하게 식별하는 정수입니다.

파일 설명자 테이블: 파일 설명자 테이블은 요소가 파일 테이블 항목에 대한 포인터인 파일 설명자인 정수 배열 인덱스의 모음입니다. 각 프로세스마다 운영 체제에 하나의 고유한 파일 설명자 테이블이 제공됩니다.



파일 테이블 항목: 파일 테이블 항목은 열린 파일에 대한 메모리 내 대체 구조로, 파일 열기 요청을 처리할 때 생성되며 이러한 항목은 파일 위치를 유지합니다.

C의 파일 테이블 항목

표준 파일 설명자 : 프로세스가 시작되면 해당 프로세스 파일 설명자 테이블의 fd(파일 설명자) 0, 1, 2가 자동으로 열립니다. (기본적으로) 이러한 3개의 fd는 각각 다음과 같은 파일에 대한 파일 테이블 항목을 참조합니다. /dev/tty



/dev/tty : 터미널의 메모리 내 대체물입니다.

단말기 : 키보드/비디오 화면이 결합된 화면입니다.

표준 파일 설명자

stdin에서 읽기 => fd 0에서 읽기 : 키보드에서 문자를 쓸 때마다 stdin에서 fd 0까지 읽고 /dev/tty라는 파일에 저장합니다.
stdout에 쓰기 => fd 1에 쓰기 : 비디오 화면에 대한 출력을 볼 때마다 /dev/tty라는 파일에서 나온 것이며 fd 1을 통해 화면의 stdout에 기록됩니다.
stderr에 쓰기 => fd 2에 쓰기 : 비디오 화면에 오류가 표시됩니다. 이는 fd 2를 통해 화면의 stderr에 기록된 파일에서도 발생합니다.

입출력 시스템 호출

기본적으로 I/O 시스템 호출에는 총 5가지 유형이 있습니다.

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_RD만 읽기 전용 모드로 파일을 엽니다.
O_WRONLY 쓰기 전용 모드로 파일을 엽니다.
O_RDWR 읽기 및 쓰기 모드로 파일을 엽니다.
O_CREATE 파일이 없으면 만듭니다.
O_EXCL 이미 존재하는 경우 생성을 방지합니다.
O_ 추가 파일을 열고 내용의 끝에 커서를 놓습니다.
O_ASYNC 신호에 의한 입력 및 출력 제어를 활성화합니다.
O_CLOEXEC 열린 파일에 대해 close-on-exec 모드를 활성화합니다.
O_NONBLOCK 열린 파일의 차단을 비활성화합니다.
O_TMPFILE 지정된 경로에 이름 없는 임시 파일을 만듭니다.

OS에서 C open()이 작동하는 방식

  • 디스크에서 기존 파일을 찾습니다.
  • 파일 테이블 항목을 만듭니다.
  • 사용되지 않은 첫 번째 파일 설명자가 파일 테이블 항목을 가리키도록 설정합니다.
  • 사용된 파일 설명자를 반환합니다. 실패 시 -1입니다.

C open()의 예




// 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의 close() 함수는 파일 설명자가 끝났음을 운영 체제에 알리고 파일 설명자가 가리키는 파일을 닫습니다. 내부에 정의되어 있습니다. 헤더 파일.

C의 close() 구문

int close(int fd);>

매개변수

  • fd: F 닫으려는 파일의 파일 설명자입니다.

반환 값

  • 0 성공에.
  • -1 오류가 발생했습니다.

OS에서 C close()가 작동하는 방식

  • 파일 설명자 테이블의 요소 fd가 참조하는 파일 테이블 항목을 삭제합니다.
    – 다른 프로세스가 이를 가리키지 않는 한!
  • 파일 설명자 테이블의 요소 fd를 다음으로 설정합니다. 없는

예제 1: C의 close()




// 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 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()이 반환됩니다. 왜냐하면 메인 프로세스가 생성되면 fd 0, 1, 2 이미 에 의해 촬영되었습니다 표준입력 , 표준 출력, 그리고 표준 오류 . 따라서 사용되지 않은 첫 번째 파일 설명자는 다음과 같습니다. 파일 설명자 테이블에서. 그 후 close() 시스템 호출은 무료입니다. 파일 설명자를 설정한 다음 파일 설명자 없는 . 따라서 두 번째 open()을 호출하면 사용되지 않은 첫 번째 fd도 . 따라서 이 프로그램의 출력은 다음과 같습니다. .

4. C 읽기

파일 설명자 fd가 나타내는 파일에서 read() 함수는 지정된 양의 바이트를 읽습니다. cnt 로 표시된 메모리 영역에 대한 입력의 버프 . 성공적인 read()는 파일에 대한 액세스 시간을 업데이트합니다. read() 함수는 헤더 파일 내부에도 정의되어 있습니다.

C의 read() 구문

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

매개변수

  • fd: 데이터를 읽어올 파일의 파일 설명자입니다.
  • 버프: 데이터를 읽을 버퍼
  • CNT: 버퍼의 길이

반환 값

  • 성공 시 읽은 바이트 수를 반환합니다.
  • 파일 끝에 도달하면 0을 반환
  • 오류 시 -1을 반환
  • 신호 인터럽트 시 -1을 반환합니다.

중요사항

  • 버프 오버플로로 인해 지정된 크기보다 작지 않은 길이의 유효한 메모리 위치를 가리켜야 합니다.
  • fd 읽기 작업을 수행하려면 open()에서 반환된 유효한 파일 설명자여야 합니다. fd가 NULL이면 읽기에서 오류가 발생해야 하기 때문입니다.
  • cnt 는 요청된 읽기 바이트 수이고, 반환 값은 실제 읽은 바이트 수입니다. 또한 읽기 시스템 호출이 cnt보다 적은 바이트를 읽어야 하는 경우도 있습니다.

C의 read() 예




// 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.>

foobar.txt가 6개의 ASCII 문자 foobar로 구성되어 있다고 가정합니다. 그러면 다음 프로그램의 출력은 무엇입니까?


자바 형식 문자열



// 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 각각은 자신의 열린 파일 테이블 항목을 갖고 있으므로 각 설명자는 해당 항목에 대한 자체 파일 위치를 갖습니다. foobar.txt . 따라서 다음에서 읽은 내용은 fd2 의 첫 번째 바이트를 읽습니다. foobar.txt 이고 출력은 다음과 같습니다. c = 에프 , 아니다 c = 오 .

5. C 쓰기

buf의 cnt 바이트를 fd와 연결된 파일이나 소켓에 씁니다. cnt는 INT_MAX(limits.h 헤더 파일에 정의됨)보다 커서는 안 됩니다. cnt가 0이면 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 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);> }>

>

>

산출

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

여기에서 코드를 실행한 후 foo.txt 파일을 보면 안녕하세요 괴짜들 . foo.txt 파일에 이미 일부 콘텐츠가 있는 경우 쓰기 시스템 호출이 콘텐츠를 덮어쓰고 모든 이전 콘텐츠는 삭제됨 그리고 오직 안녕하세요 괴짜들 내용은 파일에 있습니다.

예: printf 함수를 사용하지 않고 프로그램에서 hello world를 인쇄합니다.




// 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에 쓰고 출력을 인쇄합니다. 안녕 세계 .