Computer Science/유닉스프로그래밍

[유닉스 시스템 프로그래밍] Ch02. 파일 입출력

계속지나가기 2020. 9. 27. 21:18
반응형

(본 강의 노트는 한빛 아카데미의 <유닉스 시스템 프로그래밍> 책을 기반으로 하고 있습니다)

Ch02. 파일 입출력

학습목표

  • 유닉스에서 파일 입출력의 특징을 이해한다.
  • 저수준 파일 입출력 함수를 사용할 수 있다
  • 고수준 파일 입출력 함수를 사용할 수 있다
  • 임시 파일을 생성해 파일 입출력을 할 수 있다

목차

1. 저수준 파일 입출력

2. 고수준 파일 입출력

3. 파일 기술자와 파일 포인터간 변환

4. 임시 파일 사용

01. 저수준 파일 입출력

파일 기술자

  • File Descriptor
  • 파일을 설명해주는 인자
  • 현재 열려있는 파일을 구분하는 정수값
  • 저수준 파일 입출력에 열린 파일을 참조하는데 사용

파일 생성과 열고 닫기

  1. 파일 열기 : 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을 참고

  1. 파일 생성 : create( )
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *path, mode_t mode);
  • 파일 생성 함수로, open함수에 파일 생성 기능이 없던 구버전 유닉스에서 사용
  • open함수와 달리 옵션 지정 부분 없음
  • creat 함수로 파일 생성 시, 파일 기술자를 리턴하므로 별도로 오픈할 필요 없음
  1. 파일 닫기 : close()
#include <unistd.h>
int close(int fildes);
  • 프로세스에서 열 수 있는 파일 개수가 제한되어 있으므로 파일의 사용이 끝나면 닫아야 함
  1. 파일 읽기 : read()

    #include <unistd.h>
    ssize_t read(int fildes, void *buf, size_t nbytes);
  • 파일에서 세번째 인자에 바이트 단위로 지정한 크기만큼 바이트를 읽어서 두 번째 인자 buf에 저장
  • 실제로 읽어온 바이트 개수를 리턴
  • 리턴값이 0이면 파일의 끝에 도달했음을 의미
  • 파일의 종류에 상관없이 무조건 바이트 단위로 읽어옴
  1. 파일 쓰기 : 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값을 기준으로 해석한다
    1. SEEK_SET : 파일의 시작 기준
    2. SEEK_CUR : 현재 위치 기준
    3. 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 : 상태 플래그 정보를 설정한다

파일 삭제

  1. unlink()

    #include <unistd.h>
    int unlink(const char *path);
  • path에 지정한 파일의 inode에서 링크 수를 감소시킨다
  • 링크 수가 0이되면 path에 지정한 파일이 삭제된다
  • 파일 뿐만 아니라 디렉토리도 삭제된다
  1. remove()

    #include <stdio.h>
    int remove(const char *path);
  • Path에 지정한 파일이나 디렉토리를 삭제한다
  • 디렉토리인 경우 빈 디렉토리만 삭제한다

02. 고수준 파일 입출력

파일 포인터

  1. 고수준 파일 입출력 : 표준 입출력 라이브러리
  2. 파일 포인터
    • 고수준 파일 입출력에서 열린 파일을 가리키는 포인터
    • 자료형으로 FILE *형을 사용 : 구조체에 대한 포인터

파일 열기와 닫기

  1. 파일 열기 : fopen()
    #include <stdio.h>
    FILE *fopen(const char *filename, const char *mode);
  • filename으로 지정한 파일의 모드로 지정한 모드에 따라 열고 파일 포인터를 리턴
  • 모드 값 테이블 참조

  1. 파일 닫기 : fclos()
    #include <stdio.h>
    int fclose(FILE *stream);
  • 문자열 기반 입출력 함수
  1. 문자, 문자열 기반 입력 함수
    #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에 저장
  2. 문자, 문자열 기반 출력 함수
    #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에 저장된 문자열을 쓴다

버퍼 기반 입출력

  1. 버퍼 기반 입력 함수

    #include <stdio.h>
    size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
    • fread(): size만큼의 데이터를 nitems에 지정한 개수만큼 읽어 ptr에 저장
    • 성공 시 읽어온 항목 수를 리턴, 읽을 항목이 없으면 0을 리턴
  2. 버퍼 기반 출력 함수

    #include <stdio.h>
    size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);
    • fwrite(): size만큼의 데이터를 nitems에 지정한 개수만큼 ptr에서 읽어서 스트림으로 지정한 파일에 출력
    • 성공 시 출력한 항목의 수를 리턴, 오류 발생 시 EOF 리턴

형식 기반 입출력

  1. 형식 기반 입력 함수

    #include <stdio.h>
    int scanf(const char *restrict format, ...);
    int fscanf(FILE *restrict stream, const char *restrict format, ..);
    • scanf(), fscanf()
      • 두 함수 모두 형식 지정 방법 동일
      • 성공시 읽어온 항목의 개수 리턴
  2. 형식 기반 출력 함수

    #include <stdio.h>
    int printf(const char *restrict format, /* args */ ...);
    int fprintf(FILE *restrict stream, const char *restrict format, /*args */ ..)/
    • printf(), fprintf()
      • fprintf는 지정한 파일로 형식 지정방법을 사용하여 출력

파일 오프셋 지정

  1. 파일 오프셋 이동

    #include <stdio.h>
    int fseek(FILE *stream, long offset, int whence);
    • fseek()
      • 스트림이 가리키는 파일에서 오프셋에 지정한 크기만큼 오프셋을 이동
      • 성공시 0, 실패시 EOF 리턴
  2. 현재 오프셋 구하기

    #include <stdio.h>
    long ftell(FILE *stream);
    • ftell()
      • 현재 오프셋을 리턴, 오프셋은 현재 위치까지의 바이트 수

3. 파일 기술자와 파일 포인터간의 변화

: 저수준 파일 입출력의 파일기술자와 고수준 파일 입출력의 파일 포인터는 상호 변환 가능

  1. 파일 포인터 생성 : fdopen()
    #include <stdio.h>
    FILE *fdopen(int fildes, const char *mode);
  • 파일 기술자와 모드값을 받아 파일 포인터를 생성
  1. 파일 기술자 생성 : fileno()

    #include <stdio.h>
    int fileno(FILE *stream);
    
  • 파일 포인터를 인자로 받아 파일 기술자를 리턴

임시 파일 사용

: 임시파일명이 중복되지 않도록 임시 파일명 생성

  1. 임시 파일명 생성 : tmpnam()

    #include <stdio.h>
    char *tmpnam(char *s);
    
  • 임시 파일명을 시스템이 알아서 생성
  1. 접두어 지정: tempnam()

    #include <stdio.h>
    char *tempnam(const char *dir, const char *pfx);
    
  • 임시파일명에 사용할 디렉토리와 접두어 지정
  1. 템플릿을 지정한 임시 파일명 생 : mktemp(3)

    #include <stdlib.h>
    char *mktemp(char *template);
  • 임시 파일의 템플릿을 받아 임시 파일명을 생성
  • 템플릿은 XXXXXX로 끝나야 함
    • /tmp/hanbitXXXXXX임시파일의 파일 포인터 생성

: 자동으로 w+ 모드로 열린 파일 포인터를 리턴

#include <stdio.h>
FILE *tmpfile();

Summary

  1. 파일
  • 파일은 관련있는 데이터들의 집합으로 하드디스크 같은 저장장치에 일정한 형태로 저장된다
  • 유닉스에서 파일은 데이터를 저장하기 위해서 뿐만 아니라 데이터를 전송하거나 장치에 접근하기 위해서도 사용한다
  1. 저수준 파일 입출력과 고수준 파일 입출력
  • 저수준 파일 입출력 : 유닉스 커널의 시스템 호출을 사용하여 파일 입출력을 실행하며, 특수 파일도 읽고 쓸 수 있다.
  • 고수준 파일 입출력 : 표준 입출력 라이브러리로 다양한 형태의 파일 입출력 함수를 제공한다.

반응형