본문으로 바로가기

C++) fstream binary write 을 통한 std::string 입출력

category C++/여담 2019. 3. 15. 22:06

강의 시간에 재밌는 과제를 받았다.

fstream 내의 ofstream, ifstream 으로 std::string 을 binary mode로 읽고 쓰기 였다.

많은 방법이 있겠지만, 내가 활용한 방식은 이렇다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <fstream>
#include <string>
 
using namespace std;
struct A {
    std::string mystr;
    int myint;
};
 
int main() {
    A onlywrite;
 
    onlywrite.mystr= "abcd";
    onlywrite.myint= 4;
    ofstream out("read.txt", ios::binary);
 
    out.write(onlywrite.mystr.c_str(), onlywrite.mystr.size());
    out.write((char*)&onlywrite.myint, sizeof(int));
 
    out.close();
 
    A onlyread;
 
    ifstream in("read.txt", ios::binary);
    onlyread.mya.resize(onlywrite.mystr.size());
    in.read(&onlyread.mystr[0], onlywrite.mystr.size());
    in.read((char*)&onlyread.myint, sizeof(onlyread.myint));
 
    cout << mimi.mystr<< mimi.myint<< endl;
}
cs

일단 std::string 은 내부적으로 char* 형을 가지고 있기때문에, 바이너리로 그냥 쓴다면 포인터의 주소값만 적히게 된다. 
만약 onlywrite 자체를 write 한뒤 onlyread 에서 read 하면, 그냥은 읽어지지만 그건 사실 onlywrite 의 char*의 주소값만 읽어온거라 읽어 온 것 처럼 보이게 된다.
이 오류는 끝나면 알 수 있는데, std::string 내의 iterator 가 onlywrite를 delete 한 후, onlyread 를 delete 할 때 exception 을 일으키게 된다.
아마 std::string 에 대해 잠깐 공부해보면 왜 그런지 알 수 있을 것이다.

이에 대한 수정 방안으로, std::string 안에 있는 c_str() 함수를 이용했다. 
이 함수는 std::string 내부에있는 동적할당 된 char* 타입을 꺼내주는데 이를 통해 size 만큼 txt에 작성하고, 읽어 올 수 있다.
위의 소스도 그와 동일하게 onlywrite.mystr.c_str() 을 통해 onlywrite 의 char* 타입을 꺼내 size 만큼 txt에 작성하고, 
그것을 size 만큼 다시 읽어와 onlyread 의 mystr에 붙혀넣어주었다.

주의점은 
onlyread는 size만큼의 여유분을 확보하고 있어야 한다. (resize 활용)
이를 통해 onlyread.mystr[0]에 값을 넣어준다 ( mystr[0] 는 char*의 0번째 이다. std::string 이 내부적으로 operator[] 를 오버로딩 하고있기때문 )
만약 이것을 배열로 사용한다면, onlywrite[?] 의 배열만큼 size도 txt에 추가 작성해주어야 할 것이다.

size, txt 이렇게 말이다.
그럼 size를 먼저 읽어와 resize를 통해 공간을 확보하고, txt를 읽어와 붙혀넣어주면 된다
해결!