cCcode

C Language [핵심정리] - 41 본문

C Language Basic

C Language [핵심정리] - 41

cCcode 2021. 7. 22. 21:26

1. 파일에 문자열 작성하기

지금까지는 printf 로 서식 지정자를 통해 문자열을 화면에 출력할 수 있었고, sprintf 로 서식 지정자를 통해 문자열생성할 수 있었습니다. 그러면 이제는 fprintf 를 활용해 파일에 문자열을 작성하는 방법에 대해 알아보겠습니다.

 

파일에 문자열작성하기 위해선 fopen 함수로 파일을 열어 파일 포인터를 얻은 뒤 fprintf 함수문자열을 작성하고 fclose 함수파일 포인터반환하면 됩니다. (<stdio.h>파일선언되어있습니다.)

파일에 문자열을 작성할 때 사용하는 함수들
파일에 문자열 출력
결과
생성된 파일
파일 내용

파일은 .c 파일이 있는 폴더에 생성됩니다. 파일 모드의 종류는 다음과 같습니다.

파일 모드

파일모드는 t 와 b 가 단독적으로 사용될 수 없으며, 일반적으로는 rb 나 rt 나 w+b 처럼 읽기/쓰기 모드텍스트/바이너리 모드조합해서 사용합니다. 파일쓰기가 끝났으면 반드시 fclose 함수로 파일 포인터를 닫아줘야 하는데, 그 이유는 파일 포인터도 구조체 FILE 크기만큼 동적 메모리 할당을 한것이기 때문입니다. 따라서 fclose로 닫지 않는다면 메모리 누수가 발생합니다. 

파일에 문자열 쓰는 과정

stdout 매크로를 사용한다면, fprintf 함수로도 화면에 문자열을 출력할 수 있습니다.

stdout 매크로 사용
결과

+ foepn을 사용하면 파일이 있는 경로까지 함께 지정할 수 있습니다. (경로를 지정할 때 \(역 슬래쉬)를 사용하려면 두번 작성해야합니다.)

○ 절대 경로 : fopen("C:\\Project_C\\PRINT.txt", "w");

○ 상대 경로 : fopen(" ..\\PRINT.txt", "w");

리눅스 및 OS X의 경우에는 \(역 슬래쉬) 대신 /(슬래쉬)를 사용합니다.

 

생성된 파일을 읽기 위해선 fopen 함수로 파일을 연 후 파일 포인터를 얻은 뒤 fscanf 함수서식지정하여 파일의 내용을 얻습니다.(<stdio.h>파일에 선언되어 있습니다.)

fscanf 함수 사용

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
	char String[10];
	char String_2[10];
	char String_3[10];
	char String_4[10];
	char String_5[10];
	char String_6[10];

	FILE* fp = fopen("Writing_string.txt", "r");
	// 파일을 읽기 모드(r)로 열기, 파일 포인터 반환

	int String_count = fscanf(fp, "%s %s %s %s %s %s", String, String_2, String_3, String_4, String_5, String_6);

	printf("File content is\n%s %s %s %s %s %s\nand this string count is %d\n", String, String_2, String_3, String_4, String_5, String_6, String_count);

	fclose(fp);
	
	return 0;
}

결과

제가 파일에 문자열작성할 때는 하나의 서식지정자공백까지 포함해 출력할 수 있었는데 문자열을 읽는 건 작성할 때와 달리 공백을 기준으로 문자열들을 따로 따로 구분해서 해당 문자열을 저장할 배열의 개수가 늘어났습니다.

+ fscanf 는 fprintf 함수와는 달리 stdin 매크로를 사용하여 사용자가 입력한 값변수저장할 수 있습니다.

입력한 값 변수에 저장
결과

 

지금까진 서식지정자를 사용해서 문자열을 쓰거나 읽었습니다. 그럼 서식지정자를 사용하지 않고 쓰거나 읽을 수 있을까요? 당연히 가능합니다. fputs 함수를 사용하면 문자열을 그대로 파일에 쓸 수 있습니다. (<stdio.h>파일에 선언되어 있습니다.)

fputs 사용
fputs 함수 사용
결과
결과

너무나 당연하게도 fputs 함수 또한 파일 포인터 대신 stdout를 지정해 문자열이 화면에 출력하게 할 수 있습니다.

stdout 매크로 사용
결과

fwrite 함수를 사용하면 문자열파일에 쓸 수 있습니다. (<stdio.h>파일에 선언되어 있습니다.)

fwrite 사용
fwrite 함수 사용
결과
수정된 파일

파일포인터 대신 stdout 를 지정하면 문자열이 화면에 출력됩니다.

stdout 매크로 사용
결과

 

fgets 함수를 사용하면 파일의 내용을 읽을 수 있습니다. (서식지정자 사용 X) (<stdio.h>파일에 선언되어 있습니다.)

fgets 사용
fgets 함수 사용
결과

그전에 서식지정자로 파일을 읽을 때와는 달리 서식지정자 하나로 공백까지 모두 읽을 수 있습니다. 이외에도 fgets는 파일을 읽는 특이한 방식을 가지고 있습니다.

 

파일 내용

위 파일에서 버퍼의 크기를 10으로 지정한 뒤 파일을 읽으면 NULL을 포함해 실제 문자열 9byte까지 읽을겁니다. 즉, 실제로 의도한 byte 보다 하나 덜 읽게 됩니다.

EX) happy happy 까지 확인하기 위해 11byte 즉, buffer를 11로 잡는다면

결과

이처럼 예상과 다른 결과가 나오기도 합니다. 그리고 줄바꿈(\n)이 있다면 줄바꿈까지만 읽기 때문에 주의가 필요합니다. (\n 포함)

내용
결과

이 때는 아무리 버퍼를 크게 지정해줘도 fgets를 사용한다면 is 까지밖에 못 읽습니다.

버퍼 크게 지정
결과

이처럼 \n까지만 들어갑니다. 만약 stdin 매크로를 지정한다면 사용자가 입력한 문자열버퍼에 저장하는 데, Enter를 누르면 \n이 되므로, fgets 함수는 Enter를 누르기전 버퍼 크기보다 커지기 전까지만 입력 값을 받습니다.

fgets 로 입력값 받기
결과

 

fread 함수를 사용해서 파일에서 문자열을 읽어보겠습니다. (<stdio.h>파일에 선언되어 있습니다.)

fread 함수 사용
fread 함수 사용
결과

여기서 중요한 점, 다른 함수들은 몰라도 fread 를 사용하기 위해서는 버퍼를 0으로 초기화 해야합니다. 만약 버퍼를 초기화 하지 않고 fread로 파일을 읽는다면 쓸데없는 값도 동시에 출력됩니다. 왜냐하면 파일에 저장된 문자열에는 NULL이 없기 때문에 문자열만 읽는다면, 버퍼를 가져오며 그전 메모리에 저장된 값과 합쳐지게 됩니다.

초기화 X
결과

그리고 fread 함수fgets 함수와는 달리 \n 까지 있는게 아니라 반드시 지정된 크기만큼만 읽습니다. 

 

만약 fread로 버퍼보다 큰 값을 읽으면 어떻게 될까요..? 사실 큰 문제없이 문자열이 읽어지긴 합니다만... (fread는 버퍼 크기에 상관없이 파일에서 읽을 수 있는 최대 크기만큼 읽기 때문) fread가 파일의 크기에 따라 성공 여부를 반환할 때 파일의 크기가 버퍼와 다르기 때문에 0이 반환됩니다. 

 

fread 함수도 stdin을 지정하면 사용자가 입력한 문자열을 버퍼에 저장합니다. 여기선 fread 가 무조건 지정된 크기만큼 읽기 때문에 버퍼 끝에 NULL문자가 들어갈 수 있도록 읽기 크기를 버퍼 크기보다 1 작게 만들어줘야 합니다.

fread 사용해서 입력값 받기
결과

 

지금까지 제가 stdin, stdout를 파일 포인터 대신 사용하라고 했는데, 사실 stdin, stdout 역시 파일 포인터의 일종입니다. stdin은 키보드 입력, stdout 은 콘솔 출력을 의미합니다. 따라서 fscanf, fgets 함수로 stdin 을 읽으면 키보드 입력 값을 가져오고, fprintf, fputs 함수로 stdout 에 값을 쓰면 콘솔에 값을 출력하게 되죠.

Comments