본문 바로가기
컴퓨터 기초/운영체제 실습

[운영체제 실습] 4.에러처리 및 파일 다루기(low level)

by 인생여희 2020. 6. 23.

1.파일 접근함수

 

예제

#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
extern int errno;
//access() 함수는 프로세스가 지정한 파일이 존재하는지, 읽거나 쓰거나 실행이 가능한 지를 확인하는 함수
int main(void) {
//존재하는 파일 : 0 리턴
int resultNum = access("unix.txt", F_OK);
printf("resultNum : %d \n" , resultNum);
//존재하지 않는 파일 : -1 리턴
int resultNum2 = access("uuuunix.txt", F_OK);
printf("resultNum2 : %d \n" , resultNum2);
if (access("unix.txt", F_OK) == -1) {
printf("errno=%d\n", errno);
exit(1);
}
return 0;
}
view raw ex1_1.c hosted with ❤ by GitHub

결과

unix.txt는 ex1_1파일과 같은 경로에 존재한다.

 

 

2.파일 열기 함수

 

예제

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
extern int errno;
// fopen (path,mode) 함수는 지정한 파일을 열고, 이에 해당하는 스트림의 FILE 객체를 가리키는 포인터를 반환한다.
// 이 때, 이 스트림에서 어떠한 입출력 작업이 가능한지는 mode 인자에 의해 결정된다.
int main(void) {
//파일 포인터
FILE *fp , *fp2;
//존재하는 파일 : 파일 포인터 위치(주소)가 반환됨
fp = fopen("unix.txt", "r");
printf("fp : %p \n" , fp); // fp : 00007FFD8BEDFA90
//존재하지 않는 파일
fp2 = fopen("uuuuunix.txt", "r");
printf("fp2 : %p \n" , fp2); //fp2 : 0000000000000000
if ((fp = fopen("unix.txt", "r")) == NULL) {
printf("errno=%d\n", errno);
exit(1);
}
//파일 닫기
fclose(fp);
return 0;
}
view raw ex1_2.c hosted with ❤ by GitHub

결과

 

 

3.오류 다루기

 

예제

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
extern int errno;
int main(void) {
char *err;
if (access("uuunix.txt", R_OK) == -1) {
//오류 메세지 문자열을 가리키는 포인터를 얻어온다.
//errno 의 값을 통해 발생하였던 오류에 알맞은 오류 메세지를 가리키는 포인터를 리턴한다.
//리턴값 : 오류 번호에 해당하는 오류 문자열을 가리키는 포인터
err = strerror(errno);
printf("오류: %s (uuunix.txt)\n", err);
//오류: No such file or directory(unix.txt)
exit(1);
}
return 0;
}
view raw ex1_5.c hosted with ❤ by GitHub

결과

경로에 파일이 존재하지 않을때 에러를 처리할 수 있다.

 

 

4.커멘드 인자 다루기

 

예제

#include <stdio.h>
int main(int argc, char *argv[]) {
int n;
//커멘드 라인에서 받은 인자 개수
printf("argc = %d\n", argc);
//인자 내용 출력
for (n = 0; n < argc; n++)
printf("argv[%d] = %s\n", n, argv[n]);
return 0;
}
view raw ex1_6.c hosted with ❤ by GitHub

결과

 

 

5.파일 디스크립터 및 파일 열기 시스템콜

 

예제

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
//파일 디스크립터 : 0 ~ 2번까지는 표준입출력 및 에러
int fd;
//mode_t mode;
//mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
// fd = open("unix.txt", O_CREAT, mode);
fd = open("unix.txt", O_CREAT); //unix.txt 라는 0byte 파일이 생성됨
printf("fd : %d \n " , fd); // fd: 3
//fd가 -1이면 에러..
if (fd == -1) {
perror("Creat error");
exit(1);
}
//파일 디스크립터 닫아주기
close(fd);
return 0;
}
view raw ex2_1.c hosted with ❤ by GitHub

결과

 

 

6.파일 열기 및 파일 열기 모드, 권한

 

예제

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int fd;
//O_EXCL : O_CREAT 를 이용해서 파일을 생성하고자 할때, 이미 파일이 존재한다면,
// 에러를 되돌려주며 파일을 생성하는데 실패한다
//0644는 0400, 0200, 040, 04를 더한 값이므로
//특정 파일에 대한 권한이 0644라는 의미는 이 파일에 대한 소유자는
// 읽기와 쓰기, 그룹과 기타 사용자는 읽기 권한이 있음을 의미한다
fd = open("unix3.txt", O_CREAT | O_EXCL, 0644);
printf("fd : %d \n " , fd);
// 이미 파일이 존재할때 오류 fd: -1
// 파일이 존재하지 않을 경우 fd: 3
if (fd == -1) {
perror("Excl");
//파일이 이미 존재한다면 Excl: File exists 에러를 뱉는다.
exit(1);
}
//파일 디스크립터 닫기
close(fd);
return 0;
}
view raw ex2_2.c hosted with ❤ by GitHub

결과

 

 

 

7.파일 디스크립터에 관하여

 

예제 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int fd;
//0번의 파일 디스크립터를 닫는다.
close(0);
//파일디스크럽터 0을 닫았기 때문에, 그다음 파일디스크럽터는 0이된다.
fd = open("unix2.txt", O_RDWR);
printf("fd : %d \n " , fd);
//fd : 0
if (fd == -1) {
perror("Excl");
exit(1);
}
printf("unix2.txt : fd = %d\n", fd);
//unix2.txt : fd = 0
//파일 디스크립터 닫기
close(fd);
return 0;
}
view raw ex2_3.c hosted with ❤ by GitHub

결과

 

 

8.파일 읽기(시스템콜)

 

예제

#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int fd, n;
char buf[10]; //10byte
//unix2.txt 파일을 읽기 전용으로 연다.
fd = open("unix2.txt", O_RDONLY);
if (fd == -1) {
perror("Open");
exit(1);
}
printf("sizeof(buf) : %d\n", sizeof(buf)); //10
//참고 컴파일러에 따라서 포멧을 unsigned long 포멧인 %lu로 작성해줘야 할 수도 있다.
//파일을 읽는다. 리턴값으로 읽은 파일의 바이트 수를 리턴한다.
//fd 가 가르키는 파일에서 10바이트 읽고, buf에 결과를 담는다.
n = read(fd, buf, sizeof(buf));
// 파일의 끝에 도달했다면 0, 파일 읽다가 오류가 발생하면 -1 이 리턴된다.
if (n == -1) {
perror("Read");
exit(1);
}
//파일에서 읽은 바이트 수
printf("n : %d\n", n); // n : 4
buf[n] = '\0';
int bufsize = sizeof(buf); //char 배열 사이즈 : 10
//buf에 들어있는 값 1바이트씩 출력하기
for(int i = 0 ; i < bufsize; i++){
printf("buf[%d] = %c \n" , i , buf[i]);
}
/*
buf[0] = 1
buf[1] = 2
buf[2] = 3
buf[3] = 4
buf[4] =
buf[5] =
buf[6] =
buf[7] =
buf[8] = :
buf[9] =
*/
printf("n=%d, buf=%s\n", n, buf); // n = 4, buf = 1234
//파일 디스크립터 닫기
close(fd);
return 0;
}
view raw ex2_4.c hosted with ❤ by GitHub

결과

 

 

9.파일 읽고 쓰기 (시스템콜)

 

예제

#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
//파일 읽기 디스크립터, 파일 쓰기 디스크립터
int rfd, wfd, n;
//읽은 파일 내용을 저장할 버퍼
char buf[10];
//읽기 전용을 위한 파일 디스크립터 + (읽을 파일 경로, 모드)
rfd = open("unix.txt", O_RDONLY);
if(rfd == -1) {
perror("Open unix.txt");
exit(1);
}
//쓰기를 위한 파일 디스크립터 (쓸파일경로 , 쓰기 모드 , 쓰기 권한)
wfd = open("myunix.txt", O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (wfd == -1) {
perror("Open unix.bak");
exit(1);
}
//read 함수의 리턴값은 읽은 바이트 수이다.
//즉, 읽은 값이 있으면 write 함수로 지정된 파일 디스크립터에 쓴다
while ((n = read(rfd, buf, 6)) > 0)
//읽은 바이트 수와 쓴 바이트 수가 다르면 error
if (write(wfd, buf, n) != n) perror("Write");
if (n == -1) perror("Read");
//읽기 파일 디스크립터와 쓰기 파일 디스크립터를 닫는다.
close(rfd);
close(wfd);
return 0;
}
view raw ex2_5.c hosted with ❤ by GitHub

 

결과

unix2.txt에는 1234라는 데이터가 있다. 그 데이터를 읽어서 myunix.txt에 썼다.

 

 

10.파일 오프셋(시스템 콜)

 

예제

#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int fd, n;
off_t start, cur;
char buf[256];
fd = open("unix2.txt", O_RDONLY); //내용 : 1234
if (fd == -1) {
perror("Open unix.txt");
exit(1);
}
//lseek (파일디스크립터, 0, 현재위치모드)
start = lseek(fd, 0, SEEK_CUR);
//read 함수를 사용해서 한번에 255바이트씩 읽고 buf에 담는다.
n = read(fd, buf, 255);
//버퍼의 끝에 0 을 넣어준다.
buf[n] = '\0';
printf("Offset start=%d, readed string= %s, readed byte =%d\n", (int)start, buf, n);
//Offset 시작=0, 읽은문자= 1234, 읽은바이트 수 =4
//파일을 읽고, 현재 읽은 파일의 offset 구하기
cur = lseek(fd, 0, SEEK_CUR);
printf("Offset curent=%d\n", (int)cur);
printf("file offset setting! \n");
//fileOffset 다시 셋팅 : 파일의 5번째 위치를 가리킨다. SEEK_SET
start = lseek(fd, 5, SEEK_SET);
//read 함수를 사용해서 한번에 255바이트씩 읽고 buf에 담는다.
n = read(fd, buf, 255);
buf[n] = '\0';
printf("Offset start=%d, readed string=%s\n", (int)start, buf);
//파일 디스크립터 닫기
close(fd);
return 0;
}
view raw ex2_6.c hosted with ❤ by GitHub

 

결과

 

 

11.파일 디스크립터 복사

 

예제

#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
//다시 체크하기!
int main(void) {
int fd, fd1;
fd = open("tmp.bbb", O_CREAT | O_WRONLY | O_TRUNC, 0644);
printf("fd : %d \n" , fd);
if (fd == -1) {
perror("Create tmp.bbb");
exit(1);
}
//close(1);
//입력인자로 열린 파일 디스크립터를 전달한다.
//dup 는 물리적 파일을 연 새로운 파일 디스크립터 반환.
//fd, fd1은 커널의 같은 파일 테이블 엔트리를 참조한다.
//두 개의 파일 디스크립터로 작업할때 파일의 오프셋은 동일하다.
fd1 = dup(fd);
printf("fd1 : %d \n" , fd1);
printf("DUP FD=%d\n", fd1);
printf("Standard Output Redirection\n");
close(fd);
return 0;
}
view raw ex2_7.c hosted with ❤ by GitHub

 

결과

 

 

12.파일디스크립터 특성 설정하기

 

예제

#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
/*
첫번째 인자 fd 는 open(2), socket(2) 등의 시스템 호출을 통해서 만들어진 파일 지정자이다.
두번째 인자는 fd 에 대한 특성을 제어하기위한 값이다.
*/
int main(void) {
int fd, flags;
fd = open("unix.txt", O_RDWR);
if (fd == -1) {
perror("open");
exit(1);
}
//F_GETFL - 파일지정자에 대한 플래그값 - open(2) 호출시 지정한 플래그를 되돌려준다.
if ((flags = fcntl(fd, F_GETFL)) == -1) {
perror("fcntl");
exit(1);
}
printf("flags : %d \n" , flags);
flags |= O_APPEND;
/*
arg 에 지정된 값으로 파일지정자 fd 의 플래그를 재 설정한다.
현재는 단지 O_APPEND, O_NONBLOCK, O_ASYNC 만을 설정할수 있다.
다른 플래그들 (O_WRONLY 와 같은) 은 영향을 받지 않는다.
*/
if (fcntl(fd, F_SETFL, flags) == -1) {
perror("fcntl");
exit(1);
}
//파일 쓰기
if (write(fd, "Hanbit Media", 12) != 12) perror("write");
//파일 디스크립터 닫기
close(fd);
return 0;
}
view raw ex2_9.c hosted with ❤ by GitHub

결과

uinix.txt 파일에 hanbit media 가 출력되었다.

 

 

13.파일 삭제

 

예제

 

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int cnt;
//파일 삭제 (삭제할 파일이 위치한 경로)
cnt = unlink("tmp.aaa");
//리턴 값이 -1 이면 error
if (cnt == -1) {
perror("Unlink tmp.aaa");
exit(1);
}
printf("Unlink tmp.aaa success!!!\n");
return 0;
}
view raw ex2_10.c hosted with ❤ by GitHub

결과

파일이 삭제되고, Unlink tmp.aaa success!!! 출력이 된다.

 

 

 

예제파일

send.zip
0.01MB

 

 

 

 

참고 : 유닉스시스템 프로그래밍(한빛미디어)