vs code에서 Solution Explorer에서 마우스 오른쪽 버튼을 클릭하고
Open folder in File Explorer 를 클릭하면 만들어진 폴더가 나온다.
fopen( ... )
fopen을 사용할 때에는 꼭 습관처럼
fclose( ... ) 먼저 아래쪽에 만들어 두고
그 사이에 코딩을 하는 것이 가장 좋다
이는 다른 프로그래밍에서도 마찬가지인데
다른 프로그래밍 언어에서도 똑같이
파일을 열고 파일을 닫고 하기 때문이다.
fclose( ... )
fclose( ... ) 함수는 nullptr을 파라미터로 받았을 경우
런타임 오류가 발생하게 된다.
fopen을 "r" 옵션으로 열었을 경우에 파일이 없다면
nullptr을 리턴하게 되는데
이 경우를 생각해서 프로그래밍을 해야 한다.
fopen을 통해서 읽기 전용으로 파일을 열었을 때 파일이 만약에 없다면
반환 값은 null pointer가 된다.
fclose 같은 경우는 nullptr에 대해서는 런타임 오류가 발생하게 된다.
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> int main() { // fopen FILE* infile = fopen("sample.txt", "r"); if(infile != nullptr) fclose(infile); bool fileIsExists = infile != nullptr; // fileIsExists이 true면 "sample.txt" 파일이 존재 판단 가능 return 0; } |
위 내용을 함수화 해서 파일이 존재하는지 존재하지 않는지 체크하는 함수 만들기
#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("파일이 존재합니다.\n"); } else { printf("파일이 존재하지 않습니다.\n"); } // sample.txt가 존재하지 않기 때문에 파일이 존재하지 않습니다 출력 return 0; } |
out.txt 파일을 만들어 안에 100 Hello World 100 내용이 출력되게 만들기
fprintf 사용
#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() { FILE* outfile = fopen("out.txt", "w"); fprintf(outfile, "%d Hello World %d", 100, 100); fclose(outfile); return 0; } |
fscanf의 큰 장점 : format 문자열을 이용해서 여러개의 값을 한꺼번에 받아올 수 있는 것
여러개의 값을 한 줄에서 읽어올 수 있다
fscanf를 이용해서 정수 받아오기
#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() { FILE* infile = fopen("in.txt", "r"); int data1; int data2; fscanf(infile, "%d %d", &data1, &data2); // in.txt파일에서 숫자를 2개를 받아오는데 공백을 기준으로 나눠서 읽어오게 된다. printf("data1 : %d, data2 : %d", data1, data2); fclose(infile); return 0; } |
fscanf를 이용해서 문자열을 받아오기
#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() { FILE* infile = fopen("in.txt", "r"); char line[128]; fscanf(infile, "%127[^\n]s", line); printf("%d", line); fclose(infile); return 0; } |
텍스트 인코딩 문제
C++는 기본적으로 MS 기본 인코딩이나 ANSI 인코딩을 활용하여
문자열을 저장하고 활용한다.
이를 우리가 인지하지 못한 상태에서
다른 텍스트 에디터를 활용하여 저장된 문자열을 불러오게 되면
한글 등 영문자가 아닌 다른 문자들이 올바르지 않은 문자열로 나타나게 된다.
#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() { FILE* infile = fopen("in.txt", "r"); char line[128]; int value1; fscanf(infile, "%127[^\n]s %d", line, value1); printf("문자열 : %s\n", line); printf("value: %d\n", value1); // value에 오류 발생 fclose(infile); return 0; } |
fscanf로 문자열을 받아올 때 주의해야할 점
: 문자열과 숫자들을 한 줄에서 읽으려고 할 때 문제가 발생할 수 있다.
scanf로 문자열을 입력 받으려고 하면 한 줄을 전부 다 문자열로 읽어오는게 편하다
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() { FILE* infile = fopen("in.txt", "r"); char line[256]; fscanf(infile, "%255[^\n]s %d", line); printf("%s\n", line); fgetc(infile); // 다음 줄을 읽어오기 위함 // fgetc는 파일스트림의 현재 포인터에서 문자 하나를 읽어서 리턴해주는 함수 fscanf(infile, "%255[^\n]s %d", line); printf("%s\n", line); fclose(infile); return 0; } |
fscanf는 개행문자(\n) 까지만 읽는 것인데 다시 scanf를 하려고 보면
다시 fscanf를 하려고 보니까
바로 뒤에 개행문자가 있어 아무것도 하지않고 그냥 지나가는 거
아무것도 하지 않았으니까 기존 line 문자 배열에 있는 값이 그대로 printf에 출력이 된다.
(물론 이것은 %s 옵션이 아닌 %99[^\n]s 옵션이기 때문에 그렇다.)
그래서 이것을 fgetc를 통해서 문자를 하나 읽어서 버리게 되면
fscanf가 읽으려고 봤더니 파일 포인터가 다음 줄에 있어서
그 지점부터 한 줄을 읽게 되는 것이다.
즉, fgetc는 개행문자를 읽어서 버려주는 역할
fscanf는 바로 뒤에 개행문자가 있으면 아무것도 하지 않기 때문에
우리가 이 fgetc를 하지 않았을 때는 그냥 같은 줄이 두 번 출력이 되는 것이다.
그리고 fgetc가 있으니까 출력을 하고 다음 입력을 받고 다음 문자열들을 읽어올 수 있게 되는 것
자동으로 모든 줄을 다 읽어오고 싶은 경우
#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() { FILE* infile = fopen("in.txt", "r"); while (true) { char line[256]; fscanf(infile, "%255[^\n]s %d", line); fgetc(infile); printf("%s\n", line); if(feof(infile) == 1) break; // infile의 파일포인터가 파일의 끝에 당도했기 때문에 break로 while루프 탈출 } fclose(infile); return 0; } |
feof 함수 사용
feof 함수 : 파일의 끝에 당도하게 되면 1을 리턴
연습 프로그래밍
Headerr.h
#ifndef __HEADERR_H__ #define __HEADERR_H__ #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <string> #include <vector> int getInteger(const char* prompt); std::string getString(const char* prompt); // student 객체 만들기 class Student { public: std::string name; int korean; int math; int english; Student(std::string name, int korean, int math, int english); void printInfo(); }; #endif |
Source.cpp
#include "Headerr.h" int main() { std::vector<Student> students; // 파일을 읽어서 students라는 vector에 값을 하나하나 집어넣어주기 FILE* infile = fopen("students.txt", "r"); while (true) { if(feof(infile) == 1) break; char name[100]; int korean; int math; int english; int result; result = fscanf(infile, "%99[^\n]s", name); if (result == -1) break; fgetc(infile); result = fscanf(infile, "%d %d %d", &korean, &math, &english); if (result == -1) break; fgetc(infile); // 받아온 값들을 벡터 자료구조에 집어넣기 Student s = Student(name, korean, math, english); students.push_back(s); } fclose(infile); while (true) { for(int i = 0; i < students.size(); i++) { students[i].printInfo(); } std::string name = getString("학생 이름 : "); int korean = getInteger("국어 점수 : "); int math = getInteger("수학 점수 : "); int english = getInteger("영어 점수 : "); Student s = Student(name, korean, math, english); // 정적 // students 자료구조 안에다가 학생 자료를 집어넣기 students.push_back(s); FILE* outfile = fopen("students.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].korean, students[i].math, students[i].english); } 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 line[100]; printf(prompt); fseek(stdin, 0, SEEK_END); scanf("%99[^\n]", line); return line; } Student::Student(std::string name, int korean, int math, int english){ this->name = name; this->korean = korean; this->math = math; this->english = english; } void Student::printInfo(){ printf("이름: %s / 국어: %d / 수학: %d / 영어: %d\n", name.c_str(), korean, math, english); } |
'C++' 카테고리의 다른 글
c++ 17 ( 람다 함수 ) (0) | 2022.02.27 |
---|---|
c++ 16 ( 파일 입출력 1 ) (0) | 2022.02.23 |
c++ 15 ( 기본 자료구조 - STL 기초 자료구조 활용 ) (0) | 2022.02.23 |
c++ 14 ( Generic 이라고도 불릴 수 있는 개념 ) (0) | 2022.02.22 |
c++ 13 ( const / static / extern ) (0) | 2022.02.19 |