제 10 장 화일 입출력
대부분의 PC 시스템은 디스크를 기반으로 하는 화일 관리를 하고 있다.
- 디스크 상에는 많은 화일이 존재할 수 있다.
- 작업할 화일을 열때에 지정된 작업 모드에 따라서 그 화일에 대해 읽기나 쓰기 작업을 할 수 있다.
- 열려진 화일은 작업이 끝나거나 프로그램을 마치는 경우 화일을 닫아주어야 정상적인 화일 상태를 보존할 수 있다.
화일의 데이터 상태에 따라 우리는 그 데이터가 문서 데이터인지 아니면 2진 데이터인지 구분할 필요가 있다.
텍스트 모드의 경우 화일의 끝 표시는 0x1A로 사용한다.
2진 모드의 경우 0x1A가 화일의 끝을 의미하지 않으며, '\n'의 데이터 변환도 일어나지 않는다.
저수준 입출력의 경우 UNIX 환경에서도 사용 가능한 것과 MS-DOS 환경에서만 사용 가능한 것으로 분류할 수 있다.
저수준 방법으로 화일을 열기 위해서는 open()이나 creat() 함수를 이용한다.
- creat() 함수의 내용은 다음과 같다.
에러 발생시 전역변수 errno는 다음처럼 설정된다.
ENOENT : Path or file name not found
EMFILE : Too many open file
EACCES : Permission denied
EINVACC: 엑세스 코드 에러
write() 함수는 열려진 화일에 데이터를 출력하고,
read() 함수는 열려진 화일에서 데이터를 읽는다.
- write() 함수에 대한 내용은 다음과 같다.
에러 발생시 전역변수 errno는 다음처럼 설정된다.
EACCES : Permission denied
EBADF : 화일 번호 에러
write() 함수가 한번에 저장할 수 있는 데이터 크기는 65534이다.
에러 발생시 전역변수 errno는 다음처럼 설정된다.
EACCES : Permission denied
EBADF : 화일 번호 에러
close() 함수를 이용하여 화일을 닫는다.
- close() 함수에 대한 내용은 다음과 같다.
에러 발생시 전역 변수 errno는 다음값으로 설정된다.
EBADF : 화일 번호 에러
C 언어에서는 새로운 데이터 입출력 장치 개념인 스트림(stream)을 지원한다.
스트림 입출력 함수 (화일 관련)
----------------------------------------------------------------
함수명 함수 기능 참고
----------------------------------------------------------------
fclose 화일을 닫는다. 중요
fcloseall 모든 화일을 닫는다. O
fdopen 화일을 연다. X
feof 화일의 끝을 검사한다. (매크로 함수) 중요
fflush 스트림 입출력 버퍼를 지운다. O
fgets 화일에서 문자열 읽음. 중요
fileno 화일 번호를 얻음 O
flushall 모든 입출력 버퍼를 지운다. O
fopen 화일을 연다. 중요
fprintf 화일에 형식지정된 내용을 출력한다. 중요
fputs 화일에 문자열을 출력한다. 중요
fread 화일에서 블럭을 읽는다. 중요
freopen 화일을 다시 연다. O
fscanf 화일에서 형식지정된 내용을 읽는다. 중요
fseek 현재 화일 작업 위치를 이동한다. 중요
ftell 현재 화일 작업 위치를 얻는다. O
fwrite 화일에 블럭 내용을 출력한다. 중요
fgetc 화일에서 1 문자 읽는다. 중요
getw 화일에서 1 워드 읽는다. O
fputc 화일에 1 문자 출력한다. 중요
putw 화일에 1 워드 출력한다. O
remove 화일을 지운다. (매크로 함수) X
rename 화일 이름을 바꾼다. (MS-DOS만 지원) O
rewind 화일 선두로 작업위치 옮김. O
setbuf 사용자 버퍼를 설정한다. X
setvbuf 모드 지정 버퍼를 설정한다. X
ungetc 화일로 1 문자를 돌려준다. X
----------------------------------------------------------------
중요 : 중요하다.
스트림 입출력 화일을 열기 위해서는 fopen() 함수를 이용한다.
- fopen() 함수의 내용은 다음과 같다.
스트림 방식은 화일뿐만이 아닌 여러 장치 입출력을 포함하지만 여기에서는
화일 위주로 설명한다. 화일에 데이터를 입출력하는 함수는 상당히 많이
지원되며 [표]에 나와있다. 그 중에서 몇가지 중요한 함수를 설명하면 다음과
같다.
- fseek() 함수의 내용은 다음과 같다.
- ftell() 함수의 내용은 다음과 같다.
- fread() 함수의 내용은 다음과 같다.
- fwrite() 함수의 내용은 다음과 같다.
- fgets() 함수의 내용은 다음과 같다.
- fprintf() 함수의 내용은 다음과 같다.
- fputs() 함수의 내용은 다음과 같다.
- fgetc() 함수의 내용은 다음과 같다.
- fputc() 함수의 내용은 다음과 같다.
fclose() 함수를 이용하여 화일을 닫는다. fclose() 함수에 대한 내용은 다음과 같다.
10.5 응용 예제
1. 실행 화일의 인자를 화일이름으로 받아 복사하는 프로그램
#include "stdio.h"
#include "stdio.h"
#include "stdio.h"
대부분의 PC 시스템은 디스크를 기반으로 하는 화일 관리를 하고 있다.
그러므로 화일 입출력은 디스크 입출력이라 말해도 큰 무리가 없다.
C 언어에서의 화일 입출력은 더 포괄적인 의미를 가진다.
화일 입출력시 화일(입출력할 대상)은 디스크, 테이프 장치, 프린터 등이 될 수도 있다.
화일을 사용하기 위해서는 어느 화일을 사용할지 지정해야 하는데 이것을 '연다(open)'고 표현한다.
화일을 입출력을 끝낼 때는 사용이 끝났음을 알려주어야 하는데 이것을 '닫는다(close)'라고 말한다.
화일을 닫는 방법은 터보 C에서는 다음 두 방식으로 지원한다.
도스 시스템 호출 기능에 의존하는 저수준 화일 입출력과 C 언어의 고수준 입출력(stream I/O)을 통한 화일 입출력을 지원한다.
10.1 화일 입출력 순서
터보 C에서는 저수준 및 고수준 화일 입출력을 지원한다.
두 방식 모두 화일을 입출력하기 위해서는 다음 세 단계를 사용한다.
10.1.1 작업할 화일을 연다. (FILE OPEN)
- 디스크 상에는 많은 화일이 존재할 수 있다.
그러므로 화일들 중에서 사용자나 프로그램이 사용할 화일을 지정하여 그 화일을 사용 할 수 있는 상태로 만들어야 한다.
이렇게 화일을 사용 가능한 상태로 만드는 것을 '화일을 연다(OPEN)'라고 말한다.
화일에 대한 입출력 작업을 하려면 작업 대상체인 화일이 존재하여야 한다.
그러므로 작업할 화일이 현재 존재하는지에 따라 화일을 여는 방식은 달라질 수 있다.
그러므로 작업할 화일이 현재 존재하는지에 따라 화일을 여는 방식은 달라질 수 있다.
화일은 화일 이름으로 구분이 되므로 화일을 여는 경우 화일 이름은 반드시 필요하다.
만약 임시 화일을 만드는 함수를 이용하는 경우에는 함수에서 화일 이름을 임시로 만들어준다.
10.1.2 열려진 화일에 데이터를 입출력 (FILE WRITE/READ, Input/Output)
- 작업할 화일을 열때에 지정된 작업 모드에 따라서 그 화일에 대해 읽기나 쓰기 작업을 할 수 있다.
C 언어에서는 화일의 데이터를 읽고 쓰는 방법(한 문자 단위, 워드 단위, 줄 단위, 블럭 단위, 형식지정)에 따라
여러가지 함수를 지원한다.
10.1.3 열려진 화일을 닫는다. (FILE CLOSE)
- 열려진 화일은 작업이 끝나거나 프로그램을 마치는 경우 화일을 닫아주어야 정상적인 화일 상태를 보존할 수 있다.
이 작업을 '화일을 닫는다(CLOSE)'고 한다.
10.2 화일 작업 모드
화일의 데이터 상태에 따라 우리는 그 데이터가 문서 데이터인지 아니면 2진 데이터인지 구분할 필요가 있다.
데이터가 문서인 경우에는 텍스트 모드(text mode)로 지정하고
이미지와 같은 2진 데이터인 경우 2진 모드(binary mode)로 지정해서 화일을 열어야 한다.
화일을 여는 함수는 이러한 화일 지정 모드를 가지고 있다.
10.2.1 텍스트 모드(text mode)의 데이터 변환
텍스트 모드의 경우 화일의 끝 표시는 0x1A로 사용한다.
그러므로 화일의 크기에 상관없이 데이터 중간에 0x1A가 존재하면 화일의 끝으로 인식한다.
또한 다음 그림처럼 데이터 변환이 이루어진다.
메모리 버퍼 화일 데이터
데이터 입출력
'\n' <---------------------> CR + LF
데이터 입출력
'\n' <---------------------> CR + LF
메모리 버퍼상에 존재하는 C 언어의 개행 문자 '\n'(0x0A)은
화일로 저장시 캐리지리턴(CR=0x0D)과 라인피드(LF=0x0A)로 확장되어 저장된다.
반대로 화일에서 읽는 경우 캐리지리턴(CR=0x0D)과 라인 피드(LF=0xA)의 조합은
C언어의 개행문자 '\n'(0x0A)으로 변환되어 읽혀진다.
10.2.2 2진 모드(binary mode)의 데이터 변환
2진 모드의 경우 0x1A가 화일의 끝을 의미하지 않으며, '\n'의 데이터 변환도 일어나지 않는다.
그러므로 화일의 데이터 상태가 텍스트 모드인 경우에, 이 화일을 2진 모드로 연다면 데이터 값에 잘못이 생길 것이다.
2진 모드 화일 데이터 역시 텍스트 모드로 개방한다면 비정상적인 결과를 얻을 것이다.
메모리 버퍼 화일 데이터
데이터 입출력
'\n' <---------------------> '\n'
CR + LF CR + LF
데이터 입출력
'\n' <---------------------> '\n'
CR + LF CR + LF
10.3 저수준 화일 관리 함수
저수준 입출력의 경우 UNIX 환경에서도 사용 가능한 것과 MS-DOS 환경에서만 사용 가능한 것으로 분류할 수 있다.
여기에서는 UNIX에서도 호환되는 방식을 기준으로 설명하겠다.
UNIX 환경에서도 사용 가능한 화일 입출력 함수 (권장)
-----------------------------------------------------------------
함수명 함수 기능 참고
-----------------------------------------------------------------
access 화일의 속성을 얻는다. (화일 존재 확인) O
chmode 화일의 속성을 변경한다. O
close 화일을 닫는다. (close) 중요
creat 새로운 화일을 만든다. O
dup 화일 핸들을 복사한다. X
dup2 기존 화일 핸들을 복사한다. X
eof 화일의 끝(end of file)을 검사 중요
filelength 화일 크기를 알아낸다. O
fstat 화일 정보를 얻는다. O
ioctl I/O 장치를 제어한다. X
lseek 화일의 작업 위치를 이동한다. O
open 화일을 연다. (open) 중요
read 열린 화일을 읽는다. 중요
setmode 화일의 텍스트/2진 모드를 설정한다. O
stat 화일의 정보를 얻는다. O
tell 화일의 현재 작업 위치를 알아낸다. O
umask 화일 속성 마스크(mask)를 지정한다. X
write 열린 화일에 쓴다. 중요
-----------------------------------------------------------------
중요 : 중요하다.
-----------------------------------------------------------------
함수명 함수 기능 참고
-----------------------------------------------------------------
access 화일의 속성을 얻는다. (화일 존재 확인) O
chmode 화일의 속성을 변경한다. O
close 화일을 닫는다. (close) 중요
creat 새로운 화일을 만든다. O
dup 화일 핸들을 복사한다. X
dup2 기존 화일 핸들을 복사한다. X
eof 화일의 끝(end of file)을 검사 중요
filelength 화일 크기를 알아낸다. O
fstat 화일 정보를 얻는다. O
ioctl I/O 장치를 제어한다. X
lseek 화일의 작업 위치를 이동한다. O
open 화일을 연다. (open) 중요
read 열린 화일을 읽는다. 중요
setmode 화일의 텍스트/2진 모드를 설정한다. O
stat 화일의 정보를 얻는다. O
tell 화일의 현재 작업 위치를 알아낸다. O
umask 화일 속성 마스크(mask)를 지정한다. X
write 열린 화일에 쓴다. 중요
-----------------------------------------------------------------
중요 : 중요하다.
O : 가끔 사용.
X : 나중에 익혀도 좋다.
MS-DOS용 화일 입출력 함수
-----------------------------------------------------------
함수명 함수 기능
-----------------------------------------------------------
_chmode 화일의 속성을 변경한다.
_close 화일을 닫는다. (close)
_creat 새로운 화일을 만든다.
creatnew 새로운 화일을 만든다. (존재시 만들지 않음)
creattemp 새로운 임시 화일을 만든다.
gettime 화일의 작성 시간을 얻는다.
lock 화일을 잠근다.(공유 안함)
_open 화일을 연다. (open)
_read 열린 화일을 읽는다.
settime 화일 작성 시간을 변경한다.
sopen 화일을 공유 상태로 연다.
unlock 화일을 연다. (공유 한다.)
_write 열린 화일에 쓴다.
----------------------------------------------------------
-----------------------------------------------------------
함수명 함수 기능
-----------------------------------------------------------
_chmode 화일의 속성을 변경한다.
_close 화일을 닫는다. (close)
_creat 새로운 화일을 만든다.
creatnew 새로운 화일을 만든다. (존재시 만들지 않음)
creattemp 새로운 임시 화일을 만든다.
gettime 화일의 작성 시간을 얻는다.
lock 화일을 잠근다.(공유 안함)
_open 화일을 연다. (open)
_read 열린 화일을 읽는다.
settime 화일 작성 시간을 변경한다.
sopen 화일을 공유 상태로 연다.
unlock 화일을 연다. (공유 한다.)
_write 열린 화일에 쓴다.
----------------------------------------------------------
10.3.1 화일 열기 (OPEN)
저수준 방법으로 화일을 열기 위해서는 open()이나 creat() 함수를 이용한다.
creat() 함수는 새로운 화일을 만들 때 이용한다.
전역 변수 _fmode는 화일 데이터의 작업 속성을 지정하는데 텍스트 모드와 2진 모드 두가지 속성을 지정할 수 있다.
전역 변수 _fmode의 속성은 O_TEXT와 O_BINARY를 이용해 변화시킬 수 있다.
creatnew() 함수의 경우 creat() 함수와 동일하며 다만 기존 화일이 존재시 작업을 중지하고 에러를 반환한다는 점이 다르다.
- creat() 함수의 내용은 다음과 같다.
#include <sys\stst.h>
int creat(char *path, int amode);
path : 새롭게 만들 화일 이름
amode : 화일 엑세스 방식
S_IWRITE : 쓰기용 화일
S_IREAD : 읽기용 화일
S_IWRITE | S_IREAD : 쓰기/읽기용 화일
(* 화일이 존재하는 경우, 쓰기용 화일로 선택되면 화일의 크기는
0으로 만들어진다. 기존 화일의 속성이 읽기 전용인 경우 에러를
발생하고 화일은 변경되지 않는다.
S_IREAD : 읽기용 화일
S_IWRITE | S_IREAD : 쓰기/읽기용 화일
(* 화일이 존재하는 경우, 쓰기용 화일로 선택되면 화일의 크기는
0으로 만들어진다. 기존 화일의 속성이 읽기 전용인 경우 에러를
발생하고 화일은 변경되지 않는다.
리턴값: 0 이상의 정수 = 화일 핸들러(화일 작업 번호)
-1 = 에러 발생 번호
에러 발생시 전역변수 errno는 다음처럼 설정된다.
ENOENT : Path or file name not found
EMFILE : Too many open file
EACCES : Permission denied
-1 = 에러 발생 번호
에러 발생시 전역변수 errno는 다음처럼 설정된다.
ENOENT : Path or file name not found
EMFILE : Too many open file
EACCES : Permission denied
[예]
#include <sys\stst.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
void main(void)
{
int handle;
char buf[11] = "0123456789";
{
int handle;
char buf[11] = "0123456789";
/* 화일 데이터 작업 속성을 2진 화일로 설정한다. */
_fmode = O_BINARY;
_fmode = O_BINARY;
/* 읽기/쓰기용 화일을 만든다.(화일 열림) */
handle = creat("DEMO.DAT", S_IREAD | S_IWRITE);
handle = creat("DEMO.DAT", S_IREAD | S_IWRITE);
/* 10 바이트를 화일에 저장한다. */
write(handle, buf, strlen(buf));
write(handle, buf, strlen(buf));
/* 화일을 닫는다. */
close(handle);
}
close(handle);
}
- open() 함수의 내용은 다음과 같다.
#include <fcntl.h>
#include <sys\stst.h>
#include <sys\stst.h>
int open(const char *path, int access[, unsigned mode]);
path : 새롭게 만들 화일 이름
access: 화일 작업 방식으로 세가지 부분의 값을 조합(|)하여 얻어진다.
- 부분 1 (읽기/쓰기 플래그)
O_RDONLY : 읽기 전용으로 화일을 연다.
O_WRONLY : 쓰기 전용으로 화일을 연다.
O_RDWR : 읽기/쓰기 전용으로 화일을 연다.
access: 화일 작업 방식으로 세가지 부분의 값을 조합(|)하여 얻어진다.
- 부분 1 (읽기/쓰기 플래그)
O_RDONLY : 읽기 전용으로 화일을 연다.
O_WRONLY : 쓰기 전용으로 화일을 연다.
O_RDWR : 읽기/쓰기 전용으로 화일을 연다.
- 부분 2 (부가적인 엑세스 플래그)
O_NDELAY : UNIX용으로 사용하지 않음.
O_APPEND : 화일을 열리면 화일 작업 위치를 화일의 끝으로 이동함.
O_CREAT : 화일이 존재하지 않으면 화일을 만든다. 만들어지는
화일의 속성은 mode를 이용한다.(mode 사용됨에 주의!)
O_TRUNK : 화일이 존재하면 화일 크기를 0으로 한다. 화일 속성은 기존 화일 속성과 같다.
O_EXCL : O_CREAT와 같이 사용되며, 화일이 존재시 에러를 돌려준다.
O_NDELAY : UNIX용으로 사용하지 않음.
O_APPEND : 화일을 열리면 화일 작업 위치를 화일의 끝으로 이동함.
O_CREAT : 화일이 존재하지 않으면 화일을 만든다. 만들어지는
화일의 속성은 mode를 이용한다.(mode 사용됨에 주의!)
O_TRUNK : 화일이 존재하면 화일 크기를 0으로 한다. 화일 속성은 기존 화일 속성과 같다.
O_EXCL : O_CREAT와 같이 사용되며, 화일이 존재시 에러를 돌려준다.
- 부분 3 (화일 데이터 모드)
O_BINARY : 화일을 2진 모드로 열때 사용한다.
O_TEXT : 화일을 텍스트 모드로 열때 사용한다.
(* 부분 3이 사용안되면 전역변수 _fmode를 따른다.)
O_BINARY : 화일을 2진 모드로 열때 사용한다.
O_TEXT : 화일을 텍스트 모드로 열때 사용한다.
(* 부분 3이 사용안되면 전역변수 _fmode를 따른다.)
mode : 화일 엑세스 방식
S_IWRITE : 쓰기용 화일
S_IREAD : 읽기용 화일
S_IWRITE | S_IREAD : 쓰기/읽기용 화일
(* 화일이 존재하는 경우, 쓰기용 화일로 선택되면 화일의 크기는 0으로 만들어진다.
S_IREAD : 읽기용 화일
S_IWRITE | S_IREAD : 쓰기/읽기용 화일
(* 화일이 존재하는 경우, 쓰기용 화일로 선택되면 화일의 크기는 0으로 만들어진다.
기존 화일의 속성이 읽기 전용인 경우 에러를 발생하고 화일은 변경되지 않는다.
리턴값: 0 이상 정수 = 화일 핸들러(화일 작업 번호)
-1 = 에러 발생 번호
-1 = 에러 발생 번호
에러 발생시 전역변수 errno는 다음처럼 설정된다.
ENOENT : Path or file name not found
EMFILE : Too many open file
EACCES : Permission denied
EINVACC: 엑세스 코드 에러
[예]
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char string[11] = "TEXT DATA!";
{
int handle;
char string[11] = "TEXT DATA!";
/* DEMO.TXT화일을 텍스트 데이터 모드로 새로 만든다. */
if((handle = (open("DEMO.TXT", OCREAT | O_TEXT)) == -1)
{
perror("Error:");
return 1;
}
if((handle = (open("DEMO.TXT", OCREAT | O_TEXT)) == -1)
{
perror("Error:");
return 1;
}
/* "TEXT DTAT!" 문자열을 화일에 저장한다. */
write(handle, string, strlen(string));
write(handle, string, strlen(string));
/* 화일을 닫는다. */
close(handle);
close(handle);
return 0;
}
}
10.3.2 화일의 데이터 입출력 (WRITE/READ)
write() 함수는 열려진 화일에 데이터를 출력하고,
read() 함수는 열려진 화일에서 데이터를 읽는다.
- write() 함수에 대한 내용은 다음과 같다.
#include <io.h>
int write(int handle, void *buf, unsigned len);
handle: 화일 작업 번호 (핸들)
buf : 화일에 출력할 데이터를 담은 버퍼
len : 화일에 출력할 데이터 길이(바이트 단위)
buf : 화일에 출력할 데이터를 담은 버퍼
len : 화일에 출력할 데이터 길이(바이트 단위)
리턴값: 0 이상 정수 = 화일에 저장된 데이터 길이.(캐리지리턴은 제외)
-1 = 에러 발생
-1 = 에러 발생
에러 발생시 전역변수 errno는 다음처럼 설정된다.
EACCES : Permission denied
EBADF : 화일 번호 에러
write() 함수가 한번에 저장할 수 있는 데이터 크기는 65534이다.
65535(-1)는 에러 발생시 반환값으로 사용된다.
텍스트 화일에 쓰는 경우 개행문자(LF)는 CR/LF로 변환된다.
화일에 쓰는 장소는 현재 화일 작업 위치(포인터)이며 출력한 데이터 길이만큼 화일 작업 위치는 증가하여 이동한다.
- read() 함수에 대한 내용은 다음과 같다.
#include <io.h>
int read(int handle, void *buf, unsigned len);
handle: 화일 작업 번호 (핸들)
buf : 화일에서 읽은 데이터를 담은 버퍼
len : 화일에서 읽을 데이터 길이(바이트 단위)
buf : 화일에서 읽은 데이터를 담은 버퍼
len : 화일에서 읽을 데이터 길이(바이트 단위)
리턴값: 0 이상 정수 = 화일에서 읽은 데이터 길이
-1 = 에러 발생
-1 = 에러 발생
에러 발생시 전역변수 errno는 다음처럼 설정된다.
EACCES : Permission denied
EBADF : 화일 번호 에러
write() 함수가 한번에 읽을 수 있는 데이터의 크기는 65534이다.
65535(-1)는 에러 발생시 반환값으로 사용된다.
65535(-1)는 에러 발생시 반환값으로 사용된다.
텍스트 화일을 읽는 경우 캐리지리턴은 무시되며 화일의 끝(EOF)은 Ctrl-Z 값이다.
화일에서 읽는 장소는 현재 화일 작업 위치(포인터)이며 작업한 길이만큼 화일 작업 위치는 증가하여 이동한다.
10.3.3 화일 닫기 (CLOSE)
close() 함수를 이용하여 화일을 닫는다.
텍스트 화일의 경우 화일의 끝(EOF)을 나타내는 Ctrl-Z 문자를 직접 넣어주어야 한다.
- close() 함수에 대한 내용은 다음과 같다.
#include <io.h>
int close(int f_handle);
f_handle: 화일 작업 번호 (핸들)
리턴값: 0 = 화일이 정상적으로 닫힘
-1 = 에러 발생
-1 = 에러 발생
에러 발생시 전역 변수 errno는 다음값으로 설정된다.
EBADF : 화일 번호 에러
10.4 고수준 화일 관리 함수 (stream I/O)
C 언어에서는 새로운 데이터 입출력 장치 개념인 스트림(stream)을 지원한다.
비록 물리적으로 다른 장치이지만 사용자 입장에서는 비슷한 관점에서 다룰 수 있게 해준다.
화면(디스플레이), 프린터, 키보드, 화일 등 이러한 장치들은 스트림 개념에서 모두 동일하게 취급된다.
스트림 입출력 함수는 STDIO.H 헤더 화일에 선언되어 있다.
스트림 입출력 함수 (화일 관련)
----------------------------------------------------------------
함수명 함수 기능 참고
----------------------------------------------------------------
fclose 화일을 닫는다. 중요
fcloseall 모든 화일을 닫는다. O
fdopen 화일을 연다. X
feof 화일의 끝을 검사한다. (매크로 함수) 중요
fflush 스트림 입출력 버퍼를 지운다. O
fgets 화일에서 문자열 읽음. 중요
fileno 화일 번호를 얻음 O
flushall 모든 입출력 버퍼를 지운다. O
fopen 화일을 연다. 중요
fprintf 화일에 형식지정된 내용을 출력한다. 중요
fputs 화일에 문자열을 출력한다. 중요
fread 화일에서 블럭을 읽는다. 중요
freopen 화일을 다시 연다. O
fscanf 화일에서 형식지정된 내용을 읽는다. 중요
fseek 현재 화일 작업 위치를 이동한다. 중요
ftell 현재 화일 작업 위치를 얻는다. O
fwrite 화일에 블럭 내용을 출력한다. 중요
fgetc 화일에서 1 문자 읽는다. 중요
getw 화일에서 1 워드 읽는다. O
fputc 화일에 1 문자 출력한다. 중요
putw 화일에 1 워드 출력한다. O
remove 화일을 지운다. (매크로 함수) X
rename 화일 이름을 바꾼다. (MS-DOS만 지원) O
rewind 화일 선두로 작업위치 옮김. O
setbuf 사용자 버퍼를 설정한다. X
setvbuf 모드 지정 버퍼를 설정한다. X
ungetc 화일로 1 문자를 돌려준다. X
----------------------------------------------------------------
중요 : 중요하다.
O : 가끔 사용.
X : 나중에 익혀도 좋다.
UNIX V용 함수로는 vfprintf, vfscanf, vsprintf, vsscanf 등이 있다.
10.4.1 화일 열기 (OPEN)
스트림 입출력 화일을 열기 위해서는 fopen() 함수를 이용한다.
새로운 화일을 만들고자 할때 이용된다.
전역 변수 _fmode는 화일 데이터의 작업 속성을 지정하는데 텍스트 모드와 2진 모드 두가지 속성을 지정할 수 있다.
전역 변수 _fmode의 속성은 O_TEXT와 O_BINARY를 이용해 변화 시킬 수 있다.
- fopen() 함수의 내용은 다음과 같다.
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
filename: 화일 이름
mode : 화일 접근 방식
mode : 화일 접근 방식
- 부분 1
r : 읽기 전용
w : 쓰기용으로 화일 만듦 (화일 존재시 중복하여 쓰기한다.)
a : 화일 존재시 쓰기용으로 열고 화일 작업 위치를 끝으로 옮김.
만약 화일이 없으면 새로운 화일을 쓰기용으로 만들어 연다.
r+: 읽기/쓰기 가능 (존재하는 화일)
w+: 새로운 화일 만듦 (같은 화일 존재시 중복하여 쓰기함)
a+: 화일 존재시 갱신용으로 열어 화일 작업 위치를 끝으로 이동.
화일이 없으면 새로운 화일을 만든다.
r : 읽기 전용
w : 쓰기용으로 화일 만듦 (화일 존재시 중복하여 쓰기한다.)
a : 화일 존재시 쓰기용으로 열고 화일 작업 위치를 끝으로 옮김.
만약 화일이 없으면 새로운 화일을 쓰기용으로 만들어 연다.
r+: 읽기/쓰기 가능 (존재하는 화일)
w+: 새로운 화일 만듦 (같은 화일 존재시 중복하여 쓰기함)
a+: 화일 존재시 갱신용으로 열어 화일 작업 위치를 끝으로 이동.
화일이 없으면 새로운 화일을 만든다.
- 부분 2
b : 2진 데이터 형식 입출력
t : 텍스트 데이터 방식 입출력
b : 2진 데이터 형식 입출력
t : 텍스트 데이터 방식 입출력
* 참고
부분 1과 부분 2는 같이 사용할 수 있다.
텍스트용으로 화일을 읽기 전용으로 열고 싶으면 "rt"를 사용.
2진 데이터용 화일을 쓰기 가능으로 만들어 열려면 "wb"를 사용.
기존 화일이 존재시, 화일을 텍스트용으로 추가하려면 "at"한다.
"r+t", "r+b", "w+t", "w+b" 등은 "rt+", "rb+", "wt+", "wb+"와 같다.
부분 1과 부분 2는 같이 사용할 수 있다.
텍스트용으로 화일을 읽기 전용으로 열고 싶으면 "rt"를 사용.
2진 데이터용 화일을 쓰기 가능으로 만들어 열려면 "wb"를 사용.
기존 화일이 존재시, 화일을 텍스트용으로 추가하려면 "at"한다.
"r+t", "r+b", "w+t", "w+b" 등은 "rt+", "rb+", "wt+", "wb+"와 같다.
리턴값: FILE 포인터 = 열린 스트림의 포인터
NULL = 에러 발생
NULL = 에러 발생
[예]
#include <stdio.h>
int main(void)
{
FILE *in, *out;
{
FILE *in, *out;
if((in = fopen("ATOEXEC.BAT", "rt")) == NULL)
{
fprintf(stderr, "Cannot open input file.\n");
return 1;
}
{
fprintf(stderr, "Cannot open input file.\n");
return 1;
}
if((out = fopen("ATOEXEC.BAK", "wt")) == NULL)
{
fprintf(stderr, "Cannot open input file.\n");
return 1;
}
{
fprintf(stderr, "Cannot open input file.\n");
return 1;
}
while(!feof(in)) { fputc(fgetc(in), out); }
/* 화일을 닫는다. */
fclose(in);
fclose(out);
fclose(in);
fclose(out);
return 0;
}
}
10.4.2 화일의 데이터 입출력 (WRITE/READ)
스트림 방식은 화일뿐만이 아닌 여러 장치 입출력을 포함하지만 여기에서는
화일 위주로 설명한다. 화일에 데이터를 입출력하는 함수는 상당히 많이
지원되며 [표]에 나와있다. 그 중에서 몇가지 중요한 함수를 설명하면 다음과
같다.
1. 화일의 작업위치(화일 포인터) 알아내기/이동하기
- fseek() 함수의 내용은 다음과 같다.
현재 화일 작업 위치를 이동한다. (화일 핸들을 이용한 입출력에서는 lseek() 함수를 사용했음과 비교하라.)
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence)
int fseek(FILE *stream, long offset, int whence)
stream : 이미 열려진 화일 스트림
offset : 화일에서 바이트 오프셋 (이동 거리)
whence : 오프셋의 위치(시작 위치)
SEEK_SET (0) : 화일의 시작
SEEK_CUR (1) : 화일의 현재 포인터
SEEK_END (2) : 화일의 끝
offset : 화일에서 바이트 오프셋 (이동 거리)
whence : 오프셋의 위치(시작 위치)
SEEK_SET (0) : 화일의 시작
SEEK_CUR (1) : 화일의 현재 포인터
SEEK_END (2) : 화일의 끝
리턴값 : 0 = 화일 포인터가 성공적으로 이동
0 이외 = 화일 포인터 이동 실패
0 이외 = 화일 포인터 이동 실패
예제 : 화일의 끝을 찾음
fseek(stream, 0L, SEEK_END);
| | |
| | 화일의 끝을 기준으로
| 0 크기 만큼 이동
이미 열려진 화일 스트림
fseek(stream, 0L, SEEK_END);
| | |
| | 화일의 끝을 기준으로
| 0 크기 만큼 이동
이미 열려진 화일 스트림
- ftell() 함수의 내용은 다음과 같다.
현재 화일 작업 위치를 얻는다. 현재 열려진 화일 스트림의 시작 위치에서
현재 작업 위치까지의 바이트 단위 거리를 사용한다(2진 모드).
현재 작업 위치까지의 바이트 단위 거리를 사용한다(2진 모드).
#include <stdio.h>
long int ftell(FILL *stream)
long int ftell(FILL *stream)
stream : 이미 열려진 화일 스트림
리턴값 : 화일 포인터의 위치를 돌려주며, -1L인 경우는 에러 발생을 뜻한다.
에러 발생시 전역 변수 errno에 양의 값을 설정한다.
2. 데이터를 블럭으로 쓰고/읽기
- fread() 함수의 내용은 다음과 같다.
스트림에서 데이터 블럭을 읽는다.
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
ptr : 데이터 버퍼의 포인터
size : 각 항목의 크기
n : size 길이를 갖는 항목의 수
stream: 화일 스트림
size : 각 항목의 크기
n : size 길이를 갖는 항목의 수
stream: 화일 스트림
리턴값 : 0 = 에러 발생 또는 화일의 끝(EOF)
이외 = 실제로 읽혀진 단위 항목의 수(바이트 단위 아님에 주의)
이외 = 실제로 읽혀진 단위 항목의 수(바이트 단위 아님에 주의)
[예]
#include <string.h>
#include <stdio.h>
#include <stdio.h>
int main(void)
{
char buf[20];
char str[ ]="This is a test";
FILE *stream;
{
char buf[20];
char str[ ]="This is a test";
FILE *stream;
if((stream=fopen("TEST.$$$", "w+")) == NULL)
{
fprintf(stderr, "Cannot open output file.\n");
return 1;
}
{
fprintf(stderr, "Cannot open output file.\n");
return 1;
}
/* 데이터를 화일에 저장한다. */
fwrite(str, strlen(str)+1, 1, stream);
fwrite(str, strlen(str)+1, 1, stream);
/* 화일의 시작 위치로 이동 */
fseek(stream, SEEK_SET, 0);
fseek(stream, SEEK_SET, 0);
/* 화일에서 한 문자열 읽음 */
fread(buf, strlen(str)+1, 1, stream);
fread(buf, strlen(str)+1, 1, stream);
printf("%s\n", buf);
return 0;
}
- fwrite() 함수의 내용은 다음과 같다.
화일에 데이터 블럭 내용을 출력한다.
#include <stdio.h>
size_t fwrite (const void *ptr, size_t size, size_t n, FILE *stream);
size_t fwrite (const void *ptr, size_t size, size_t n, FILE *stream);
ptr : 데이터 버퍼에 대한 포인터
size : 각 항목의 바이트 수
n : size 길이를 가지는 항목의 수
stream: 화일 스트림
size : 각 항목의 바이트 수
n : size 길이를 가지는 항목의 수
stream: 화일 스트림
리턴값 : 0 = 에러 발생
이외 = 실제로 쓰여진 데이터 항목의 수
이외 = 실제로 쓰여진 데이터 항목의 수
3. 화일(스트림)에 양식화된 데이터 쓰고/읽기
- fgets() 함수의 내용은 다음과 같다.
화일에서 개행문자가 나오거나 지정된 문자 '개수 - 1'만큼 읽으면 끝낸다.
개행문자는 지정된 버퍼에 저장되지 않으므로 NULL 문자를 문자열의 끝에 직접 지정해주어야 한다.
개행문자는 지정된 버퍼에 저장되지 않으므로 NULL 문자를 문자열의 끝에 직접 지정해주어야 한다.
#include <stdio.h>
char *fgets(char *s, int n, FILE *stream);
char *fgets(char *s, int n, FILE *stream);
s : 읽을 데이터 문자열 버퍼의 포인터
n : 읽을 문자열의 최대 문자 수
stream: 문자를 읽을 화일 스트림
n : 읽을 문자열의 최대 문자 수
stream: 문자를 읽을 화일 스트림
리턴값 : NULL = EOF나 에러 발생
이외 = s의 포인터
이외 = s의 포인터
- fprintf() 함수의 내용은 다음과 같다.
화일에 형식화된 내용을 출력한다. 화일 스트림이 지정되는 되는 것이 포함될 뿐 기존 printf 형식과 같다.
#include <stdio.h>
int fprintf(FILE *stream, const char *format[,argment,...]);
int fprintf(FILE *stream, const char *format[,argment,...]);
stream : 화일 스트림
format : 출력 형식
argment: 출력할 데이터
format : 출력 형식
argment: 출력할 데이터
리턴값 : EOF = 에러 발생
이외 = 출력된 바이트 수
이외 = 출력된 바이트 수
[예] fprintf(stream, "%d %c %f", i, c, f);
------ -------- -----
| | |
| | 전달 데이터
| 출력 형식
출력할 화일 스트림
------ -------- -----
| | |
| | 전달 데이터
| 출력 형식
출력할 화일 스트림
- fputs() 함수의 내용은 다음과 같다.
화일에 문자열을 출력한다.
#include <stdio.h>
int fputs(const char *s, FILE *stream);
int fputs(const char *s, FILE *stream);
s : 스트림에 출력할 문자열의 포인터
stream : 화일 스트림
stream : 화일 스트림
- fscanf() 함수의 내용은 다음과 같다.
스트림에서 형식지정된 내용을 읽는다.
#include <stdio.h>
int fscanf(FILE *stream, const char *format[,argment,...]);
int fscanf(FILE *stream, const char *format[,argment,...]);
stream : 화일 스트림
format : 출력 형식
argment: 출력할 데이터
format : 출력 형식
argment: 출력할 데이터
리턴값 : EOF = 화일의 끝
이외 = 입력된 항목의 수
이외 = 입력된 항목의 수
[예] fscanf(stream, "%d %c %f", &i, &c, &f);
---- ------- -------
| | |
| | 입력 데이터 저장 포인터
| 입력 형식
읽어올 화일 스트림
---- ------- -------
| | |
| | 입력 데이터 저장 포인터
| 입력 형식
읽어올 화일 스트림
- fgetc() 함수의 내용은 다음과 같다.
스트림에서 한 문자 읽기
#include <stdio.h>
int fgetc(FILE *stream);
int fgetc(FILE *stream);
stream : 화일 스트림
리턴값 : EOF = 에러 발생 또는 EOF
이외 = 읽은 문자
이외 = 읽은 문자
- fputc() 함수의 내용은 다음과 같다.
스트림에 한 문자 출력하기
#include <stdio.h>
int fputc(int c, FILE *stream);
int fputc(int c, FILE *stream);
c : 출력할 문자
stream : 화일 스트림
stream : 화일 스트림
리턴값 : EOF = 에러 발생
이외 = 출력한 문자
이외 = 출력한 문자
10.4.3 화일 닫기 (CLOSE)
fclose() 함수를 이용하여 화일을 닫는다. fclose() 함수에 대한 내용은 다음과 같다.
#include <stdio.h>
int close(FILE *stream);
stream: 작업 스트림 포인터
리턴값: 0 = 화일이 정상적으로 닫힘
EOF = 에러 발생
EOF = 에러 발생
10.5 응용 예제
1. 실행 화일의 인자를 화일이름으로 받아 복사하는 프로그램
#include "stdio.h"
#define BUF 512
void main(int argc, char **argv)
{
int fsrc, fdest, bytes;
char buf[BUF];
{
int fsrc, fdest, bytes;
char buf[BUF];
fsrc = open(*++argv, 0);
fdest = creat(*++argv, 1);
fdest = creat(*++argv, 1);
while (bytes = read(fsrc, buf, BUF))
{
write(fdest, buf, bytes);
}
{
write(fdest, buf, bytes);
}
close(fsrc);
close(fdest);
}
close(fdest);
}
2. 키보드의 입력문자를 test.doc 화일에 저장하는 프로그램
(입력 끝 = Ctrl-Z 누름)
(입력 끝 = Ctrl-Z 누름)
#include "stdio.h"
#define FILE_NAME "test.doc"
FILE * fopen();
void main(void)
{
FILE *fdest;
int c;
{
FILE *fdest;
int c;
fdest = fopen("text.c", "w");
while ((c = getc(stdin)) != EOF)
putc(c, fdest);
putc(c, fdest);
fclose(fdest);
}
}
3. test.doc 화일을 읽어서 화면에 출력하는 프로그램
#include "stdio.h"
#define FILE_NAME "test.doc"
FILE * fopen();
void main(void)
{
FILE *fsrc;
int c;
{
FILE *fsrc;
int c;
fsrc = fopen(FILE_NAME, "r");
while ((c = getc(fsrc)) != EOF)
putc(c, stdout);
putc(c, stdout);
fclose(fsrc);
}
}
[출처] 12. 화일 입.출력 (이슬림라이트) |작성자 로이
'컴퓨터 > 언어,프로그래밍' 카테고리의 다른 글
[C언어] 문자열 함수 정리 (0) | 2009.05.27 |
---|---|
유닉스 중에 #define FILE_NAME 0644 의미가 뭐죠? (0) | 2009.05.27 |
파일 디스크립터를 출력으로 지정( creat, dup2) (0) | 2009.05.27 |
hole있는 파일 생성(creat, write, lseek) (0) | 2009.05.27 |
운영체제(유닉스)에서 open()과 read()함수의 소스코드 (0) | 2009.05.27 |