---
description: 텍스트 파일의 특정 문자열을 원하는 문자열로 치환하는 프로그램 만들기
---

# \[CPP-01] 파일 입출력 및 문자열 치환하기

**\[CPP-Module01 / ex07: Sed is for losers 과제]**&#x20;

* `FILENAME`, 비어있지 않은 두개의 문자열 `s1`과 `s2`을 인자로 받는 `replace` 프로그램을 만들어라.
* 이 프로그램은 주어진 파일을 오픈한 뒤 파일 내에 있는 문자열 s1을 s2로 변경한 `FILENAME.replace` 을 만든다.
* 테스트 파일을 함께 제출해야한다.

## 1. fstream : 파일입출력 스트림

`<iostream>`을 사용하는 표준입출력과 마찬가지로 CPP의 파일입출력에는 `ifstream`, `ofstream`, `fstream` 세 가지 클래스가 사용된다. 각각 입력, 출력, 입출력을 위한 객체들이 정의되어 있으며, 표준입출력처럼 연산자 오버로딩을 통해 간단하게 사용할 수 있다. C처럼 함수이름을 외울필요가 없는 것이 장점이다.

```cpp
std::cout << "Hello"; // 콘솔에 Hello 출력
std::out << "Hello"; // 파일스트림에 등록된 파일에 Hello 출력
```

과제에서는 인자로 주어진 파일을 읽은 뒤 내용을 변경한 새 파일을 만들어야하므로 `include <fstream>`을 한다.

## 2. open() : 스트림에 파일 연결하기

```cpp
std::ifstream fin; // 파일스트림 객체 fin(file input)을 선언. fout도 마찬가지.
fin.open(filename);
```

`open` 멤버함수를 사용해 입출력에 사용할 파일과 프로그램 사이에 스트림을 만들어 준다. 아래 코드처럼 open을 생략하고 한줄로 줄여쓰는게 일반적인 것 같다.

```cpp
std::ifstream fin(filename); 
std::ofstream fout(filename + ".replace");
```

## 3. is\_open() : 예외처리 하기

파일을 읽을 때 파일이 존재하지 않을 수 있다. 아래 두 멤버함수를 예외처리를 위한 조건식으로 사용할 수 있다.

* `fail()`  : 해당 값이 true면 파일이 존재하지 않는다.
* `is_open()` : 해당 값이 true면 파일이 존재한다.

## 4. RAII : 파일 연결 해제하기

```cpp
fin.close();
fout.close();
```

하지만 CPP에서는 `close` 함수를 꼭 쓰지 않아도 된다. 소멸자가 스택에 할당된 자원은 스코프가 끝나면 자동으로 해지되기 때문이다. 이를 객체지향 프로그래밍에서는 `RAII`(Resource Acquisition Is Initialization)라고 부른다고 한다.

## 5. eof(), <<, >> : 파일에 문자열 읽고 쓰기

cout으로 콘솔에 출력했던 것처럼, `<<` 과 `>>` 연산자를 쓰면 된다. `eof()` 함수는 파일이 끝나면 1을 반환한다.

```cpp
#include <iostream>
#include <fstream>

int main()
{
  ifstream fin("sample.txt"); // 읽을 파일을 fin 스트림객체와 연결한다.
  std::string line;
  while (!fin.eof())
  {
    fin >> line; // >> 연산자는 white space나 '\n'을 기준으로 읽는다.
    std::cout << line << std::endl;
  }
  return (0);
}
```

그 외에도 아래 함수들이 존재한다.

* `put('A')` : 한 글자씩 쓰기
* `get()` : 한 글자씩 읽기
* `getline(fin, 입력받은 문자열을 저장할 string 객체)` : 입력스트림으로부터 '\n' 을 기준으로 한 줄씩 읽어 객체에 저장

## 6. find() 및 replace() : 문자열 치환하기

문자열을 다루는 함수들이니 `string` 클래스를 include 한다.

```cpp
include <iostream>
include <string>

if (line.find(s1) == std::string::npos)
   std::cout << "해당 line에 s1 문자열이 없음" << std::endl;
else
    line.replace(pos, s1.length(), s2);
```

### 6.1. find()와 npos

```cpp
find(std::string str);
```

인자로 들어온 문자열이 line에 있다면 해당 문자열의 첫번째 인덱스를 반환한다. 만약 찾는 문자열이 없는 경우에는 `std::string::npos`를 반환한다. `npos`는 -1로 정의되는 상수라고 한다.

### 6.2. replace()

```cpp
replace(size_type pos, size_type count, std::string str);
```

기존 문자열의 `pos` 부터 `count` 개의 문자들을 `str`로 치환한다.
