리눅스에서의 파일 다루기 - whdlgp/system_programming_pra GitHub Wiki
리눅스에서 파일시스템
리눅스는 사실상 거의 모든 부분을 파일로 해결한다. 예를들어 파일을 열고, 쓰고, 읽고, 닫는 작업으로 소켓통신도 하고 시리얼 포트간 통신도 하고 그런다. 리눅스에서 파일을 다룬다는건 사실상 시스템 하나를 다룰 줄 안다는 것과 비슷하지 않을까(적어도 나는 그렇게 생각).
리눅스 프로그래밍을 공부하면서 느낀 변태같은 점 중 하나는 요상한 fork라는 멀티 프로세스 방식이었고, 그 다음으로 요상한 하나는 파일 시스템을 다루는 방법론이었다. 참 파일가져다 별걸 다한다 ㅡㅡ;
물론 기본 파일시스템 함수로 다 하기에는 상당한 노가다성을 필요로 하기 때문에, 다른 라이브러리를 활용해 쓰기는 한다.
이후 문서는 다음 사이트를 참조하고 있다.
Falinux Forum
파일 디스크립터
작성한 프로그램 내에서 파일을 다루는 법 또한 C 표준 함수와 약간 다른 모양새를 보였는데, 그 부분이 바로 파일 디스크립터다.
앞서 리눅스 시스템에서는 왠만한 부분은 파일마냥 읽고 써서 처리한다고 말했다. 때문에 단순히 파일 이름으로 읽고 쓰기에는 다소 불편하거나 힘든 점이 있다. 때문에 리눅스에서는 파일 디스크립터터 라는 개념을 쓰는데, 쉽게 말해 사용할 파일에 숫자를 붙인거다.
파일 디스크립터는 프로세스마다 다르다. 프로세스마다 별개라고 말하는게 맞는것 같다.
- __같은 파일__이라도 파일 디스크립터는 프로세스가 다르면 __서로 다른 값__을 가질 수 있다.
- __다른 파일__이라도 파일 디스크립터는 프로세스가 다르면 __서로 같은 값__을 가질 수 있다.
파일 디스크립터를 사용하는 한가지 예를 들면
- 파일 "data.txt"을 열면서, 파일 디스크립터 값 4를 붙였다.
- 이 파일에 값을 쓸 때는 파일 디스크립터 4 에 쓴다.
별명같은거다.
또한, 파일 디스크립터 값이 미리 정해져있는 것이 있는데, 다음 3가지는 서로다른 프로세스라도 다 같은 값이다.
- 0 : 표준 입력(stdin)
- 1 : 표준 출력(stdout)
- 2 : 표준 오류(stderr)
때문에 파일을 열어도 파일 디스크립터는 3번부터 시작한다.
open
(옵션 한번 더럽게 많내;)
open(파일 이름, 옵션,,,)
성공시 리턴값은 파일 디스크립터 값이며 실패시 -1을 준다.
사용은 다음과 같이 사용하면 된다.
int fd;
fd = open("data.txt", O_RDWR);
보기에는 엄청 심플해 보이는데, 사용법은 솔직히 좀 짜증난다(원래 파일 다루는 함수가 짜증나긴 하는데 ,,,). 옵션을 별걸 다 만들어놨다.
읽기, 쓰기 권한 옵션
O_RDONLY
- 읽기 전용으로 열기
O_WRONLY
- 쓰기 전용으로 열기
O_RDWR
- 읽기/쓰기 모두 가능으로 열기
상세 옵션
O_CREAT
- 파일이 있으면 싹다 지우고 열기
- 파일이 없으면 생성하고 열기
- 생성시 필요한 접근권한을 같이 적어줘야함.
(ex: fd = open("data.txt", O_RDWR|O_CREAT, 0644))
O_EXCL
- O_CREAT 와 같이 사용
(ex: fd = open("data.txt", O_RDWR|O_CREAT|O_EXCL, 0644)) - 파일이 있으면 지우지 않고 에러반환
O_TRUNC
- 파일이 있으면 싹다 지우고 열기
- 파일이 없으면 에러반환
O_APPEND
- 파일을 열면서 읽기/쓰기 위치를 맨 끝으로 하여 열기(추가모드)
- 파일에 쓰기를 할 경우 맨 끝부터 시작하여 쓰기 동작수행
그 외의 다른 옵션들도 있지만, 나는 더 많은 옵션을 지금 사용하진 않을 것이기에,,, 여기까지 작성해둔다.
read
read(파일 디스크립터, 저장할 버퍼 포인터, 저장할 버퍼 길이);
반환값으로 읽기 성공시 읽어드린 바이트 수, 실패시 -1을 반환한다.
read는 그래도 좀 간단하다. 만약 읽어드린 값을 저장할 버퍼가 buffer이고 길이 1024 라면,
ssize_t nread;
char buffer[1024];
nread = read(fd, buffer, 1024);
이렇게 사용하면 된다.
읽기를 수행할 경우 현재 읽기/쓰기 위치에서부터 읽기를 시작하는데, 파일 내용이 다음과 같고, 읽기 위치가 C에 위치한다면 C부터 끝까지 읽을것이다.
babo computer
computer의 총 바이트 수는 8이고, EOF까지 포함하여 9를 반환하게 된다. 읽기 수행후 읽은 만큼 읽기/쓰기 위치는 이동하게 된다.
write
write(파일 디스크립터, 작성할 내용 버퍼 포인터, 작성할 내용 버퍼 길이);
현재 읽기/쓰기 위치가 파일의 맨 끝(EOF)이라면 맨 끝부터 쓰기를 수행한다.
작성에 성공하면 작성한 바이트 수를, 실패하면 -1을 반환한다.
read와 마찬가지로 간단하다.
만약 작성할 내용이 content 버퍼에 담겨있고, 길이가 7 이라면
char content[] = "Hello!\n";
write(fd, content, 7);
이렇게 사용하면 된다. 쓰기 수행후 쓴 만큼 읽기/쓰기 위치는 이동하게 된다.
close
close(파일 디스크립터)
성공시 0, 실패시 -1을 반환한다.
그냥 파일을 닫는다고 보면 된다. close시 close 한 파일 디스크립터는 더는 사용하지 않고, 새로 open할때 이용된다.