-
C언어 기초#13 스트림과 파일 입출력 printf scanf 심화, fopen(), fclose(), 이진 파일 읽고 쓰기, 버퍼링, fseek(), rewind(), ftell(), foef()Programming 기초/C Language 2023. 5. 3. 19:20
* 스트림(stream)
- 스트림이란 모든 입력과 출력을 바이트(byte)들의 흐름으로 생각하는 것.
- 장점 : 장치 독립성. 입출력 장치에 상관없이 프로그램을 작성할 수 있다.
- 특징 : 버퍼(buffer) 사용. cpu의 속도가 입출력 장치보다 훨씬 빠르기 때문에 버퍼에 어느 정도 데이터가 쌓이면 cpu가 한 번에 데이터를 가져간다. 출력도 마찬가지.
* 표준 입출력 스트림(standard input/output stream)
프로그램이 시작될 때 자동으로 만들어지고, 프로그램이 종료될 때 자동으로 소멸된다.
이름 스트림 연결 장치 관련 함수 예시 stdin 표준 입력 스트림 키보드 scan() stdout 표준 출력 스트림 모니터의 화면 printf() stderr 표준 오류 스트림 모니터의 화면 fprintf(stderr) * printf() 출력
- 표준 출력 스트림(콘솔)에 데이터를 출력한다.
- 형식 제어 문자열
% [플래그] [필드폭] [.정밀도] 형식
// 필수적인 것은 '형식'뿐.1.플래그(flag) : 하나의 문자로서 출력의 정렬과 부호 출력, 공백 출력, 8진수와 16진수 접두사 출력 등을 지시한다
printf("%010d", 123); // 출력: 0000000123 , 빈칸 대신에 0을 출력 printf("%+d", 123); // 양수이면 +를 붙인다. printf("%#x", 0x10); // 앞에 0, 0x을 출력한다. ...
2. 필드폭(width)
- 데이터가 출력되는 필드의 크기를 지정. %10d라고 하면 필드폭은 10문자 크기가 된다.
- 기본 오른쪽 정렬.
- 데이터의 크기가 필드보다 크면 필드폭은 자동으로 넓어지게 된다.
printf("%10d", 123); // 우측정렬 printf("-%10d", 123); // 좌측정렬 printf("-%10d", -123); // 좌측정렬
3. 정밀도(precision)
- %e, %E, %f를 사용하여 실수를 출력할 때 소수점 이하의 자릿수의 개수를 정함.
- 기본 소수점 이하 6자리로 출력
- 기본좌측 정렬.
printf("%-10.3f", 1.23456789); //출력 : 1.234 좌측정렬
4. 형식
%d, %i(부호 있는 10진수), %e(지수 표기법), %p(포인터 형식) 등등.
* scanf()를 이용한 입력
- 표준 입력 스트림(키보드)에서 데이터를 입력한다. 읽은 항목의 수를 반환한다.
- scanf()가 반환하는 값은 읽은 항목의 개수이다. 사용자가 값을 몇 개나 성공적으로 입력하였는지를 검사할 수도 있다.
if(scanf("%d%d%d", &x, &y, &z) ==3) ... // scanf()가 반환한 올바르게 읽은 값의 개수가 3개이면 if문이 실행된다.
- fflush()의 사용
scanf()를 사용하여서 입력을 처리할 때 이전에 입력되었던 값들이 버퍼에 남아 있을 때 등, 입력 버퍼를 강제로 비우고자 할 때 사용된다.
fflush(stdin); // 입력 버퍼를 비운다.
* 파일의 개념
파일도 스트림으로 취급되기 때문에 파일도 일련의 연속된 바이트라고 생각하면 된다.
모든 파일은 입출력 동작이 발생하는 현재 위치를 나타내는 파일 포인터(file pointer)를 가지고 있다. 파일을 처음으로 열면 파일 포인터는 파일의 첫 번째 바이트를 가리킨다. 입출력 연산이 진행되면 파일 포인터가 자동적으로 이동된다.
* 파일의 유형
- C에서는 텍스트 파일(text file)과 이진 파일(bianery file)의 두 가지 파일 유형을 지원한다.
- 텍스트 파일에서는 모든 정보가 문자열로 변환되어서 파일에 기록되었다.
- 이진 파일은 데이터가 이진수 형태로 저장되어 있는 파일이다. (가독성과 이식성이 떨어지고 저장효율성과 가용성이 좋음)
* 파일 열기
형식 : FILE *fopen(const char *name,const char *mode)
설명 : name이라는 이름을 가지는 파일을 mode에 지정된 모드로 연다. FILE 포인터를 변환한다.
예 : FILE *fp;
fp = fopen("test.txt", "w");- fopen()
- fopen()은 주어진 파일 이름을 가지고 파일을 생성하여 이 파일을 가리키는 FILE 포인터를 반환한다.
- FILE은 stdio.h에 typedef를 이용하여 선언된 구조체 자료형이다.
-읽기 모드
모드 설명 "r" 읽기 모드로 파일을 연다. 만약 파일이 존재하지 않으면 오류가 발생한다. "w" 쓰기 모드로 새로운 파일을 생성한다. 파일이 이미 조재하면 기존의 내용이 지워진다. "a" 추가 모드로 파일을 연다. 만약 기존의 파일이 있으면 데이터가 파일의 끝에 추가된다. 파일이 없으면 새로운 파일을 만든다. "r+" 읽기 모드로 파일을 연다. 쓰기 모드로 전환할 수 있다. 파일이 반드시 존재하여야 한다. "w+" 쓰기 모드로 새로운 파일을 생성한다. 읽기 모드로 전환할 수 있다. 파일이 이미 존재하면 기존의 내용이 지워진다. "a+" 추가 모드로 파일을 연다. 읽기 모드로 전환할 수 있다. 데이터를 추가하면 EOF 마커를 추가된 데이터의 뒤로 이동한다. 파일이 없으면 새로운 파일을 만든다. "t" 텍스트 파일 모드로 파일을 연다. "b" 이진 파일 모드로 파일을 연다. - "a"나 "a+"모드는 추가모드(append mode)라고 한다.
- "r+", "w+", "a+" 파일 모드가 지정되면 읽고 쓰기가 모두 가능하다. 이러한 모드를 수정 모드(update mode)라고 한다. 그러나 모드 전환시 반드시 fflush(), fsetpos(), fseek(), rewind() 중의 하나를 호출하여야 한다.
* 파일 닫기
성공적으로 파일을 닫는 경우에는 0이 반환된다. 만약 실패한 경우에는 -1이 반환된다.
형식 : int fclose(FILE *stream);
설명 : stream에 의하여 지정된 파일을 닫는다.
예 : FILE *fp;
fp = fopen("test.txt", "w");
fclose(fp):#include<stdio.h> int main(void) { FILE *fp = NULL; // FILE을 가리키는 포인터 fp를 선언 fp = fopen("sample.txt", "w"); if(fp == NULL) printf("파일 열기 실패\n"); else printf("파일 열기 성공\n"); fclose(fp); // fopen()을 호출하였으면 반드시 fclose()를 호출하여 파일을 닫아야 한다. return 0; }
* 파일의 삭제
stdio.h에 정의된 라이브러리 함수, remove()를 사용한다. 성공시 0 반환, 실패시 -1 반환.
* 이진 파일 쓰기
이진 파일을 생성하려면 fopen()을 호출할 때 파일 모드에 "b"를 붙이면 된다.
파일 모드 설명 "rb" 읽기 모드 + 이진 파일 모드 "wb" 쓰기 모드 + 이진 파일 모드 "ab" 추가 모드 + 이진 파일 모드 "rb+" 읽고 쓰기 모드 + 이진 파일 모드 "wb+" 쓰고 읽기 모드 + 이진 파일 모드 - 이진 파일 출력은 메모리 블록에 있는 데이터를 디스크 파일로 직접 저장한다.
- fwrite()는 실제 저장한 항목의 수를 반환한다.
fwrite(buffer, sizeof(int), SIZE, fp);
/*
buffer - 파일에 기록할 데이터를 가지고 있는 메모리 블록의 시작 주소
sizeof(int) - 항목의 크기로서 단위는 바이트
SIZE - 항목의 개수
*/* 이진 파일 읽기
fread(buffer, sizeof(int), SIZE, fp);
* 버퍼링
스트림에는 기본적으로 버퍼(buffer)가 포함되어 있다.
버퍼는 파일로부터 읽고 쓰는 데이터의 임시 저장 장소로 이용되는 메모리의 블록이다.
장치나 파일을 직접적으로 제어할 필요가 있는 경우라든지 많은 양의 이진 데이터를 쓰거나 읽을 경우에는 오히려 버퍼가 없는 편이 편하다. 버퍼 제거 함수인 setbuf()함수를 사용한다.
일반적으로 버퍼가 없는 입출력의 경우, 입력과 출력을 할 때마다 시스템 호출이 필요하므로 속도가 매우 느려지고 비효율적이다.
setbuf(fp, NULL);
// 스트림의 버퍼를 지정하는 함수로서 만약 버퍼 자리에 NULL을 써주면 버퍼를 제거하겠다는 것을 의미한다.* 순차 접근(sequential access)
지금까지의 파일 입출력 방법은 모두 데이터를 파일의 처음부터 순차적으로 읽거나 기록하는 것이었다. 이것을 순차 접근방법이라고 한다.
순차 접근 방법은 앞부분을 읽지 않고 중간이나 마지막으로 건너뛸 수 없다.
* 임의 접근(random access)
파일에서 읽기나 쓰기가 수행되면 파일 포인터가 갱신된다. 예를 들어 읽기 모드로 파일을 열고, 100바이트를 읽었다면 파일 포인터의 값이 100이 된다. 다음에 다시 200바이트를 읽었다면 파일 포인터는 300이 된다.
데이터를 임의의 위치에서 읽기 위해선 위치 표시자를 조작해야한다. 위치 표시자를 조작하는 함수는 fseek()이다.
* fseek()
위치 표시자를 보다 정밀하게 제어할 수 있다. fseek()는 위치 표시자의 값을 원하는 값으로 설정한다.
성공하면 0을 반환하고 실패한 경우네느 0이 아닌 값을 반환한다.
파일이 열렸을 경우, 파일 포인터의 초기값은 0이다.
int fseek(FILE *fp, long offset, int origin);
- fp는 FILE에 대한 포인터이다.
- offset은 기준 위치로부터 위치 표시자가 이동하는 거리를 나타낸다. long형이므로 정수 상수를 인수로 사용하는 경우네는 3000L처럼 L을 붙이는 것이 좋다. 양수이면 앞으로, 음수이면 뒤로 간다.
- origin은 위치 표시자를 이동시키는 기준 위치를 나타낸다. origin에는 다음과 같은 값 중에서 하나를 사용할 수 있다.
상수 값 설명 SEEK_SET 0 파일의 시작 SEEK_CUR 1 현재 위치 SEEK_END 2 파일의 끝 fseek(fp, 0L, SEEK_SET); // 파일의 처음으로 이동 fseek(fp, 0L, SEEK_END); // 파일의 끝으로 이동 fseek(fp, 50L, SEEK_CUR); // 현재 위치에서 50바이트 이동 fseek(fp, -20L, SEEK_END); // 파일의 끝에서 20바이트 앞으로 이동 fseek(fp, sizeof(struct element), SEEK_SET); // 구조체만큼 앞으로 이동
* rewind()
- 주로 파일을 읽은 다음, 다시 읽고자 할 때 사용된다.
- rewind()가 호출되면 위치 표시자가 0으로 설정된다.
void rewind(FILE *fp)
* ftell()
- 위치 표시자의 현재 위치를 알아내고자 할 때 사용된다.
- long형으로 반환하는 이유는 파일이 클 때 위치 표시자의 값이 long형으로만 표시되 수 있기 때문이다.
- 오류가 발생하면 -1L을 반환한다.
long ftell(FILE *fp)
* feof()
현재 위치가 파일의 끝인지 알려주는 함수이다.
이진 파일인 경우 -1 값이 파일의 끝을 알려주지 않기 때문에 필요하다.
int feof(FILE *fp)
'Programming 기초 > C Language' 카테고리의 다른 글
C언어 기초#14 동적 메모리와 연결 리스트 (0) 2023.05.03 C언어 기초#12 전처리 및 비트 필드 (0) 2023.04.28 C언어 기초#11 이중포인터, 함수포인터, 배열포인터, void포인터 (0) 2023.04.18 C언어 기초#10 구조체와 포인터, 공용체(union), 열거형(enum), typedef (0) 2023.04.15 C언어 기초#9 문자열(string) (0) 2023.04.13