코딩 61일차 C/C++

마스터피스·2024년 1월 24일
0

C/ C++ 

목록 보기
33/35
post-thumbnail

파일 입출력 2

1) fopen( ... )

-fopen 함수를 이용할 때는 꼭 습관처럼 fclose 를 아래에 먼저 작성하고 그 안에서 프로그래밍을 해야 합니다. 다른 프로그래밍 언어에서도 마찬가지 형태로 프로그래밍 하는 것을 권장드립니다. 이로 인해 발생할 수 있는 여러 가지 잘못된 런타임 오류를 미연에 방지할 수 있기 때문입니다.

2.fclose( ... )

  • fclose 함수는 nullptr을 파라미터로 받았을 경우(정확히는 올바르지 않은 모든 포인터) 런타임 오류(실행 도중 프로그램이 강제종료가 되는 현상)이 발생합니다. 이런 런타임 오류는 디버그 예외에도 잡히지 않기 때문에 꼭 인지하고 계셔야 합니다. fopen을 이용해 "r" 옵션을 이용해 파일을 열었을 경우, 파일이 없다면 nullptr을 파라미터로 리턴하게 되는데 이 경우에 fclose 함수를 이용해 nullptr을 fclose 할 경우 알 수 없는 오류와 함께 프로그램이 종료되는 경우가 있습니다.

  • fopen 과 fclose 사이에 항상 코딩을 해야한다. 또한 fclose의 특징은 파일을 열었을 때 파일이 없다면 fclose가 에러가 뜬다. 이를 이용해 파일이 있는지 없는지 알 수 있는 코드를 만들 수 있다.

예제코드)

#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("sameple.txt");

    if (exists) {
        printf("파일이 존재합니다.\n");
    }
    else {
        printf("파일이 존재하지 않습니다.\n");
    }

    return 0;
}

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 예제코드)

#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);


    return 0;
}
  1. 텍스트 파일의 텍스트 인코딩 문제

  • C++은 기본적으로 텍스트 인코딩이 ASCII 이며, 마이크로소프트 Visual Studio C++ 은 마이크로소프트 내에서 사용하는 한글 인코딩을 사용합니다. 이런 여러 가지 문제로 인해 텍스트 인코딩 문제가 있을 수 있는데, 한글 같은 경우 정상적으로 출력이 되지 않거나 깨지게 될 수 있습니다. 이 동작에 대해 자세히 알아보려면 텍스트 인코딩이라는 내용을 명확하게 인지하고 공부해야 합니다. 하지만 점점 프로그래밍 레벨이 올라가게 되면 각종 엔진이나 라이브러리를 활용하게 되는데, 이 경우, 엔진이나 라이브러리를 활용하게 되면 이런 문제에 대한 고민이 별로 필요 없게 됩니다. 지금은 저수준 파일 입출력을 공부하기 때문에 생기는 문제로서 영문 위주의 파일 입출력을 추천 드립니다.

3-1) 많은양의 데이터 한줄씩 읽어오기

3-1-1) fscanf 특성 알기

  • fscanf는 파일의 개행문자 까지만 읽는다.

3-1-2) fgetc()

  • 파일스트림의 현재 포인터에서 문자 하나를 읽어서 리턴해주는 것 (쉽게 말하자면 다음줄을 읽어오게 하는 코드) = 개행 문자를 읽어서 버려주는 역할을 함.

3-1-3) feof

  • 파일의 끝에 도달하면 1을 리턴해주는 함수

ex)

while (true) {
    char line[256];
    fscanf(infile, "%255[^\n]s", line);
    fgetc(infile);

    if (feof(infile) == 1) break;

}

예제)

예제파일)

Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
Vivamus vitae aliquam massa. Sed pretium risus a enim suscipit, 
ut finibus tortor ultricies. Integer non neque sem. 
Nulla imperdiet accumsan sollicitudin. Vestibulum tempus sapien dolor,
 ut imperdiet massa tincidunt vel. Quisque dapibus sem ante, 
eu tincidunt ipsum vehicula eget. Vestibulum ac maximus massa, 
sit amet tincidunt orci. Etiam placerat lacinia volutpat. Integer elit felis, 
fringilla porttitor maximus in, gravida sollicitudin eros. Nunc vestibulum, 
nulla nec interdum consectetur, ligula augue aliquam nulla, non pretium est 
felis id nunc. Aenean accumsan, ex eget sodales hendrerit, justo nunc facilisis est,
 a pulvinar diam lacus.

예제코드)

#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) {
        //line 크기 임의 설정
        char line[256];
        fscanf(infile, "%255[^\n]s", line);
        // 파일스트림의 현재 포인터에서 문자 하나를 읽어서
        // 리턴해주는 것(쉽게 말하면 다음줄을 읽어오게 하는 코드)
        // fscanf는 개행문자 까지만 읽는것 (= fgetc는 개행문자를 읽어서 버려주는 역할을 하는 것)
        fgetc(infile);

        printf("%s\n", line);

        if (feof(infile) == 1) break;

    }

    fclose(infile);

    return 0;
}

연습문제)

sol)

헤더파일)

#ifndef __HEADER_H
#define __HEADER_H

#define _CRT_SECURE_NO_WARNINGS

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

int getInteger(const char* promt);
std::string getString(const char* prompt);

class Student {
public:
    std::string name;
    int korean;
    int math;
    int eng;

    Student(std::string name, int korean, int math, int eng);
    void printInfo();

};


#endif

소스파일)

#include "Header.h"

int main() {
    std::vector<Student> students;
    FILE* infile = fopen("students.txt", "r");
    while (true) {
        if (feof(infile) == 1) break;
        char name[100];
        int korean;
        int math;
        int eng;
        int result;

        result = fscanf(infile, "%99[^\n]s", name);
        if (result == -1) break;
        fgetc(infile);
        result = fscanf(infile, "%d %d %d", &korean, &math, &eng);
        if (result == -1) break;
        fgetc(infile);
        Student s = Student(name, korean, 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("학생 이름 : ");
        int korean = getInteger("국어점수: ");
        int math = getInteger("수학점수 : ");
        int eng = getInteger("영어 점수 : ");

        Student s = Student(name, korean, math, eng);
        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].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 line[100];
    printf(prompt);
    fseek(stdin, 0, SEEK_END);
    scanf("%99[^\n]s", line);
    return line;
}


Student::Student(std::string name, int korean, int math, int eng) {
    this->name = name;
    this->korean = korean;
    this->math = math;
    this->eng = eng;


}

void Student::printInfo() {
    printf("이름 : / %s 국어 : %d / 수학 : %d / 영어 : %d\n",name.c_str(), korean, math, eng );
}
profile
코딩 일지

0개의 댓글