(C++) File IO - 과 pubsetbuf()
ifstream
을 사용할지, fopen()
을 사용할지는 얻어낸 결과를 어디에 담을 것인지에 따라 결정하면 된다. 어차피 얻어낸 데이터를 가공하는 과정에서 string
으로 만들어야 한다거나, string
의 메서드를 사용해야 편한 경우라면 그냥 ifstream
을 사용한다.
왜냐면, char*
에서 string
으로 변환하는건 새로운 string
을 만들면서 생성자로 char*
데이터를 집어넣는 수 밖에 없는데 이 때 Deep copy가 발생 한다. Shallow copy하는 방법 없나 찾아봤는데 아마 없는 것 같다. 그래서 문자열 데이터가 큰 경우 copy시 발생하는 오버헤드를 줄일 필요가 있기 때문에 아예 가공할 데이터의 타입을 따라가는 것이 좋다.
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
32
33
34
35
36
37
38
39
#include <fstream>
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
ifstream ifs;
char buf[USER_BUFSIZ];
ifs.rdbuf()->pubsetbuf(buf, USER_BUFSIZ); // setbuf before open().
ifs.open("C:\\Users\\umbum\\source\\repos\\a", std::ios::binary);
if (ifs.fail()) {
std::cout << "[*] failed to open" << std::endl;
exit(EXIT_FAILURE);
}
filebuf* pbuf = ifs.rdbuf();
// pbuf->pubsetbuf(buf, BUF_SIZE); 이렇게 해도 되고
// ifs.rdbuf()->pub..이렇게 해도 되나 ifs.getline()을 쓸 경우는 이게 낫고, pbuf->sgetn()을 쓸거면 위가 낫다.
// 이렇게 버퍼를 지정해 놓기만 하면, getline()이든 sgetn()이든 접근 시 알아서 버퍼를 채우고, 버퍼에서 가져오는 듯.
// 아직 데이터에 접근하지는 않았으니 여기서는 모두 00이 출력된다.
for (int i = 0; i < BUF_SIZE; i++) {
printf("%02x ", buf[i]);
}
cout << "\n==============================================" << endl;
char b4[4];
pbuf->sgetn(b4, 4); // 이 때 1. buf에 데이터가 채워지고, 2. b4에 데이터가 copy된다.
// pbuf->sgetn() 를 반복적으로 호출해주면 offset이 증가하며 알아서 다음 데이터를 가져온다.
// ifs.getline() 도 버퍼에서 가져오기 때문에 buffer를 사용하기 위해 꼭 sgetn()일 필요는 없다.
// pbuf->pubseekoff(-4, ifs.cur); 현재 위치 기준 뒤로 감기는 이렇게.
printf("%02x%02x%02x%02x", b4[0], b4[1], b4[2], b4[3]); // 데이터 있다.
for (int i = 0; i < BUF_SIZE; i++) {
printf("%02x ", buf[i]);
} // 여기도 채워져 있다.
ifs.close();
return 0;
}
pubsetbuf(buf, BUF_SIZE)
는 내부적으로 C++의 std::basic_streambuf::setbuf(buf, BUF_SIZE)
를 호출하게 되는데, 이는 호출 하나 안하나 버퍼 사이즈에 변화를 주지 않는 C의 setbuf()
와는 달리, user-provided buffer로 변경하면서 SIZE도 지정한 대로 변경하게 되므로 최적화에 사용할 수 있다. 따라서 오히려 C의 setvbuf()
와 비슷하다.
This post is licensed under CC BY 4.0 by the author.