C-Language/File IO
File IO in C language
Soul-Learner
2016. 11. 15. 23:39
C 언어에서 텍스트 파일 다루기 예
C 언어에서 텍스트파일이나 바이너리 파일을 생성하고 읽고 쓰는 방법을 알아보고자 한다
FILE 구조체는 파일을 읽고 쓰기위한 모든 정보를 가지고 있는데, fopen() 함수를 이용하여 파일경로를 전달하면 해당 파일에 대한 FILE 구조체를 얻을 수 있고 이 구조체를 이용하여 파일에 대한 모든 작업을 수행할 수 있다
파일을 열고 닫는 함수
FILE *fopen( const char * filename, const char * mode );
int fclose( FILE *fp ); 성공시 0, 실패시 EOF 리턴(EOF는 stdio.h에 선언됨)
텍스트 파일 입출력 모드 ( OS에 따라서 개행문자가 다르므로 윈도우의 텍스트 파일에서 \r\n을 읽어올 때 \n으로 변환해주고, 파일에 저장할 때는 텍스트에 포함된 개행문자 \n를 \r\n으로 변환하여 저장하는 기능이 지원된다).
바이너리 모드에서는 이러한 변환기능이 전혀 작동하지 않는다
이미지 데이터를 텍스트 모드('w')로 파일에 쓰는 경우에는 '\n'이 '\r\n' 으로 변환되어 저장되므로 생성된 파일의 크기가 원본보다 더 커지는 문제가 발생할 수도 있다. 참고로, '\n'은 아스키코드 10에 해당하고, '\r' 은 13에 해당한다
- r : read only
- w : writing (파일이 없으면 생성됨, 기존 내용을 지우고 기록함)
- a : append text (파일이 없으면 생성됨, 기존 내용 다음에 기록함)
- r+ : read & write text (파일이 없어도 생성하지 않음, 기존 내용을 지우지 않음)
- w+ : read & write text(파일이 없으면 생성됨, 기존 내용 지우고 기록함)
- a+ : append text, read (파일이 없으면 생성됨, 기존 내용 다음에 기록함, 읽기는 처음부터)
읽기/쓰기를 동시에 하는 모드 ("r+", "w+", "a+") 의 경우, 읽기 작업을 한 후, 쓰기 작업을 하거나, 쓰기 작업을 한 후 읽기작업을 하는 경우 중간에 반드시 스트림을 비우거나 (fflush), 위치가 조정 되어야 한다.
바이너리 파일 입출력 모드(입출력시에 OS의 개행문자에 따라 자동변환 기능이 작동하지 않는다)
텍스트가 아닌 바이너리 파일에 위의 모드를 적용할 때는 다음과 같은 표현을 사용한다
"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"
파일에 텍스트를 기록하는 함수
- int fputc( int c, FILE *fp ); 파일에 한개의 문자 기록하고 해당 문자를 정수로 리턴한다 실패시 EOF 리턴
- int fputs( const char *s, FILE *fp ); 파일에 문자열을 기록하고 음수가 아닌 정수를 리턴한다. 실패시 EOF 리턴
- int fprintf(FILE *fp,const char *format, ...); 파일에 형식화된 문자열을 기록한다.
파일로부터 텍스트를 읽어오는 함수
int fgetc( FILE * fp ); 파일로부터 한개의 문자를 읽어서 정수로 리턴한다. 실패시 EOF 리턴
char *fgets( char *buf, int n, FILE *fp ); : 지정한 크기( n-1)만큼 문자열을 읽어서 지정된 버퍼에 저장하고 끝에 null 문자를 추가한다
fgets 함수는 읽는 도중에 \n 를 만나면 \n를 포함하여 읽어오고, EOF를 만나면 그 전까지 읽어온다
int fscanf(FILE *fp, const char *format, ...) : 파일로부터 읽어올 때 지정된 자료형에 따라 공백문자 전까지만 읽어온다.
바이너리 파일을 읽고 쓰는 함수
size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
기능 : 파일로부터 바이너리 데이터를 읽어와서 ptr에 저장하고 읽어온 총 바이트 수를 리턴한다. 리턴된 수와 number_of_elements 가 다르면 오류이거나 EOF 이다
- ptr : 읽어온 데이터를 저장할 주소
- size_of_elements : 한번에 읽어올 데이터 량
- number_of_elements : 읽어올 총 회수
- a_file : 데이터를 읽어올 파일 포인터
size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
기능 : 파일에 바이너리 데이터를 기록하고 성공한 총 바이트 수를 리턴한다. 리턴된 수와 number_of_elements 가 다르면 오류를 의미한다
- ptr : 데이터 소스의 주소
- size_of_elements : 한번에 기록할 데이터의 량
- number_of_elements : 기록할 총 회수
- a_file : 데이터가 저장될 파일 포인터
텍스트 파일을 읽고 쓰는 예
#include <stdio.h> int main() { // 파일에 쓰기 FILE *fp = fopen("C:\\test\\sample.txt", "w"); if (!fp) { printf("파일열기 실패 \n"); return 0; } fputc('A', fp); fputc('\n', fp); fputs("Hello everyone\n", fp); fprintf(fp, "%s \n", "서식화 문자열"); fclose(fp); printf("파일에 쓰기 성공 \n"); // 파일 읽기 fp = fopen("C:\\test\\sample.txt", "r"); char buf[100]; int ch = fgetc(fp); printf("읽어온 문자=%c \n", ch); fgets(buf, 100, fp); // 파일 내의 현재의 행에 남아 있는 개행문자까지 읽어온다(버림) fgets(buf, 100, fp); // 다음 행 전체를 \n 포함하여 읽어온다 printf("읽어온 문자열=%s", buf); fscanf(fp, "%s", buf); // 다음 행에서 첫번째 공백 전까지 읽어온다 printf(buf); fscanf(fp, "%s", buf); // 두번째 공백 전까지 읽어온다 printf("%s \n", buf); fclose(fp); return 0; }
바이너리 모드('rb', 'wb')와 fgetc() 함수를 사용하여 이미지 파일을 복사하는 예
#include <stdio.h> int main() { FILE *source, *target; int i; source = fopen("C:\\test\\dog.png", "rb"); if (source == NULL) { printf("파일 열기 실패\n"); return 0; } fseek(source, 0, SEEK_END); int length = ftell(source); fseek(source, 0, SEEK_SET); target = fopen("C:\\test\\dogCpy.png", "wb"); if (target == NULL) { fclose(source); return 0; } for (i = 0; i < length; i++) { fputc(fgetc(source), target); } printf("파일복사 성공.\n"); fclose(source); fclose(target); return 0; }
이미지를 복사할 때 바이너리 모드('rb', 'wb')와 fread(), fwrite()함수를 사용하는 예
#include <stdio.h> int main() { FILE *source, *target; int i; source = fopen("C:\\test\\dog.png", "rb"); if (source == NULL) { printf("파일 열기 실패\n"); return 0; } fseek(source, 0, SEEK_END); int length = ftell(source); fseek(source, 0, SEEK_SET); target = fopen("C:\\test\\dogCpy.png", "wb"); if (target == NULL) { fclose(source); return 0; } unsigned char data = 0; for (i = 0; i < length; i++) { fread(&data, 1, 1, source); fwrite(&data, 1, 1, target); } printf("파일복사 성공.\n"); fclose(source); fclose(target); return 0; }
텍스트 파일에서 한행씩 파일 끝까지 읽어와서 토큰으로 분리하여 화면에 출력하는 예
#include <stdio.h> #include <stdlib.h> // atoi() #include <string.h> // strtok() #pragma warning(disable:4996) typedef struct User { int num; char name[16]; char email[32]; } user; int main() { char buf[32]; char tmp[32]; user user1 = { 0 }; FILE* f = fopen("C:\\test\\users.txt", "r"); while (1) { char* line = fgets(buf, 31, f); // 개행문자를 포함하여 읽어온다 if (line == NULL) break; line = strtok(line, "\n"); // 개행문자가 제거된 문자열을 얻는다 char* pnum = strtok(line, "|"); char* pname = strtok(NULL, "|"); char* pemail = strtok(NULL, "|"); user1.num = atoi(pnum); strcpy(user1.name, pname); strcpy(user1.email, pemail); printf("%d, %s, %s \n", user1.num, user1.name, user1.email); } return 0; }