C언어 : 파일 입출력(2)

지환·2022년 2월 3일
1

C언어

목록 보기
34/37
post-thumbnail

파일 입출력 2번 째 글이다. 이번엔 텍스트 파일에 데이터를 읽고 쓰는 것에 대해 다룰 예정이다.

1. fprintf

  • 화면에 문자 또는 숫자를 출력하고 싶으면 printf 함수를 사용한다.
  • 첫 매개변수를 파일 포인터를 받아서, 출력할 문자열을 파일에 저장한다.
  • "bcd"를 출력하고 싶으면, fprintf(파일 포인터, "bcd") 라고 출력
int fprintf(FILE *stream, const char *format [, argument]...);
함수 사용 형식 : fprintf(파일 포인터, 파일에 입력할 문자열 형식, 출력할 값들);
ex: 
fprintf(p_file, "hallo\n"); 파일에 hallo 문자열을 쓰고 줄 바꿈을 한다.

<fprintf 함수를 이용해서 파일에 "hello" 문자열을 저장하자>

#include <stdio.h>

int main()
{

	FILE* p_file = fopen("파일입출력.txt", "wt");
	if (NULL != p_file)
	{
		fprintf(p_file, "hello\n");
		fclose(p_file);
	}

}

<결과>

텍스트 파일에서 문자열 읽기 : fscanf 함수

함수 원형 : int fscanf(FILE stream, const char format[, argument]...)
함수 사용 형식 : fscanf(파일 포인터, 파일에서 데이터를 입력 받을 형식, 입력 받을 변수 목록)

ex:

int data;
fscanf(p_file, "%d", &data);

텍스트 파일에서 한 줄 단위로 문자열 읽기 : fgest 함수

함수 원형 : char *fgets(char *stirng, int n, FILE *stream);
함수 사용 형식 : fgets(파일에서 읽은 문자열을 저장할 메모리의 주소, 첫 번째 매개변수로 사용한 메모리의 크기, 파일 포인터);

ex : 
char temp[54];
fgets(temp, sizeof(temp), p_file);

<fgets 함수로 문자열을 줄 단위로 모두 읽어 오기>

void main()
{
	char temp[64];
	FILE* p_file = fopen("파일입출력.txt", "rt");
	if (NULL != p_file)
	{
		while (NULL != fgets(temp, sizeof(temp), p_file)) 
		{
			printf("%s", temp);
		}
		fclose(p_file);
	}

}

<결과>

  • fscanf 함수는 줄 바꿈뿐만 아니라 공백 문자 입력도 구별한다.
    1. fscanf 함수는 EOF 문자를 만나면 EOF를 반환한다.
    2. fscanf 함수는 읽은 문자열에서 \n을 제외
  • fgets 함수는 입력의 구분을 줄 바꿈으로만 판단하기 때문에 파일에 저장된 문자열을 한 줄 단위로 읽어 온다.
    1.fgets 함수는 EOF 문자를 만나면 null 반환한다.
    2.fgets 함수는 \n을 문자열에 포함시킨다.

바이너리 파일에 데이터 읽고 쓰기

  • 문자열 속성은 문자열에 포함한 NULL 문자 0을 찾아서 데이터 크기를 체크한다. 그렇기 때문에 문자열 길이를 추가로 적을 필요가 없다.
    예를 들어) "BCD"문자열이 있으면 데이터 크기가 3이라는 것을 알 수 있다.
  • 바이너리 속성은 데이터를 숫자로만 판단하기 때문에 표준 입출력 함수가 데이터를 분석해서 길이나 크기를 알아 낼 수 없다.
  • 바이너리 속성은 프로그래머가 직접 값을 입력해야한다.

바이너리 파일에 데이터 저장하기 : fwrite 함수

<함수 원형>
size_t fwrite(const void *butter, size_t size, size_t count, FILE *stream);
<사용 형식>
fwrite(저장할 데이터의 시작주소, 저장할 데이터의 기준 단위 크기, 반복 횟수, 파일 포인터)

예를 들어 : int형 변수 data에 저장되어 있는 16진수 값을 파일에 저장하고 싶으면 이와 같이 하면된다.

int data = 0x00000412;
fwrite(&data, sizeof(int), i, p_file)

<fwrite 함수로 바이너리 파일에 int형 변수 값 저장하기>

#include <stdio.h>

void main()
{
	int data = 0x0000012;
	FILE* p_file = fopen("파일입출력.dat", "Wb");
	fwrite(data, sizeof(int), 1, p_file); //여기서 data의 의미는 &data[0] 시작주소를 의미한다. 
	// 세 번째 매개변수는 주로 반복횟수를 의미한다. 
	// fwrite(data, sizeof(int) * 5, 1, p_file); sizeof는-단위크기 // 1은 반복횟수다. 
	fclose(p_file);

}
  • fwrite 함수를 사용해서 데이터를 저장하면, 파일 포인터가 가리키는 정보 중에서 '파일 내부 데이터를 읽거나 쓰기 시작하는 위치'가 데이터를 저장한(단위크기 x 횟수) 크기만큼 자동으로 증가한다.
  • 따라서 파일에 데이터를 저장한 만큼 이동하는 함수를 추가 할 필요가 없다.
  • 파일 포인터는 파일의 현재 사용 상태를 나타내는 메모리의 주소를 나타낸다.
#include <stdio.h>

void main()
{
	int data = 100, data_list[5] = { 0,1,2,3,4 };
	FILE* p_file = fopen("파일입출력.dat", "wb");
	if (NULL != p_file)
	{
		fwrite(&data, sizeof(int), 1, p_file);
		fwrite(data_list, sizeof(int), 5, p_file);
		fclose(p_file);
	}
}

바이너리 파일에서 데이터 읽기 : fread 함수

<함수 원형>
size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
<사용 형식>
fread(읽은 데이터를 저장할 주소, 저장할 데이터의 기준 단위 크기, 반복 횟수, 파일 포인터);

예를 들어 파일에 저장되어 있는 데이터를 읽어서 int형 변수 data에 저장하고 싶으면 다음과 같이 구성한다.

int data;
fread(&data, sizeof(int), 1, p_file);
//p_file이 가리키는 파일에서 4바이트 크기만큼 1회만 데이터를 읽어 와서 data 변수에 저장한다.
  • p_file 파일 포인터가 가리키는 바이너리 파일에서 4바이트 크기로 데이터로 읽어서 data변수에 저장한다.
  • fread 함수를 정리해보면, 기준 단위 크기로 반복 횟수만큼 데이터를 읽어 와서 '데이터를 저장할 주소'에 읽은 데이터를 저장한다.
  • 따라서 실제로 파일에서 읽은 데이터의 크기는 '단위크기 x 반복 횟수'다.
  • 위의 예시에서 4바이트를 파일에서 읽은 이유는 fread 함수를 호출할 때 사용한 두 번째 매개변수와 세 번째 매개변수를 곱한 크기만큼 읽어오기 때문이다.

<fread 함수로 바이너리 파일의 첫 4바이트 값 읽어오기.>

void main()
{
	int data;
	FILE* p_file = fopen("파일입출력.dat", "rb");
	if (NULL != p_file)
	{
		fread(&data, sizeof(int), 1, p_file);
		//읽기모드로 파일을 열면, 파일의 처음 위치 부터 데이터를 읽을 수 있다. 
		//파일의 첫 4바이트만큼 읽어와서 data의 시작주소에 넣는다.
		fclose(p_file);
		printf("file data : %d(0x%04x)\n", data, data);
	}

}

<결과>

  • fread 함수를 호출하면 실제로 데이터를 읽어 온 크기만큼 '파일 내부 데이터를 읽거나 쓰기 시작하는 위치'가 증가한다.
  • 다음 fread 함수를 호출하면 증가한 위치에서부터 파일 읽기를 시작한다.
  • fread 함수의 세 번째 매개변수도 '반복 횟수'의 용도를 띈다.
    만약에 fread함수를 사용해서 파일에 20바이트의 데이터를 읽어 와서 int형 배열에 저장하고 싶다면 다음과 같이 구성하면 된다.
int data[5];
fread(data, sizeof(int), 5, p_file); //4바이트 단위로 5회 반복해서 데이터를 읽어온다.

※주의

  • fread,fwrite 작업도 실패할 수 있다.
if(5 == fread (&data, sizeof(int), 5, p_file); //5==5같아야한다. 

파일 내부의 작업 위치 탐색, 확인 > fseek, ftell 함수

함수 원형
int fseek(FILE *stream, long offset, int origin);
함수 사용 형식
fseek(파일 포인터, 이동 거리, 기준 위치);
  1. 이 함수는 파일의 데이터를 읽을 기준 위치로
    1-1) SEEK_SET(파일의 시작)
    1-2) SEEK_END(파일의 끝)
    1-3) SEEK_CUR(현재 위치)를 사용 할 수 있다.
  2. 지정한 기준 위치로부터 사용자가 지정한 '이동 거리'만큼 이동한다.
    2-1) 음수 또는 양수로 구성된다. 음수(앞) /// 양수(뒤)
fseek(p_file, 0, SEEK_SET);
fseek(p_file, 32, SEEK_CUR); //현재 위치에서 32만큼 뒤로이동

이동한 위치를 값으로 나타내는 함수가 ===> ftell 함수다.
ftell

<함수 원형> 
long ftell(FILE *stream);
<함수 사용 형식>
현재 열려 있는 파일 내에서 데이터를 읽거나 저장할 위치 = ftell(파일 포인터);

<fseek 함수와 ftell함수 사용해서 바이너리 파일 크기 알아내기>

void main()
{
	int file_size = 0;
	FILE* p_file = fopen("파일입출력.dat", "rb"); //읽기 모드로 바이너리 파일을 오픈했다/
	if (NULL != p_file) // 파일 열기에 성공한 경우 
	{
		fseek(p_file, 0, SEEK_END); //파일의 끝으로 이동해라
		file_size = ftell(p_file); // 현재 파일 위치로 파일의 크기를 구했다.
		printf("파일 크기 : %d\n", file_size);
		fclose(p_file);
	}

}

<결과>

<최종 정리>

파일 입출력 관련 함수

fopen : 파일(스트림 열기)

fclose : 파일 닫기 :

fgetc : 파일에서 문자 읽기

fputc : 파일에 문자 출력

fgets : 파일에서 문자열 읽기

fputs : 파일에 문자열 출력

fscanf : 서식 데이터 입력

fprintf : 데이터 서식 파일 출력

fread : 파일 이진 자료 입력

fwrite : 파일 이진 자료 출력

fseek : 파일 임의 접근

ftell : 파일 현재 위치

rewind : 파일 포인터 재설정

feof : 파일 상태 파악

ferror : 파일 오류 확인

fflush : 출력버퍼를 파일에 기록

profile
아는만큼보인다.

0개의 댓글