학습한 파일 입출력 함수들
int fputc(int c, FILE * stream); // 문자 출력
int fgetc(FILE * stream); // 문자 입력
int fputs(const char * s, FILE * stream); // 문자열 출력
char * fgets(char * s, int n, FILE * stream); // 문자열 입력
당시에는 위 함수들의 두 번째 또는 세 번째 매개변수 stream에 표준 입출력을 의미하는 stdin이나 stdout을 인자로 전달함으로써 키보드와 모니터를 대상으로 입출력을 진행하였다.
예제.
#include <stdio.h>
int main(void)
{
FILE* fp = fopen("simple.txt", "wt");
if (fp == NULL) {
puts("파일오픈 실패!");
return -1; // 비정상적인 종료를 의미 -1 반환
}
fputc('A', fp);
fputc('B', fp);
fputs("My name is hi \n", fp);
fputs("Your name is hi \n", fp);
fclose(fp);
return 0;
}
문자열을 출력하고 있음, 그 문자열에는 개행문자.
따라서 텍스트 모드로 파일을 개방해야 함.
저장된 데이터 읽어오기 예제
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
char str[30];
int ch;
FILE* fp = fopen("simple.txt", "rt");
if (fp == NULL) {
puts("파일오픈 실패!");
return -1; // 비정상적인 종료를 의미 -1 반환
}
ch = fgetc(fp);
printf("%c \n", ch);
ch = fgetc(fp);
printf("%c \n", ch);
fgets(str, sizeof(str), fp);
printf("%s", str);
fgets(str, sizeof(str), fp);
printf("%s", str);
fclose(fp);
return 0;
}
출력한 문자열의 형태가 다음과 같음.
문자열의 끝에 \n이 존재한다는 것.
"My name is hi \n"
"Your name is hi \n"
문자열이 파일에 저장될 때에는 문자열의 끝을 의미하는 널 문자는 저장되지 않는다.
때문에 파일에서는 개행을 기준으로 문자열을 구분한다.
위 코드를 보면 총 두개의 문자열을 읽어들이기 위해서 fgets 함수를 두 번 호출했는데, 매번 호출이 될 때마다 개행 문자를 만날 때까지 문자열을 읽어 들이게 된다.
따라서 fgets 함수의 호출을 통해서 읽어 들일 문자열의 끝에는 반드시 \n 문자가 존재해야 한다.
feof 함수 기반의 파일복사 프로그램
때로는 파일의 마지막에 저장된 데이터까지 모두 읽어 들어야 하는 상황이 존재한다.
그리고 이를 위해서는 파일의 끝을 확인하는 방법이 필요. 이러한 목적으로 정의된 함수
#include <stdio.h>
int feof(FILE * stream);
- 파일의 끝에 도달한 경우 0이 아닌 값 반환
이 함수는 인자로 전달된 FILE 구조체의 포인터를 대상으로, 더 이상 읽어 들일 데이터가 존재하지 않으면(파일의 끝까지 모두 읽어 들인 상태이면) 0이 아닌 값을 반환한다.
따라서 다음의 파일복사 프로그램과 같이 파일의 끝을 확인해야 하는 경우에 유용하게 사용이 된다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
FILE* src = fopen("src.txt", "rt"); // 당연히 src.txt 파일이 있어야겠쥬?
FILE* des = fopen("dst.txt", "wt");
int ch;
if (src == NULL || des == NULL) {
puts("파일오픈 실패!");
return -1;
}
while ((ch = fgetc(src)) != EOF)
fputc(ch, des);
if (feof(src) != 0) // feof -> 파일의 끝에 도달한 경우 0이 아닌 값을 반환
puts("파일복사 완료!");
else
puts("파일복사 실패!");
fclose(src);
fclose(des);
return 0;
}
문자열 단위 복사 예제
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
FILE* src = fopen("src.txt", "rt"); // 당연히 src.txt 파일이 있어야겠쥬?
FILE* des = fopen("dst.txt", "wt");
int str[20];
if (src == NULL || des == NULL) {
puts("파일오픈 실패!");
return -1;
}
while (fgets(str, sizeof(str), src)!=NULL)
fputs(str, des);
if (feof(src) != 0) // feof -> 파일의 끝에 도달한 경우 0이 아닌 값을 반환
puts("파일복사 완료!");
else
puts("파일복사 실패!");
fclose(src);
fclose(des);
return 0;
}
fgets 함수는 파일의 끝에 도달해서 더 이상 읽을 데이터가 존재하지 않거나 오류가 발생하는 경우에 NULL을 반환한다.
때문에 이 예제에서도 파일복사의 성공을 확인하기 위해서 feof 함수를 호출하였다.
바이너리 데이터의 입출력: fread, fwrite
바이너리 데이터의 입력에 사용되는 fread 함수
#include <stdio.h>
size_t fread(void * buffer, size_t size, size_t count, FILE * stream);
- 성공 시 전달인자 count, 실패 또는 파일의 끝 도달 시 count보다 작은 값 반환
int buf[12];
fread((void*)buf, sizeof(int), 12, fp); // fp는 FILE 구조체 포인터
"sizeof(int) 크기의 데이터 12개를 fp로부터 읽어 들여서 배열 buf에 저장하라!"
즉, fread 함수는 두 번째 전달인자(sizeof(int))와 세 번째 전달인자(12)의 곱(sizeof(int) * 12)의 바이트 크기만큼 데이터를 읽어 들이는 함수.
위의 fread 함수호출을 통해서 int형 데이터 12개를 fp로부터 읽어서 배열 buf에 저장하게 된다.
위 함수는 실제로 읽어 들인 데이터의 갯수를 반환하는데(읽어 들인 바이트 수가 아니라 갯수)
위 문장은 sizeof(int) 크기의 데이터를 12개 읽어 들이는 경우이니, 함수의 호출이 성공을 하고 요청한 분량의 데이터가 모두 읽혀지면 12가 반환된다.
반면, 함수의 호출이 성공을 했지만 파일의 끝에 도달을 해서 12개를 모두 읽어 들이지 못했거나 오류가 발생하는 경우에는 12보다 작은 값이 반환된다.
바이너리 데이터의 출력에 사용되는 fwrite 함수
#include <stdio.h>
size_t fwrite(const void * buffer, size_t size, size_t count, FILE * stream);
- 성공 시 전달인자 count, 실패 시 count보다 작은 값 반환
int buf[12] = {1, 2, 3, 4, 5, 6, 7};
fwrite((void*)buf, sizeof(int), 7, fp);
"sizeof(int) 크기의 데이터 7개를 buf로부터 읽어서 fp에 저장해라!"
fread와 fwrite를 사용한 예제
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void)
{
FILE* src = fopen("src.bin", "rb");
FILE* des = fopen("dst.bin", "wb");
char buf[20];
int readCnt;
if (src == NULL || des == NULL) {
puts("파일오픈 실패!");
return -1;
}
while (1)
{
readCnt = fread((void*)buf, 1, sizeof(buf), src);
if (readCnt < sizeof(buf))
{
if (feof(src) != 0)
{
fwrite((void*)buf, 1, readCnt, des);
puts("파일복사 완료");
break;
}
else
puts("파일복사 실패");
break;
}
fwrite((void*)buf, 1, sizeof(buf), des);
}
fclose(src);
fclose(des);
return 0;
}
참고 : [윤성우 열혈 C 프로그래밍] - 대부분의 내용 및 코드는 이 책에서 개인 공부 정리 목적으로 참고하였습니다.
'Language&Framework&Etc > C' 카테고리의 다른 글
파일 입출력(24-5) 임의 접근을 위한 '파일 위치 지시자'의 이동 (0) | 2020.12.17 |
---|---|
파일 입출력(24-4) 텍스트 데이터와 바이너리 데이터를 동시에 입출력 하기 (0) | 2020.12.17 |
파일 입출력(24-2) 파일의 개방 모드(Mode) (0) | 2020.12.14 |
파일 입출력(24-1) 파일과 스트림(Stream), 그리고 기본적인 파일의 입출력 (0) | 2020.12.14 |
구조체와 사용자 정의 자료형2(23-5) 열거형(Enumerated Type)의 정의와 의미 (0) | 2020.12.14 |