C언어 공부

C++ 심화 - 8 파일 입출력2

당혜성 2025. 3. 22. 00:26

fopen(...)

fopen을 사용할 때에는 꼭 습관처럼 fclose(...)먼저 아래쪽에 만들어 두고 그 사이에 코딩을 하는 것이 가장 좋다.

 

이는 다른 프로그래밍에서도 마찬가지인데, 다른 프로그래밍 언어에서도 똗같이 파일을 열고 파일을 닫고 하기 때문이다.

 

코드로 보면 이렇다.

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>

int main() {
	
	FILE* infile = fopen("sample.txt", "r");


	fclose(infile);

	return 0;
}

(이름을 sample 말고 다른 이름으로 만들어도 된다. .txt만 붙여주도록 하자.)

 

fclose(...)

fclose(...) 함수는 nullptr을 파라미터로 받았을 경우 런타임 오류가 발생하게 된다.

 

fopen을 "r"옵션으로 열었을 경우에 파일이 없다면 nullptr을 리턴하게 되는데, 이 경우를 생각해서 프로그래밍을 해야한다.

 

아마 위에 있는 코드를 실행했다면 오류가 났을것이다. 왜냐하면 sample.txt를 안만들었기 때문이다.

 

그럼 파일이 만들어 졌는지 확인하는 코드를 짜보자.

예시 코드

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>

bool file_exists(const char* filename) {
	FILE* fp = fopen(filename, "r");

	if (fp != nullptr) fclose(fp);

	return fp != nullptr;
}

int main() {
	
	bool exists = file_exists("sample.txt");

	if(exists){
		printf("파일이 존재한다");
	}
	else {
		printf("파일이 존재하지 않는다");
	}
	

	return 0;
}

이렇게 되면 파일이 만들어 졌는지 확인이 가능하다.

 

파일이 안만들어져 있으면 파일로 직접 가서 파일을 만들도록 하자.

 

만약 파일이 존재하지 않는다고 하면,

자신의 프로젝트 파일 경로 복사 -> 메모장 켜기 -> 다른 이름으로 저장 -> 자신의 프로젝트 경로 붙여넣기-> 텍스트 파일 이름 생성 후 저장

 

fprintf, fscanf

fprintf를 사용해보자

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>


int main() {
	
	FILE* outfile = fopen("out.txt", "w");
	fprintf(outfile, "%d hi %d", 100, 100);
	fclose(outfile);

	return 0;
}

이렇게 만든 후, 다시 프로젝트 파일로 가면 out.txt 파일이 만들어져 있다.

 

fscanf도 똗같다

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>


int main() {
	
	FILE* infile = fopen("in.txt", "r");

	int data1;
	int data2;
	fscanf(infile, "%d %d", &data1, &data2);

	printf("data1: %d, data2: %d", data1, data2);
	fclose(infile);
	return 0;
}

in.txt 파일은 따로 만들어 줘야 한다. 위에 알려준대로 만들어 보자.

 

저장 할때 100 100을 넣어주자.

 

실행을 하면 정상적으로 나올것이다.

 

문자를 받고 싶다면 영어로만 해야한다. 한국어로 하면 글자가 깨진다.

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>


int main() {
	
	FILE* infile = fopen("in.txt", "r");

	char line[128];

	fscanf(infile, "%127[^\n]s", line);

	printf("%s", line);
	fclose(infile);
	return 0;
}

기본적으로 출력은 이렇게 한다. 자신이 만든 txt 파일에 가서 한국어를 적어보자.

 

앞서 말했듯 글자가 깨져서 나올것이다. 영어로 하면 정상적으로 나온다

 

이것은 텍스트 인코딩의 문제이다.

C++는 기본적으로 MS 기본 인코딩이나 ANSI 인코딩을 활용하여 문자열을 저장하고 활용한다.

 

이를 우리가 인지하지 못한 상태에서 다른 텍스트 에디터를 활용하여 저장된 문자열을 불러오게 되면 한글 등 영문자가 아닌 다른 문자들이 올바르지 않은 문자열로 나타나게 된다

 

fscanf의 활용

텍스트 파일을 한줄한줄 다 읽어서 전체를 출력하는 코드를 만들어 보자.

 

 

in.txt파일에 이걸 넣어보도록 하자.

더보기

Lorem ipsum dolor sit amet, 
consectetur adipiscing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 
Ut enim ad minim veniam, 
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, 
sunt in culpa qui officia deserunt mollit anim id est laborum.

ipsum 문자라는 것인데, 디자이너나 프로그래머들이 임시로 넣는 별 의미 없는 문자열 들이다.

 

fscanf로 한줄씩 읽어보도록 하자.

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>


int main() {
	
	FILE* infile = fopen("in.txt", "r");

	char line[256];

	fscanf(infile, "%255[^\n]s", line);
	printf("%s\n", line);
	fclose(infile);
	return 0;
}

이러면 Lorem ipsum dolor sit amet, 이 출력이 된다.

 

만약 fscanf 를 2번 해서 출력하면 어떻게 될까? 한번 생각해 보자.

 

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>


int main() {
	
	FILE* infile = fopen("in.txt", "r");

	char line[256];

	fscanf(infile, "%255[^\n]s", line);
	printf("%s\n", line);

	fscanf(infile, "%255[^\n]s", line);
	printf("%s\n", line);

	fclose(infile);
	return 0;
}

Lorem ipsum dolor sit amet, 이문장이 2번 출력이 된다.

그래서 다음줄로 넘어가기 위해

fgetc(infile); 을 사용해야 한다.

 

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>


int main() {
	
	FILE* infile = fopen("in.txt", "r");

	char line[256];

	fscanf(infile, "%255[^\n]s", line);
	fgetc(infile);
	printf("%s\n", line);

	fscanf(infile, "%255[^\n]s", line);
	printf("%s\n", line);

	fclose(infile);
	return 0;
}

fgetc9infile); 이건 다음 문자열로 가는게 아니다. 파일 스트림에 현제 포인터에서 읽어 리턴해주는 것이다.

 

자동으로 모든 줄을 읽어오고 싶다면 반복문을 사용하여 이러한 코드를 사용하면 된다.

코드 예시

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>


int main() {
	
	FILE* infile = fopen("in.txt", "r");

	while (true) {
		char line[256];
		fscanf(infile, "%255[^\n]s", line);
		fgetc(infile);
		printf("%s\n", line);
		if (feof(infile) == 1)break;
	}

	
	fclose(infile);
	return 0;
}

이렇게 하면 텍스트파일 안에 있는 모든 내용이 출력이 된다.

 

연습 문제가있다. 아마 우리가 처음부터 끝가지 배운것을 활용해야 하기 때문에 분명히 쉽지 않을것이다.

강의는 여기 다음 람다함수가 끝이다. 모르겠으면 코드를 보고 한줄한줄씩 코드를 해석해 보는것도 도움이 될것이고, gpt를 활용하여 코드를 쉽게 해석해달라고 하면 알려줄 것이다.

 

풀지 못했더라도 보여준 예시 코드를 손으로 직접 한 번씩 짜보는게 좋다. 동영상이 없어 순서는 모르겠지만, 한번 어떤 순서로 했는지 코드를 짜보면 좋을것이다.

연습

사용자로부터 학생의 이름을 받고 입력받은 학생의 국어, 수학, 영어 점수를 입력받아 score.txt 파일에 저장하는 프로그램을 만드시오.

이 프로그램이 시작되면 socre.txt 파일이 존재할 경우 score.txt파일에서 학생의 이름과 국어, 수학, 영어 점수를 불러올 수 있어야 한다.

학생의 이름과 각각 점수는 / 슬래시 기호로 구분하시오.

이 프로그램은 학생의 리스트와 점수를 출력하는 기능도 있다.

 

헤더 코드

#ifndef __mainHeader_H__
#define __mainHeader_H__
#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <string>
#include <vector>




int getinteger(const char* prompt);
std::string getstring(const char* prompt);

class student {
public:
	std::string name;
	int kor;
	int math;
	int eng;

	student(std::string name, int kor, int math, int eng);
	void printinfo();
};
#endif

 

소스 코드

#define _CRT_SECURE_NO_WARNINGS
#include "mainHeader.h"


int main() {
	std::vector<student> students;
	FILE* infile = fopen("student.txt", "r");
	while (true) {
		if (feof(infile) == 1)break;
		char name[100];
		int kor;
		int math;
		int eng;
		int result;
		result = fscanf(infile, "%99[^\n]s", name);
		if (result == -1)break;
		fgetc(infile);
		fscanf(infile, "%d %d %d", &kor, &math, &eng);
		if (result == -1) break;
		fgetc(infile);
		student s = student(name, kor, math, eng);
		students.push_back(s);
	}
	fclose(infile);

	while (true) {
		for (int i = 0; i < students.size(); i++) {
			students[i].printinfo();
		}
		std::string name = getstring("학생 이름:\n");
		int kor = getinteger("국어점수:\n");
		int math = getinteger("수학점수:\n");
		int eng = getinteger("수학점수:\n");

		student s = student(name, kor, math, eng);
		students.push_back(s);
		FILE* outfile = fopen("student.txt", "w");
		for (int i = 0; i < students.size(); i++) {
			fprintf(outfile, "%s\n", students[i].name.c_str());
			fprintf(outfile, "%d %d %d\n", students[i].kor, students[i].math, students[i].eng);
		}
		fclose(outfile);
	}
	
	return 0;
}

int getinteger(const char* prompt) {
	int input;
	printf(prompt);
	fseek(stdin, 0, SEEK_END);
	scanf("%d", &input);
	return input;
}

std::string getstring(const char* prompt) {
	char name[20];
	printf(prompt);
	fseek(stdin, 0, SEEK_END);
	scanf("%99[^\n]s", name);
	return name;
}

student::student(std::string name, int kor, int math, int eng) {
	this->name = name;
	this->kor = kor;
	this->math = math;
	this->eng = eng;
}

void student::printinfo() {
	printf("이름: %s / 국어: %d / 수학: %d / 영어: %d\n", name.c_str(), kor, math, eng);
}