파일
- 파일은 컴퓨터 등의 기기에서 의미 있는 정보를 담는 논리적인 단위
일반 파일 (Ordinary File)
- 일반 파일은 텍스트 파일, 이진 파일 등을 포함함
- UNIX 계열의 운영체제에서 파일의 확장자는 특별한 의미가 없음
- 파일의 확장자는 파일명의 일부분으로, 해당 파일의 형식을 짐작하는 용도로 쓰일 수 있도록 붙임.
- 운영체제 또는 응용프로그램은 파일명 뒤에 확장자를 붙임으로써, 각 파일의 속성을 구분함.
- 컴파일러 등의 일부 프로그램은 특정 확장자를 구분/요구하기도 함.
- 파일의 입출력은 커널(kernel) 단계에서 버퍼링(buffering) 작업을 함.
- 디스크의 여러 부분에 분리•저장되어 있는 데이터를 하나의 파일로 연결된 것처럼 함
- 파일 내부에 저장되는 데이터의 구조는 운영체제에 의해 제어되는 것이 아닌, 처리하는 프로그램에 따라 제어됨.
디렉토리 (Directory)
- UNIX 계열의 운영체제에서 디렉토리는 파일의 한 종류
- 디렉토리는 파일의 목록을 저장하는 파일
- 디렉토리는 파일을 포함하며, 하위 디렉토리 또한 포함할 수 있음.
- 디렉토리는 일반 파일과는 다른 개념이지만, 읽을 때는 일반 파일과 동일하게 취급함.
- 빈 디렉토리도 . 과 .. 두 파일을 포함하고 있음.
- . 는 디렉토리 자신
- .. 는 상위 디렉토리
파일 접근 프리미티브
파일 접근 프리미티브
- 시스템 호출 (system call)
- 응용 프로그램은 하드웨어에 직접 접근할 수 없음
- 응용프로그램이 하드웨어에 접근할 수 있도록, 커널이 응용프로그램에 제공하는 함수 또는 인터페이스를 시스템 호출 또는 시스템콜이라고 함
- UNIX 계열의 파일 접근 프리미티브
- 입출력 장치에 접근 할 수 있도록 하는 UNIX 계열의 커널에서 제공하는 시스템 호출의 작은 집합
함수 설명 create() 빈 파일을 생성함 open() 파일을 읽거나 쓰기 위해 열거나, 빈 파일을 생성함 close() 열려 있는 파일을 닫음 write() 파일에 내용을 씀 read() 파일의 내용을 읽음 lseek() 파일 내부에 특정 바이트로 이동함
- 입출력 장치에 접근 할 수 있도록 하는 UNIX 계열의 커널에서 제공하는 시스템 호출의 작은 집합
파일 지시자(File descriptor)
- UNIX계열의 파일 접근 프리미티브는 파일 지시자의 개념을 이용
- 파일 지시자는 음이 아닌 정수임
- 단순히 숫자인 이유는 프로세스가 유지하고 있는 FD 테이블의 인덱스이기 때문
- 프로세스가 실행 중인 파일에 접근하고자 하면, 커널은 해당 프로세스의 파일 디스크립터 숫자 중에 사용하지 않는 가장 작은 값을 할당함
- 후에 프로세스가 열려있는 파일에 시스템 호출을 이용하여 접근할 때, 이 값을 이용해 해당 파일을 지칭할 수 있음
creat() 함수
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
int creat(const char *pathname, mode_t mode);
- 설명
- 빈 파일을 생성함
- 유효한 파일이 있는 경우 파일을 열고, 파일 지시자를 반환함
- 인자
- pathname : 파일의 이름 또는 경로
- mode : 파일의 접근 권한
- 파일의 접근 권한을 나타내는 8진수
- 해당 파일이 이미 존재하는 경우 무시됨
- sys/stat.h 헤더파일에 정의된 다음의 플래그를 OR 비트 연산자와 함께 사용할 수 있음
- 반환
- 파일 지시자
- 오류시 -1
open()
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
int opnen(const char *pathname,int flags, [mode_t mode]);
- 설명
- 파일을 읽거나 쓰기 위해 열거나, 빈 파일을 생성하고 파일 지시자를 반환함
- 인자
- pathname : 파일의 이름이나 경로
- flags : 파일의 열기 모드
- 파일의 열기 모드를 나타내는 상수
- fcntl.h 헤더 파일에 정의된 플래그를 OR 비트 연산자와 함께 사용
- mode : 파일의 접근 권한
- flats가 O_CREAT인 경우에만 적용
- 반환
- 파일 지시자
- 오류시 -1
close()
#include <unistd.h>
int close(int fd);
- 설명
- 열려있는 해당 파일을 닫고, 이를 시스템에 알림
- 열려있는 모든 파일은 프로세스가 종료될 때, 자동으로 닫힘
- 인자
- fd : 파일 지시자
- 반환
- 성공 시 0
- 오류시 -1
- 수행 중인 한 프로세스가 동시에 개방할 수 있는 파일의 개수에 제한이 있기 때문에, close() 함수를 사용하는 것을 권장함
open()과 close()함수 예시
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define PERMS 0644
int main() {
int fd = 0;
char *pathname = "./newfile.txt";
fd = open(pathname, O_CREAT | O_RDWR, PERMS);
if (fd == -1) {
perror("open() error");
exit(-1);
}
printf("fd of %s is %d\n", pathname, fd);
close(fd);
return 0;
}
write()
#include <unistd.h>
ssize_t write(int fd, void *buffer,size_t nbyte);
- 설명
- 열려있는 해당 파일에 데이터를 지정한 크기만큼 씀
- 인자
- fd: 파일 지시자
- buffer : 파일에 쓸 데이터의 메모리 공간에 대한 포인터
- nbyte : 파일에 쓸 데이터의 크기
- 반환
- 성공 시 쓰여진 데이터의 크기
- 오류 발생시 -1
- 현재 파일의 위치에 데이터를 쓰고, 읽기-쓰기 포인터(offset)는 마지막으로 쓴 byte의 바로 뒤로 이동
- 파일 open()시에
- O_CREAT 또는 O_RDWD flag 사용
- O_APPEND flag 사용
write() 함수 예시
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define PERMS 0644
int main() {
int fd = 0;
char *pathname = "./mymsg.txt";
fd = open(pathname, O_CREAT | O_TRUNC | O_RDWR, PERMS);
char *msg = "Hello my name is Sohee\n";
ssize_t wsize = 0;
if (fd == -1) {
perror("open() error");
exit(-1);
}
wsize = write(fd, (char *)msg, strlen(msg));
if (wsize == -1) {
perror("write() error");
exit(-2);
}
printf("fd : %d, wsize : %ld\n", fd, wsize);
close(fd);
return 0;
}
read() 함수
#include <unistd.h>
ssize_t read(int fd, void * buffer, ssize_t nbyte);
- 설명
- 열려있는 해당 파일에서 데이터를 지정한 크기만큼 읽고, 이를 메모리 공간에 저장함
- 인자
- fd : 파일 지시자
- buffer : 파일에서 읽은 데이터를 저장할 메모리 공간에 대한 포인터
- nbyte : 파일에서 읽을 데이터의 크기
- 반환
- 성공시 읽은 데이터의 크기
- 파일의 끝을 읽은 경우 0
- 오류시 -1
- 현재 파일의 위치에서 데이터를 읽고, 읽기-쓰기 포인터(offset)는 마지막으로 읽은 byte의 바로 뒤로 이동함.
read() 함수 예시
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define PERMS 0644
#define MAX_SIZE 1024
int main() {
int fd = 0;
char *pathname = "./mymsg.txt";
char buf[MAX_SIZE + 1] = {'\0'};
ssize_t rsize = 0;
ssize_t tsize = 0;
fd = open(pathname, O_RDONLY, PERMS);
if (fd == -1) {
perror("open() error");
exit(-1);
}
do {
memset(buf, '\0', MAX_SIZE + 1);
rsize = read(fd, buf, MAX_SIZE);
if (rsize == -1) {
perror("read() error");
exit(-2);
}
printf("%s", buf);
tsize += rsize;
} while (rsize > 0);
printf("fd : %d, total rsize : %ld, tsize= %ld\n", fd, rsize, tsize);
close(fd);
return 0;
}
write()와 read() 함수 예시
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define PERMS 0644
#define MAX_SIZE 32
struct _User {
char name[MAX_SIZE + 1];
int age;
};
typedef struct _User User;
int main() {
int fd = 0;
char *pathname = "./myname.txt";
ssize_t wsize = 0;
char username[MAX_NAME_SIZE + 1] = {'\0',};
int userage = 0;
User *user = (User *)malloc(sizeof(User));
memset(user->name, '\0', MAX_SIZE + 1);
user->age = 0;
printf("Name : ");
scanf("%[^\n]", username);
strcpy(user->name, username);
printf("Age : ");
scanf("%d", &userage);
user->age = userage;
fd = open(pathname, O_CREAT | O_TRUNC | O_RDWR, PERMS);
if (fd == -1) {
perror("open() error");
exit(-1);
}
wsize = write(fd, (User *)user, sizeof(User));
if (wsize == -1) {
perror("write() error");
exit(-2);
}
printf("fd: %d, wSize: %ld \n", fd, wsize);
close(fd);
free(user);
return 0;
}
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define PERMS 0644
#define MAX_SIZE 32
struct _User {
char name[MAX_SIZE + 1];
int age;
};
typedef struct _User User;
int main() {
int fd = 0;
char *pathname = "./myname.txt";
ssize_t rsize = 0;
ssize_t tsize = 0;
User *user = (User *)malloc(sizeof(User));
memset(user->name, '\0', MAX_SIZE + 1);
user->age = 0;
fd = open(pathname, O_RDONLY, PERMS);
if (fd == -1) {
perror("open() error");
exit(-1);
}
rsize = read(fd, (User *)user, sizeof(User));
if (rsize == -1) {
perror("read() error");
exit(-2);
}
printf("fd: %d, rSize: %ld \n", fd, rsize);
printf("User Name: %s, User Age: %d \n", user->name, user->age);
close(fd);
free(user);
return 0;
}
lseek() 함수
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int flag);
- 설명
- 열려있는 해당 파일에서 읽기-쓰기 포인터(offset)의 위치를 반환
- 인자
- fd : 파일 지시자
- offset : 읽기-쓰기 포인터의 이동 시작 위치에서 이동할 byte의 수
- 0, 음 또는 양의 정수
- 음수인 경우에 시작위치에서 이전으로 이동
- 양수인 경우에 시작 위치에서 이후로 이동
- 0, 음 또는 양의 정수
- flag : 읽기-쓰기 포인터의 이동 시작 위치
- SEEK_SET : 파일의 시작
- SEEK_CUR : 파일의 현재 offset 위치
- SEEK_END : 파일의 끝
- 반환
- 성공시 읽기-쓰기 포인터의 변경된 위치
- 오류시 -1
lseek() 함수 예시
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define PERMS 0644
#define MAX_SIZE 32
int main() {
int fd = 0;
char *pathname = "./mymsg.txt";
ssize_t wsize = 0;
char msg[MAX_SIZE + 1] = "NICE to meet you\n";
fd = open(pathname, O_RDWR);
if (fd == -1) {
perror("open() error");
exit(-1);
}
lseek(fd, (off_t)0, SEEK_END);
wsize = write(fd, (char *)msg, strlen(msg));
if (wsize == -1) {
perror("write() error");
exit(-2);
}
printf("fd: %d, wSize: %ld \n", fd, wsize);
close(fd);
return 0;
}
에러
errno 변수
- 예외가 발생했을 때, 프로스램이 더 많은 정보를 얻을 수 있도록 UNIX계열은 오류코드를 저장한 정수형 변수를 제공
- errno 변수는 전역적으로 접근이 가능한 정수형 변수임
- perror() 서브루틴
- 자신에게 전달된 문자열 인수와 errno변수의 현재 값에 연관된 추가 메시지 등으로 구성된 표준 오류를 화면에 출력
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int fd = 0;
fd = open("./notexist", O_RDWR);
if (fd == -1) {
fprintf(stderr, "error %d\n", errno);
}
return 0;
}
open() 함수의 에러
close() 함수의 에러
write() 함수의 에러
read() 함수의 에러
'시스템 소프트웨어' 카테고리의 다른 글
연결 리스트 (Linked list) (0) | 2023.03.08 |
---|---|
배열과 문자열 (Array and String) (0) | 2023.03.07 |
시그널 (Signal) (0) | 2023.03.07 |
파일과 디렉토리 (File and Directory) (0) | 2023.02.05 |
프로세스 (Process) (0) | 2023.02.05 |