open()과 fopen()의 차이
open()과 fopen() 모두 파일을 열기 위해 사용되지만 그 용도와 기능적인 측면에서 몇 가지 차이점이 있다.
- open()
open()의 경우 Unix 및 Unix 계열 운영 체제의 시스템 호출이다.
이 함수는 저수준 파일 입출력을 제공하며 POSIX 호환 운영 체제에서 사용된다.
- fopen()
fopen() 함수는 C 표준 라이브러리에 포함된 고수준 함수이다.
이 함수는 플랫폼에 독립적인 방식으로 파일 입출력을 제공하며 이식성이 높은 코드를 작성할 때 주로 사용된다.
fopen 함수와 관련해서는 아래 링크에서 설명했었으니 이번에는 open에 대해서 주로 다뤄보겠다.
https://enchupin.tistory.com/86
open, close, write, read 함수의 정의
- open()
<fcntl.h>에 정의되어 있다.
- close(), write(), read()
<unistd.h>에 정의되어 있다.
open()
open() 함수는 다음과 같은 매개변수를 요구한다.
int open(const char* pathname, int flags, mode_t mode);
- pathname
pathname은 파일 이름을 포함한 경로를 의미한다.
- flags
flags는 수행할 동작의 유형을 지정한다.
옵션에는 O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_TRUNC, O_APPEND 등이 있다.
위 옵션들은 <fcntl.h>에 8진수로 다음과 같이 정의되어 있다.
0000 O_RDONLY (읽기 전용)
0001 O_WRONLY (쓰기 전용)
0002 O_RDWR (읽기 및 쓰기)
0100 O_CREAT (파일이 없으면 생성, 있으면 파일을 엶)
0200 O_EXCL (파일이 이미 있으면 오류를 반환, 반드시 O_CREAT와 함께 사용)
1000 O_TRUNC (파일을 열 때 내용을 비움)
2000 O_APPEND (쓰기 데이터를 파일 끝에 추가)
따라서 위 옵션들을 비트 논리 연산자를 통해 여러 옵션을 함께 사용하는 것이 가능하다.
만약 flags를 지정하지 않았을 경우 default 값은 O_RDWR이다.
- mode
mode는 파일이 생성될 때 파일의 permission을 설정할 수 있다.
파일이 이미 생성되어 있으면 해당 인자는 무시된다.
mode에 사용할 수 있는 옵션은 아래와 같다.
0400 S_IRUSR // owner has read permission
0200 S_IWUSR // owner has write permission
0100 S_IXUSR // owner has execute permission
0700 S_IRWXU // mask for file owner permissions -> has read, write, execute permission
0040 S_IRGRP // group has read permission
0020 S_IWGRP // group has write permission
0010 S_IXGRP // group has execute permission
0070 S_IRWXG // mask for group permissions
0004 S_IROTH // others have read permission
0002 S_IWOTH // others have write permission
0001 S_IXOTH // others have execute permission
0007 S_IRWXO // mask for permissions for others
해당 옵션들은 <sys/stat.h>에 8진수로 정의되어 있으며
flags의 옵션과 마찬가지로 비트 논리 연산자를 사용하여 여러 옵션을 함께 사용할 수 있다.
가장 흔하게 사용되는 파일들의 옵션은 0644로 사용자에게 읽기 쓰기 권한을 주고 나머지에게 읽기 권한만 부여한 것이다.
따라서 아래 코드처럼 작성하여 파일을 생성(open)할 수 있다.
int fd;
fd = open("C:\\Users\\enchupin\\Desktop\\example\\example.txt", O_RDWR | O_CREAT, 0644);
위와 같이 작성하면 example.txt 파일이 없으면 생성하고 있으면 열어서 문자열을 입력하는 동작을 하게 된다.
이때 open()이 반환하는 값은 File Descriptor이다.
만약 동작을 수행하는데 실패했다면 -1을 반환한다.
close()
open()도 fopen()과 마찬가지로 메모리 관리를 위해 열었으면 close()를 통해서 닫아주어야 한다.
또한 이미 닫힌 파일을 또다시 닫으려는 시도는 의도하지 않은 결과가 발생할 수 있다.
특히 멀티스레드 프로그램에서는 더 치명적인데 여러 스레드가 동시에 파일을 닫으려고 시도하기 때문이다.
따라서 함수 호출 반환값을 항상 확인하는 것이 좋은 습관이다.
write()
write() 함수는 다음과 같은 매개변수를 요구한다.
ssize_t write(int fd, const void* buf, size_t count);
write 함수는 파일 디스크립터(fd), 버퍼(buf), 버퍼의 크기(count)를 인자로 요구한다.
파일 디스크립터를 통해 파일의 정보에 접근하고 버퍼에 있는 데이터를 파일의 current file offset 위치에 작성한다.
이때 buf는 단순히 주소값을 가리키므로 시스템은 주어진 주소로부터 얼마나 값을 읽어야 하는지 알 수 없다.
따라서 count를 통해서 작성할 데이터의 크기를 전달해주어야 한다.
write는 정상적으로 동작하였다면 기록한 데이터의 바이트 수를 반환하고 데이터를 기록하지 않았거나 특수한 상황에서 0을 반환하며 에러가 발생하면 -1을 반환한다.
read()
ssize_t read(int fd, void *buf, size_t count);
read()도 write()와 비슷한 방식으로 동작한다.
fd를 통해 파일의 정보에 접근하고 current file offset에서부터 count 크기만큼 데이터를 읽어 들이며
읽어 들인 데이터를 buf가 가리키는 메모리 공간에 채워 넣는다.
read는 정상적으로 동작하였다면 읽어 들인 데이터의 바이트 수를 반환하고 읽어 들일 데이터가 없거나 특수한 상황에서 0을 반환하며 에러가 발생하면 -1을 반환한다.
*ssize_t는 일반적으로 unistd.h 헤더파일에 다음과 같이 정의되어 있다.
typedef long ssize_t;
'C언어 > 시스템 소프트웨어' 카테고리의 다른 글
[시스템 소프트웨어/C언어] stat(), fstat() (0) | 2024.10.08 |
---|---|
[시스템 소프트웨어/C언어] lseek, 파일 오프셋 변경 (파일 작업 위치 변경) (0) | 2024.10.08 |
[C언어] perror, errno, exit (0) | 2024.10.07 |
[시스템 소프트웨어] File Sharing (file offset) (0) | 2024.10.07 |
[시스템 소프트웨어] 메타 데이터, inode, 파일 디스크립터 (0) | 2024.10.07 |