POCU C++정주행 2회차 - 파일 입출력

2023. 2. 10. 23:11C++ 복습

원래 하루에 게시물 1개 올리는데 이번에는 2개를 올리게 되었다... 이전 게시물에서도 말했지만 원래 진작에 게시물을 써나가야 했는데 그러지를 않았기 때문이다. 밀린 것까지 포함해서 앞으로 좀 급하게 게시물을 써나갈 생각이다. 그럼 시작한다.

 

파일 입출력

이 글은 C++에서 파일 입출력을 하기 위해서 어떤 함수를 쓰고 사용법이 어떻게 되는지 등은 자세히 다루지 않는다. 이미 배웠다고 가정하고 복습 카텍리에 저장했기 때문이다. 대신 C++에서 파일 입출력을 할 때, 일반적인 상황과 그렇지 않고 잘못된 입력이 들어왔을 때에 대한 대처 방법을 이곳에 써보려고 한다.

 

정상적인 상황의 예시들

아래의 예시들은 get(), getline(), >> 을 이용해서 파일로부터 데이터를 읽는 코드이다. 참고로 앞의 3개는 cin과 같은 C++의 스트림이라면 어느 곳에 넣어도 동일하게 동작한다.

 

C언어에서 getchar같은 함수를 이용해 반복문을 돌렸던 것처럼 데이터를 읽는 모습이다.

// 한 문자씩 읽는 예시

ifstream fin;
fin.open("Hello World.txt");

char character;

while (true)
{
    fin.get(character);
    
    if (fin.fail())
    {
        break;
    }
    
    cout << character;
}

fin.close();

 

정상적으로 한 줄씩 출력된다. 하지만 이건 행복 회로일 뿐이다.

// 한 줄씩 읽는 예시

ifstream fin;
fin.open("Hello World.txt");

string line;

while (!fin.eof())
{
    getline(fin, line);
    cout << line << endl;
}

fin.close();

Hello World.txt의 내용
결과 화면

 

이것 역시 정상적으로 작동하지만 행복 회로인 것은 마찬가지다.

// 한 단어씩 읽는 예시

ifstream fin;
fin.open("Hello World.txt");

string name;
float balance;

while (!fin.eof())
{
    fin >> name >> balance;
    cout << name << ": $" << balance << endl;
}

fin.close();

Hello World.txt
결과 화면

 

지금부터 왜 행복 회로인지 알아보겠다. 우선 한 줄씩 읽는 예시부터 보자.

// 한 줄씩 읽는 예시

ifstream fin;
fin.open("Hello World.txt");

string line;

while (!fin.eof())
{
    getline(fin, line);
    cout << line << endl;
}

fin.close();

Hello World.txt
결과 화면

보이는가? 결과 화면이 뭔가 석연치않다. 왜냐하면 직관적으로 생각했을 때, 파일이 빈 파일이라면 분명히 아무것도 출력이 되지 않아야 할 법한데 빈 줄이라 눈에 보이지는 않지만 어쨋든 1줄을 생성을 하기 때문이다. 이는 절대 정상적인 작동이라고는 볼 수 없다. 첫 진입시 당장은 eof가 아니어서 진입에 문제가 없지만 첫 출력에서 개행을 시켜버리기 때문에 이런 일이 생기는 것이다.

 

그럼 이번에는 값을 하나씩 읽어오는 케이스에 대해서 알아보자.

while (!fin.eof())
{
    fin >> number;
    cout << number << endl;
}

파일의 현재 상태
결과 화면

처음 fin은 100이라는 값의 1을 가리키고 있는 상태이다. 사실 100, 200, 300까지는 아무 문제없이 잘 읽는다. 하지만 문제는 바로 300뒤에 개행 문자를 읽을 때 나타난다. 300을 읽는 동시에 fin은 개행 문자를 가리키는데 이 때 eof가 아니기 때문에 반복문을 한 번 더 진입한다. 그리고 number로 개행 문자를 읽으려고 하면 바로 실패하고 다음으로 넘어가게 된다. 이 때, number는 아직 300이라는 값을 가지고 있기 때문에 300이 한 번 더 출력된다. 뒤에 개행 문자를 붙이고 있었던 것 때문에 오작동을 하게 된 것이다. cin을 사용하는 것처럼 엔터를 통해 개행 문자가 데이터로 들어가는 경우가 있을 때 주의해야 한다.

 

이제 파일에 완전히 엉뚱한 값이 들어있는 경우를 살펴보자.

while (!fin.eof())
{
    fin >> number;
    cout << number << endl;
}

파일의 현재 상태
결과 화면

fin은 number를 읽을 때 자료형이 맞지 않기 때문에 실패하게 된다. 이 때, 이전 예시와는 다르게 이 녀석은 공백이 아니어서 fin이 그냥 넘어가지 않고 'C'를 계속 가리키고 있다. 읽기를 한 번 실패해서 failbit가 활성화된 상태라면 모든 읽기를 무시하기 때문이다. 그래서 재진입을 해도 number가 계속 100인 상태에서 출력한 이후에 다시 재진입이 일어나서 무한 반복에 빠지는 것이다.

 

그럼 이런 문제를 전부 대응하도록 코드를 짜려면 어떻게 해야할까?

 

 

베스트 프랙티스

결론부터 말하면 그런 코드를 처음부터 완벽하게 짜는 것은 불가능하다.... 다만 업계에서는 스트림을 통해서 데이터를 읽을 때 자체적으로 리더를 구현해놓고 철저하게 테스트를 돌린다고 한다. 여기서 어떤 데이터로 테스트를 돌리는가도 매우 중요한 문제이다. 강의에서 소개한 훌륭한 테스트 케이스를 여기에 소개하겠다.

 

위의 테스트 케이스를 모두 통과했다면 정말 어지간한 거 아니면 거의 다 돈다고 보면 된다.

'C++ 복습' 카테고리의 다른 글

POCU C++정주행 1회차 - 참조자  (0) 2023.02.10
POCU C++ 정주행 - Intro  (0) 2023.01.16