UNIX I/O(Input & Output)
목표
- 장치에 독립적인 입출력의 기본 개념을 학습한다.
- 읽기(read)와 쓰기(write)를 실험한다.
- 여러 파일 디스크립터를 모니터링하는 방법을 탐구한다.
- 올바른 오류 처리를 사용한다.
- 파일 디스크립터의 상속을 이해한다.
{장치 용어}
- 주변 장치 : 컴퓨터 시스템에서 접근하는 하드웨어 장치(입출력 장치) ex) 디스크, 테이프, CD-ROM,화면,키보드,프린터,마우스 장치 및 네트워크 인터페이스
- 장치 드라이버 : 사용자 프로그램이 시스템 호출을 통해 운영체제 모듈에 접근하여 장치들에 대한 제어 및 입출력을 수행
장치 드라이버는 장치 작동의 세부 사항을 숨기고, 장치를 비인가 사용으로부터 보호함
- UNIX는 대부분의 장치에 5가지 함수를 통해 일관된 접근을 제공하여 장치 인터페이스를 단순화함
(open, close, read, write and ioctl)
- 특수 파일 : 모든 장치는 특수 파일이라고 불리는 파일로 표현되고 이는 /dev(device의 약자) 디렉토리에 위치, 디스크 파일 및 다른 장치는 동일한 방식으로 이름이 지정 및 접근됨
UNIX 파일
- UNIX 파일은 m 바이트로 이루어진 연속된 시퀀스 ex) B0,B1...Bk...,Bm-1
- 모든 입출력 장치 및 커널은 파일로 표현됨
/dev/sda2 (하드 디스크 파티션), /dev/tty2 (터미널) / /dev/knem (커널 메모리 이미지), /proc (커널 데이터 구조)
UNIX I/O
- 파일을 우아하게 장치에 매핑하여 단순하고 저수준의 인터페이스인 UNIX I/O를 제공하고, 모든 입출력은 일관되고 통일된 방식으로 처리됨
- 기본적인 UNIX I/O 작업 (시스템 호출) - 파일 열기 및 닫기
- open() : 애플리케이션이 I/O 장치에 접근할 의도를 알림
- close() : 애플리케이션이 파일 접근을 마침
- 현재 파일 위치 변경 (seek)
- 커널은 파일 위치 k를 유지하고 열린 파일에 대해 처음에는 0으로 설정됨, 파일 위치는 파일 시작점으로부터의 바이트 오프셋이고 애플리케이션은 seek 함수를 호출하여 파일 위치 k를 명시적으로 설정 가능함
- 파일 읽기 및 쓰기 - 연속적으로 작동, 중간에 임의의 지점에 설정하려면 처음에 위치를 중간으로 지정해야됨
- read() : 파일에서 메모리로 n 바이트 읽음
- write() : 메모리에서 파일로 n 바이트를 씀
Reading (읽기)
- UNIX는 read 및 write 함수를 통해 파일과 다른 장치에 순차적으로 접근 (3가지 파라미터 제공,
#include <unistd.h>
ssize_t read(int filedes, void *buf, size_t nbyte);
- read 함수는 fildes로 나타내는 파일 또는 장치에 nbyte 데이터를 사용자 변수 buf로 읽어오려고 시도를 함
- 데이터를 담을 수 있을 만큼 buf 버퍼를 제공, 초기화되지 않은 포인터 buf를 제공하면 안됨
- ssize_t 데이터 타입 : 읽은 바이트 수에 사용되는 서명된 정수형 데이터 타입 / size_t : 읽을 바이트 수에 사용되는 부호 없는 정수형 데이터 타입
Read 함수
- 반환 값 : 읽기 성공 시 (1바이트라도 읽으면) 실제로 읽은 데이터의 크기(바이트 수)를 알려주고, 읽기가 실패하면 -1을 반환하고 왜 실패하였는지 오류 코드(errno)를 설정합니다.
- 특징 : 파일을 읽을 때 요청한 데이터 양보다 적게 읽을 수 있습니다. ex) 파일의 끝에 도달했을 때 요청한 양을 다 채우지 못할 수 있음, 파일을 계속 읽다가 파일의 끝(end-of-file)에 도달하면 더 이상 읽을 게 없다는 뜻으로 0을 반환
파일 디스크립터
- 열린 파일 및 장치를 나타내며 쉘에서 프로그램 실행 시, 3개의 열린 스트림을 시작함
(STDIN_FILENO, STDOUT,FILENO, STDERR_FILENO)
- STDIN_FILENO (표준 입력)
- 키보드 입력을 말하며 오래된 코드는 0으로 표현됨
-STDOUT_FILENO (표준 출력)
- 화면 출력을 말하며 오래된 코드는 1로 표현됨
- STDERR_FILENO (표준 오류 장치)
- 오류 출력을 처리하는 장치를 말하며 오래된 코드는 2로 표현되고 프로그램에서 이 스트림을 닫으면 안됨
Example (예시)
- 아래 코드 세그먼트는 표준 입력으로부터 최대 100바이트를 buf에 읽어옵니다.
char buf[100];
ssize_t bytesread;
bytesread = read(STDIN_FILENO, buf, 100);
다음 코드가 실행되면 어떻게 될까요?
char *buf;
ssize_t bytesread;
bytesread = read(STDIN_FILENO, buf, 100);
- buf에 대한 메모리 공간을 할당하지 않기에 read 함수의 결과가 예측 불가능 (메모리 접근 오류)
다음 코드 세그먼트는 readline 함수를 호출하여 표준 입력으로부터 최대 99바이트의 한 줄을 읽습니다.
int bytesread;
char mybuf[100];
bytesread = readline(STDIN_FILENO, mybuf, sizeof(mybuf));
데이터 복사
- 출발지: 현재 파일 오프셋 위치
- 도착지: 메모리 영역 (프로그램 변수)
- 크기: 지정된 길이
- filedes: 파일을 열 때 사용한 파일 디스크립터
- buffer: 데이터를 저장할 버퍼의 주소
- n: 읽을 데이터의 크기 (바이트 수)
Writing (쓰기)
write 함수
#include <unistd.h>
ssize_t write(int filedes, const void *buf, size_t nbyte);
- write 함수는 파일에 데이터를 쓰는 역할을 하고 사용자가 제공하는 버퍼(buf) 내부에 있는 데이터를 fildes로 지정된 파일에 nbyte만큼 작성, 반환 값은 실제로 바이트가 얼만큼 쓰였는지 나타냄
- filedes: 파일을 가리키는 번호 (파일 디스크립터)
- buf: 파일에 쓸 데이터가 저장된 버퍼
- nbyte: 쓰려고 하는 데이터의 크기 (바이트 단위)
=> 실제로 쓰인 바이트 수가 요청한 바이트 수보다 적을 수 있지만, 이것은 오류가 아닙니다.
- r_read(), r_write()
- 신호를 처리하면서 읽기와 쓰기가 필요한 프로그램을 크게 단순화시킵니다.
- readwrite()
- 하나의 파일 디스크립터에서 바이트를 읽고, 읽은 모든 바이트를 다른 파일 디스크립터로 씁니다 (r_read()와 r_write() 사용).
- 버퍼 크기는 PIPE_BUF로 설정되며, 이는 PIPE_BUF 바이트 이하로 파이프에 쓰는 작업이 원자적이기 때문에 유용합니다.
- copyfile()
- readwrite() 함수를 사용하는 버전입니다.
- 출발지: 메모리 영역 (프로그램 변수)
- 목적지: 현재 파일 오프셋 위치
- 크기: 지정된 길이
- filedes: 파일 디스크립터 (파일을 열 때 받은 값)
- buffer: 데이터를 저장하고 있는 버퍼의 주소
- n: 쓸 데이터의 크기 (바이트 수)
> 프로그램 메모리에 저장된 데이터를 파일에 쓰는 역할을 하며 fildes는 어디에 쓸지(파일)을 나타내고 buffer는 쓸 데이터가 있는 곳, n은 쓸 데이터의 크기를 지정함 / 데이터를 복사할 때, 프로그램 변수의 메모리 영역에서 파일의 현재 위치로 데이터를 옮김
파일 오프셋 (File Offset)
- 현재 I/O 위치
- VCR 헤드의 위치와 같음 (즉, 파일에서 읽거나 쓸 위치를 가리킴)
- 읽기/쓰기 작업은 파일 오프셋이 가리키는 위치에서 수행됨
- 읽기/쓰기 작업이 완료되면 파일 오프셋이 자동으로 이동됨 (다음 읽기/쓰기는 새로운 위치에서 시작됨)
발생할 수 있는 문제:
- write 함수의 가정: write 함수가 buf(버퍼)가 1024 바이트(BLKSIZE)로 가득 차 있다고 가정합니다.
- read 함수의 불완전성: 그러나 read 함수는 1024 바이트 전체를 읽지 못할 수도 있습니다. (예를 들어, 입력이 적을ㄸ때, read가 실패할 수도 있습니다.
- 결과: write는 제대로 채워지지 않은 buf를 그대로 출력하게 되며, 그 결과 쓰레기 데이터가 출력될 수 있습니다.
해결 방법: read 함수가 반환하는 실제 읽은 바이트 수를 확인한 후, 그만큼만 write로 출력하는 것이 안전합니다.
이 코드에서는 read가 성공적으로 데이터를 읽어들인 후, write로 출력하는 구조입니다. 하지만 다음과 같은 문제가 있을 수 있습니다:
- write가 요청한 바이트 모두를 쓰지 않을 수 있음: write 함수가 읽은 바이트 수만큼 출력하려 하지만, 모든 바이트를 출력하지 못할 가능성이 있습니다.
- 신호에 의해 중단될 수 있음: read나 write 함수가 중간에 신호를 받아 실행이 중단되면, -1을 반환하며 EINTR 오류를 설정합니다. 이 경우 코드를 다시 시도하는 처리가 필요할 수 있습니다.
따라서, write가 모든 바이트를 출력했는지 확인하고, 신호 중단 시 복구할 수 있도록 처리하는 것이 중요합니다.
- 파일 복사: 하나의 파일(fromfd)에서 데이터를 읽어 다른 파일(tofd)로 복사합니다.
- 중단 처리: read나 write 작업이 신호로 중단되면, 이를 다시 시도하여 안전하게 복사를 계속합니다.
- 포인터 사용: write 함수에서 buf 대신 bp라는 포인터를 사용하여 데이터를 쓰는 위치를 지정합니다. bp는 buf의 특정 위치를 가리키는 포인터입니다.
Restart read/write after a signal (신호 이후에 읽기 및 쓰기를 재시작)
- r_read(), r_write() : 신호를 처리하면서 읽기와 쓰기가 필요한 프로그램을 크게 단순화시킵니다.
- readwrite() : 하나의 파일 디스크립터에서 바이트를 읽고, 읽은 모든 바이트를 다른 파일 디스크립터로 씁니다. (r_read()와 r_write() 사용), 버퍼 크기는 PIPE_BUF로 설정되며, 이는 PIPE_BUF 바이트 이하로 파이프에 쓰는 작업이 원자적이기 때문에 유용합니다.
- copyfile() : readwrite() 함수를 사용하는 버전입니다.
readblock()
readblock() 함수는 r_read()에서 발생할 수 있는 문제를 해결하기 위해 만들어졌습니다. r_read()는 신호에 의해 중단되면 다시 시도하지만, 경우에 따라 요청한 바이트보다 적은 양의 데이터를 읽을 수 있습니다.
readblock() 함수는 이런 문제를 해결하기 위해:
- 요청한 바이트 수를 모두 읽을 때까지 계속해서 데이터를 읽습니다.
- 오류가 발생하거나 파일 끝에 도달할 때까지 멈추지 않습니다.
반환 값:
- 0: 파일 끝에 도달하여 더 이상 읽을 데이터가 없을 때
- 요청한 바이트 수: 모든 데이터를 성공적으로 읽었을 때
- -1: 오류가 발생했을 때
Opening
open 함수
#include <fcntl.h>
#include <sys/stat.h>
int open(const char *path, int flag); // 기존 파일을 open 할 때 필요
int open(const char *path, int flag, mode_t mode); // 새로운 파일을 open 할 때 필요
- open 함수는 파일을 열거나 새로 생성할 때 사용하는 함수
- 반환값 : 성공하면 파일 디스크립터(양수 값)을 반환하고 실패하면 -1을 반환하여 오류가 발생하였음을 나타냅니다.
- path: 파일 또는 장치의 경로명을 가리킵니다.
- flag: 열려는 파일에 대한 상태 플래그와 접근 모드를 지정합니다.
- 접근 권한 (Access permission): 파일을 생성하는 경우, 접근 권한을 지정하는 세 번째 매개변수를 포함해야 합니다.
Flag
flag 인자는 접근 모드(access mode)와 추가 플래그(additional flags)의 원하는 조합을 비트 OR 연산을 통해 생성합니다
- 접근 모드 (access mode):
- 반드시 하나의 접근 모드를 지정해야 합니다.
- O_RDONLY: 읽기 전용
- O_WRONLY: 쓰기 전용
- O_RDWR: 읽기 및 쓰기
- 추가 플래그 (Additional flags):
- O_APPEND: 쓰기 전에 파일의 끝으로 파일 오프셋이 이동합니다.
- O_TRUNC: 쓰기 위해 열린 일반 파일의 길이를 0으로 잘라냅니다.
- O_CREAT: 파일이 존재하지 않으면 생성합니다. 세 번째 인자를 사용하여 권한을 지정해야 합니다.
- O_EXCL: O_CREAT와 함께 사용되며, 파일이 이미 존재하면 오류를 반환합니다.
- O_NOCTTY: 열린 장치가 제어 터미널이 되는 것을 방지합니다.
질문
- 새로운 파일을 생성할 때, 기존 파일을 덮어쓰지 않으려면 어떤 플래그를 사용해야 할까요?
- O_CREAT | O_EXCL 조합을 사용, 이 조합은 파일이 이미 존재할 경우 오류를 반환합니다.
Permission Mask (권한 마스크)
- 각 파일에는 3가지 클래스 (사용자 or 소유자, 그룹, 다른 모든 사용자)가 연결되어 있음
- 가능한 권한 및 특권은 읽기(r), 쓰기(w), 실행(x) 이렇게 3가지가 존재, 이 권한은 사용자, 그룹, 기타 사용자에게 각각 따로 지정되야 합니다.
- 파일을 O_CREAT 플래그로 열 때, 세 번째 인자로 mode_t 유형의 마스크를 사용하여 파일 권한을 지정해야 합니다.
- 파일 권한은 비트 마스크로 배열되었으며, 특정 비트 위치에 1을 설정하여 권한을 나타냅니다. 이 비트가 1이면 해당 클래스가 해당 권한을 가지고 있음을 의미합니다.
- 권한 마스크의 역사적 배열은 다음과 같습니다: user(사용자), group(그룹), others(기타 사용자) 순서로 권한이 나열되어 있으며, 각각 읽기(r), 쓰기(w), 실행(x) 권한을 가질 수 있습니다.
POSIX symbolic names (POSIX 심볼릭 이름)
- POSIX는 파일 권한 비트에 대응하는 마스크에 대한 심볼릭 이름을 정의, 이러한 이름은 sys/stat.h에 정의되어 있습니다.
int fd; // 파일 디스크립터를 저장할 변수
mode_t fdmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
// 권한 설정: 소유자는 읽기/쓰기 가능, 그룹 및 기타는 읽기만 가능
// info.dat 파일을 읽기/쓰기 모드로 열거나, 파일이 없으면 생성함.
if ((fd = open("info.dat", O_RDWR | O_CREAT, fdmode)) == -1)
perror("failed to open info.dat"); // 파일 열기에 실패하면 오류 메시지 출력
- info.dat라는 이름의 파일을 현재 디렉터리에 만듭니다.
- 만약 info.dat 파일이 이미 존재한다면, 기존 파일을 덮어씁니다.
- 새 파일에 대한 권한 설정:
- 파일 소유자는 읽기와 쓰기가 가능.
- 그룹과 다른 사람들은 읽기만 가능.
Closing
cp 명령어
- cp 명령어를사용하여 파일을 복사할 수 있음 위의 copyfilemain.c는 open은 있지만 close함수를 하지 않고 main 함수에서 반환되면 메모리를 불필요하게 사용하여 메모리를 낭비함으로 open하고 I/O 작업을 하게 되면 반드시 close 함수로 닫아주어야 함
close() 함수
#include <unistd.h>
int close(int filedes);
- 커널에 파일이 더 이상 사용되지 않음을 알려 커널이 해당 파일에 할당된 리소스를 해제할 수 있음
r_close() 함수
- close() 함수와 유사하지만, 신호에 의해 중단될 경우 다시 시작됩니다.
#include <errno.h>
#include <unistd.h>
int r_close(int fd) {
int retval;
while ((retval = close(fd)), retval == -1 && errno == EINTR);
return retval;
}
- 파일 닫기 작업 중 EINTR(Interrupted System Call) 오류가 발생하면,
- close()가 중단되지 않고 재시도하도록 구현된 함수, 정상적으로 닫히면 반환값을 리턴합니다.
lseek
- 파일 오프셋(File Offset)을 명시적으로 지정된 위치로 이동합니다.
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int filedes, off_t offset, int start_flag);
매개변수 설명:
- filedes: 파일 디스크립터
- offset: 이동할 거리 (정수형 숫자 타입) / 파일 위치의 이동방향 ex) 10이면 오른쪽으로 10 바이트 이동
- 음수 값: 왼쪽으로 이동
- 양수 값: 오른쪽으로 이동
- start_flag: 기준점 설정
- SEEK_SET: 파일 시작 위치 기준
- SEEK_CUR: 현재 파일 오프셋 기준
- SEEK_END: 파일 끝 위치 기준
File representation
File descriptors vs. pointers (파일 디스크립터와 포인터의 비교)
- C 프로그램에서 파일은 파일 포인터 또는 파일 디스크립터를 통해 지정됩니다.
File pointers (파일 포인터)
사용 예: fopen, fscanf, fprintf, fread, fwrite, fclose 등
- 이들은 stdio.h 헤더에 정의되어 있습니다. stdin, stdout, stderr [표준 입출력 및 에러] 로 정의
File descriptors (파일 디스크립터) (중점적으로 다룸!)
사용 예: open, read, write, close, ioctl 등
- 이들은 unistd.h 헤더에 정의되어 있습니다. STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO [표준 입출력 및 에러] 로 정의
- 파일 디스크립터 테이블 (User Program Area)
- 사용자 프로그램이 파일을 열면 파일 디스크립터 번호가 할당됨, 프로세스마다 가짐
- 예: myfd = 3은 테이블의 3번 슬롯에 저장됩니다.
- 시스템 파일 테이블 (Kernel Area) , (커널에 있는 테이블, 여러 프로세스가 공유하며 사용하는 테이블)
- 파일 디스크립터가 시스템 파일 테이블의 항목을 가리킵니다.
- 파일에 대한 상태 정보(열림 상태, 읽기/쓰기 모드 등)가 저장됩니다.
- 메모리 상의 inode 테이블 (In-memory inode Table) (커널에 있는 테이블, 여러 프로세스가 공유하며 사용하는 테이블)
- 시스템 파일 테이블의 항목은 해당 파일의 inode 정보와 연결됩니다.
- inode에는 파일 경로, 크기, 권한 등 메타데이터와 실제 위치 정보가 포함됩니다.
=> 파일을 open 하면 3개의 테이블에 entry가 추가되면서 실행됨
File descriptors (파일 디스크립터)
- 파일 디스크립터는 프로세스마다 고유한 파일 디스크립터 테이블의 인덱스
The system file table (시스템 파일 테이블)
- 시스템의 모든 프로세스가 공유
- 열린 파일마다 하나의 항목(entry)이 생성됩니다.
- 각 항목에는 다음 정보가 포함됩니다:
- 파일 오프셋(offset)
- 접근 모드(access mode)
- 파일 디스크립터 테이블 항목의 개수 (파일을 참조 중인 프로세스 수) / 여러 시스템 파일 테이블 항목이 같은 물리적 파일을 가리킬 수 있습니다.
In-memory inode table (메모리 상의 inode 테이블)
- 시스템 파일 테이블 항목이 inode 테이블 항목을 참조합니다.
- 시스템에 열린 모든 파일의 정보가 inode 테이블에 저장됩니다.
Question.
1. 이전 예제에서 프로세스가 close(myfd) 함수를 실행하면?
- OS가 파일 디스크립터 테이블의 네 번째 항목과 해당되는 시스템 파일 테이블의 항목을 삭제합니다.
- OS는 inode 항목의 참조 수를 감소시킵니다.
- 만약 inode의 참조 수가 0이 되면, OS는 메모리에서 inode 항목을 삭제합니다.
2. 두 개의 프로세스가 동일한 파일을 쓰기 모드로 열면?
- 각 프로세스는 별도의 파일 오프셋을 가지므로, 한 사용자가 작성한 내용을 다른 사용자가 덮어쓸 수 있습니다.
3. 파일 오프셋이 inode 테이블에 저장되면 어떻게 될까?
- 모든 프로세스가 동일한 파일 오프셋을 공유하게 됩니다. 이 경우, 여러 프로세스의 쓰기 작업이 순차적으로 이루어집니다.
File pointers (파일 포인터)
- 파일 포인터는 프로세스의 사용자 영역에 있는 FILE 구조체를 가리킵니다.
FILE 구조체
버퍼(buffer)와 파일 디스크립터 값을 포함합니다.
- 왼쪽 코드: 두 프로세스는 파일 디스크립터와 파일 오프셋을 공유하며, 순차적으로 파일을 읽습니다.
- 동작 설명:
- 파일 디스크립터(myfd)가 부모 프로세스에서 먼저 열립니다.
- fork()로 프로세스가 복제되면서 부모와 자식 프로세스는 같은 파일 디스크립터를 공유합니다.
- 공유된 파일 디스크립터를 통해 파일의 파일 오프셋(file offset)도 공유됩니다.
- 두 프로세스가 순차적으로 파일을 읽어 각각 다른 문자(a, b)를 가져옵니다.
- Process nnn got a
- Process mmm got b
- 오른쪽 코드: 각 프로세스가 별도의 파일 디스크립터와 오프셋을 사용하여, 동일한 데이터를 읽습니다.
- 동작 설명:
- fork()로 부모와 자식 프로세스가 복제됩니다.
- 각 프로세스가 독립적으로 파일을 열고(open) 자신의 파일 디스크립터를 생성합니다.
- 따라서 두 프로세스는 서로 다른 파일 오프셋을 사용하여 같은 위치에서 읽습니다.
- Process nnn got a
- Process mmm got a
- 왼쪽 코드:
- 버퍼링이 발생하여 fork() 이후 두 프로세스가 동일한 출력을 두 번 수행합니다.
- 결과: "This is my output.This is my output."
- 오른쪽 코드:
- 줄바꿈(\n)으로 인해 버퍼가 플러시된 후 fork()가 호출되므로 한 번만 출력됩니다.
- 결과: "This is my output."
이 예제는 버퍼링과 프로세스 복제가 출력에 어떤 영향을 미치는지 설명합니다. 줄바꿈(\n)의 유무가 버퍼링에 영향을 주며, fork() 전에 버퍼가 비워지지 않으면 중복 출력이 발생할 수 있습니다.
Filters and Redirection
필터(Filters)
- 정의: 입력(표준 입력) 데이터를 읽어서 처리한 후, 결과를 출력(표준 출력)하는 프로그램.
- 예시 명령어:
- head: 파일의 처음 몇 줄을 출력
- tail: 파일의 마지막 몇 줄을 출력
- sort: 데이터를 정렬
- grep: 특정 단어를 검색
- awk: 데이터 처리 및 변환
- cat 명령어: 입력 파일 없이 사용하면 필터처럼 동작해서 입력을 받아 바로 출력합니다.
예시:
cat | grep "hello"
- 사용자가 입력한 내용 중 "hello"가 포함된 줄만 출력.
리다이렉션(Redirection)
- 정의: 명령어의 입출력 방향을 변경하는 기능.
- 종류:
- >: 출력 리다이렉션 (출력을 파일로 저장)
- 예: ls > output.txt
→ ls의 결과가 output.txt 파일에 저장됨.
- 예: ls > output.txt
- <: 입력 리다이렉션 (파일에서 입력을 읽음)
- 예: cat < input.txt
→ input.txt의 내용을 cat이 출력함.
- 예: cat < input.txt
- >: 출력 리다이렉션 (출력을 파일로 저장)
- 필터: 데이터를 가공해서 출력하는 프로그램 (예: grep, sort).
- 리다이렉션: 명령어의 출력을 파일에 저장하거나 입력을 파일에서 읽음 (>, < 사용)
dup2() 함수란?
- 기능: 기존 파일 디스크립터(oldfd)를 새 디스크립터(newfd)에 복사합니다.
- 동작:
- newfd가 열려 있으면 닫음.
- oldfd의 파일을 newfd로 연결.
예시 흐름:
- 파일 오픈 후:
- [1]: 표준 출력
- [3]: my.file에 쓰기
- dup2(3, 1) 호출 후:
- [1]: my.file로 리다이렉션 (표준 출력이 파일로 연결됨)
- 닫은 후:
- [1]: 여전히 my.file로 쓰기 가능
결과:
- 표준 출력이 **my.file**에 기록됩니다.
- 프로그램에서 printf()로 출력하면 화면 대신 파일에 저장됩니다.
'Computer Science > 시스템 프로그래밍' 카테고리의 다른 글
시스템 프로그래밍 chapter 06. (UNIX 스페셜 파일) (0) | 2024.11.05 |
---|---|
시스템 프로그래밍 chapter 05. (파일과 디렉토리) (1) | 2024.10.29 |
시스템 프로그래밍 chapter 03. (1) | 2024.10.08 |
시스템 프로그래밍 chapter 02. (0) | 2024.10.08 |
시스템 프로그래밍 Chapter 01. (0) | 2024.10.07 |