(본 강의 노트는 한빛 아카데미의 <유닉스 시스템 프로그래밍> 책을 기반으로 하고 있습니다)
Ch02. 파일 입출력
학습목표
- 유닉스에서 파일 입출력의 특징을 이해한다.
- 저수준 파일 입출력 함수를 사용할 수 있다
- 고수준 파일 입출력 함수를 사용할 수 있다
- 임시 파일을 생성해 파일 입출력을 할 수 있다
목차
1. 저수준 파일 입출력
2. 고수준 파일 입출력
3. 파일 기술자와 파일 포인터간 변환
4. 임시 파일 사용
01. 저수준 파일 입출력
파일 기술자
- File Descriptor
- 파일을 설명해주는 인자
- 현재 열려있는 파일을 구분하는 정수값
- 저수준 파일 입출력에 열린 파일을 참조하는데 사용
파일 생성과 열고 닫기
- 파일 열기 : open( )
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int oflag [, mode_t mode]);
- path에 지정한 파일을 oflag에 지정한 플래그 값에 따라 열고 파일기술자를 리턴
- oflag 값은 table을 참고
종류 | 기능 |
O_RDONLY | 파일을 읽기 전용으로 연다. |
O_WRONLY | 파일을 쓰기 전용으로 연다. |
O_RDWR | 파일을 읽기와 쓰기가 가능하게 연다. |
O_CREAT | 파일이 없으면 파일을 생성한다 |
O_EXCL | O_CREAT 옵션과 함께 사용할 경우 기존에 없는 파일이면 파일을 생성하지만, 파일이 이미 있으면 파일을 생성하지 않고 오류 메시지를 출력한다. |
O_APPEND | 파일의 맨 끝에 내용을 추가한다. |
O_TRUNC | 파일을 생성할 때 이미 있는 파일이고 쓰기 옵션으로 열었으면 내용을 모두 지우고 파일의 길이를 0으로 변경한다. |
O_NONBLOCK/O_NDELAY | 비블로킹(Non-blocking) 입출력 |
O_SYNC/O_DSYNC | 저장장치에 쓰기가 끝나야 쓰기 동작을 완료 |
- mode : 파일 접근 권한 지정
- 예: 0644 같이 숫자나 플래그 값으로 지정 가능
- mode의 flag 값을 table을 참고
- 파일 생성 : create( )
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *path, mode_t mode);
- 파일 생성 함수로, open함수에 파일 생성 기능이 없던 구버전 유닉스에서 사용
- open함수와 달리 옵션 지정 부분 없음
- creat 함수로 파일 생성 시, 파일 기술자를 리턴하므로 별도로 오픈할 필요 없음
- 파일 닫기 : close()
#include <unistd.h>
int close(int fildes);
- 프로세스에서 열 수 있는 파일 개수가 제한되어 있으므로 파일의 사용이 끝나면 닫아야 함
파일 읽기 : read()
#include <unistd.h> ssize_t read(int fildes, void *buf, size_t nbytes);
- 파일에서 세번째 인자에 바이트 단위로 지정한 크기만큼 바이트를 읽어서 두 번째 인자 buf에 저장
- 실제로 읽어온 바이트 개수를 리턴
- 리턴값이 0이면 파일의 끝에 도달했음을 의미
- 파일의 종류에 상관없이 무조건 바이트 단위로 읽어옴
파일 쓰기 : write()
#include <unistd.h> ssize_t write(int fildes, const void *buf, size_t nbytes);
- 두번째 인자 buf가 가리키는 메모리에서 세번째 인자에 바이트 단위로 지정한 크기만큼 파일에 기록
- 실제로 쓰기를 수행한 바이트 수를 리턴
파일 오프셋 위치 지정 : lseek()
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fildes, off_t offset, int whence);
- offset으로 지정한 크기만큼 오프셋을 이동시킴
- offset의 값은 whence값을 기준으로 해석한다
- SEEK_SET : 파일의 시작 기준
- SEEK_CUR : 현재 위치 기준
- SEEK_END : 파일의 끝 기준
- 파일 오프셋의 현재 위치를 알려면?
- cur_offset = lseek(fd,0,SEEK_CUR);
파일 기술자 복사 : dup()
#include <unistd.h>
int dup(int fildes);
기존 파일 기술자를 인자로 받아 새로운 파일 기술자를 리턴
새로운 파일 기술자는 현재 할당할 수 있는 파일 기술자 중 가장 작은 값으로 자동 할당
dup2(3) : 새로운 파일 기술자를 지정할 수 있음
#include <unistd.h> int dup2(int fildes, int fildes2);
파일 기술자 제어 : fcntl()
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fildes, int cmd, /* arg */ ...);
- 파일 기술자가 가리키는 파일에 cmd로 지정한 명령을 수행
- cmd의 종류에 따라 인자를 지정할 수 있음
- 자주 사용하는 cmd
- F_GETFL : 상태 플래그 정보를 읽어온다
- F_SETFL : 상태 플래그 정보를 설정한다
파일 삭제
unlink()
#include <unistd.h> int unlink(const char *path);
- path에 지정한 파일의 inode에서 링크 수를 감소시킨다
- 링크 수가 0이되면 path에 지정한 파일이 삭제된다
- 파일 뿐만 아니라 디렉토리도 삭제된다
remove()
#include <stdio.h> int remove(const char *path);
- Path에 지정한 파일이나 디렉토리를 삭제한다
- 디렉토리인 경우 빈 디렉토리만 삭제한다
02. 고수준 파일 입출력
파일 포인터
- 고수준 파일 입출력 : 표준 입출력 라이브러리
- 파일 포인터
- 고수준 파일 입출력에서 열린 파일을 가리키는 포인터
- 자료형으로 FILE *형을 사용 : 구조체에 대한 포인터
파일 열기와 닫기
- 파일 열기 : fopen()
#include <stdio.h> FILE *fopen(const char *filename, const char *mode);
- filename으로 지정한 파일의 모드로 지정한 모드에 따라 열고 파일 포인터를 리턴
- 모드 값 테이블 참조
- 파일 닫기 : fclos()
#include <stdio.h> int fclose(FILE *stream);
- 문자열 기반 입출력 함수
- 문자, 문자열 기반 입력 함수
#include <stdio.h> int fgetc(FILE *stream); int getc(FILE *stream); int getchar(void); int getw(FILE *stream); char *gets(char *s); char *fgets(char *s, int n, FILE *stream);
- fgetc() : 문자 한개를 unsigned char 형태로 읽어온다
- getc(), getchar(): 매크로
- getw(): 워드 단위로 읽어온다
- gets() : 표준 입력에서 문자열을 읽어들인다
- fgets() : 파일(스트림)에서 n보다 하나 적게 문자열을 읽어 s에 저장
- 문자, 문자열 기반 출력 함수
#include <stdio.h> int fputc(int c, *stream); int putc(int c, *stream); int putchar(int c); int putw(int w, FILE *stream); char *puts(const char *s); char *fputs(const char *s, FILE *stream);
- fputc(): 문자 한개를 unsigned char 형태로 파일에 쓴다
- putc(), putchar(): 매크로
- putw(): 워드 단위로 파일에 쓴다
- puts(): 표준 입력에서 문자열을 파일에 쓴다
- fputs(): 파일(스트림)에 s에 저장된 문자열을 쓴다
버퍼 기반 입출력
버퍼 기반 입력 함수
#include <stdio.h> size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
- fread(): size만큼의 데이터를 nitems에 지정한 개수만큼 읽어 ptr에 저장
- 성공 시 읽어온 항목 수를 리턴, 읽을 항목이 없으면 0을 리턴
버퍼 기반 출력 함수
#include <stdio.h> size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);
- fwrite(): size만큼의 데이터를 nitems에 지정한 개수만큼 ptr에서 읽어서 스트림으로 지정한 파일에 출력
- 성공 시 출력한 항목의 수를 리턴, 오류 발생 시 EOF 리턴
형식 기반 입출력
형식 기반 입력 함수
#include <stdio.h> int scanf(const char *restrict format, ...); int fscanf(FILE *restrict stream, const char *restrict format, ..);
- scanf(), fscanf()
- 두 함수 모두 형식 지정 방법 동일
- 성공시 읽어온 항목의 개수 리턴
- scanf(), fscanf()
형식 기반 출력 함수
#include <stdio.h> int printf(const char *restrict format, /* args */ ...); int fprintf(FILE *restrict stream, const char *restrict format, /*args */ ..)/
- printf(), fprintf()
- fprintf는 지정한 파일로 형식 지정방법을 사용하여 출력
- printf(), fprintf()
파일 오프셋 지정
파일 오프셋 이동
#include <stdio.h> int fseek(FILE *stream, long offset, int whence);
- fseek()
- 스트림이 가리키는 파일에서 오프셋에 지정한 크기만큼 오프셋을 이동
- 성공시 0, 실패시 EOF 리턴
- fseek()
현재 오프셋 구하기
#include <stdio.h> long ftell(FILE *stream);
- ftell()
- 현재 오프셋을 리턴, 오프셋은 현재 위치까지의 바이트 수
- ftell()
3. 파일 기술자와 파일 포인터간의 변화
: 저수준 파일 입출력의 파일기술자와 고수준 파일 입출력의 파일 포인터는 상호 변환 가능
- 파일 포인터 생성 : fdopen()
#include <stdio.h> FILE *fdopen(int fildes, const char *mode);
- 파일 기술자와 모드값을 받아 파일 포인터를 생성
파일 기술자 생성 : fileno()
#include <stdio.h> int fileno(FILE *stream);
- 파일 포인터를 인자로 받아 파일 기술자를 리턴
임시 파일 사용
: 임시파일명이 중복되지 않도록 임시 파일명 생성
임시 파일명 생성 : tmpnam()
#include <stdio.h> char *tmpnam(char *s);
- 임시 파일명을 시스템이 알아서 생성
접두어 지정: tempnam()
#include <stdio.h> char *tempnam(const char *dir, const char *pfx);
- 임시파일명에 사용할 디렉토리와 접두어 지정
템플릿을 지정한 임시 파일명 생 : mktemp(3)
#include <stdlib.h> char *mktemp(char *template);
- 임시 파일의 템플릿을 받아 임시 파일명을 생성
- 템플릿은 XXXXXX로 끝나야 함
- /tmp/hanbitXXXXXX임시파일의 파일 포인터 생성
: 자동으로 w+ 모드로 열린 파일 포인터를 리턴
#include <stdio.h>
FILE *tmpfile();
Summary
- 파일
- 파일은 관련있는 데이터들의 집합으로 하드디스크 같은 저장장치에 일정한 형태로 저장된다
- 유닉스에서 파일은 데이터를 저장하기 위해서 뿐만 아니라 데이터를 전송하거나 장치에 접근하기 위해서도 사용한다
- 저수준 파일 입출력과 고수준 파일 입출력
- 저수준 파일 입출력 : 유닉스 커널의 시스템 호출을 사용하여 파일 입출력을 실행하며, 특수 파일도 읽고 쓸 수 있다.
- 고수준 파일 입출력 : 표준 입출력 라이브러리로 다양한 형태의 파일 입출력 함수를 제공한다.
'Computer Science > 유닉스프로그래밍' 카테고리의 다른 글
[유닉스 이론과 실습] ch13. 배시쉘 프로그래밍 (0) | 2020.10.18 |
---|---|
[유닉스 이론과 실습] ch04. vi 사용법 익히기 (0) | 2020.10.18 |
Introduction UNIX (0) | 2020.10.18 |
[유닉스 이론과 실습] ch05. 배시쉘 활용하기 (0) | 2020.09.23 |
[유닉스 시스템 프로그래밍] Ch01. 유닉스 시스템 프로그래밍 개요 (0) | 2020.09.11 |