``c ifstream``을 사용할지, ``c fopen()``을 사용할지는 얻어낸 결과를 어디에 담을 것인지에 따라 결정하면 된다. 

어차피 얻어낸 데이터를 가공하는 과정에서 `` string``으로 만들어야 한다거나, `` string``의 메서드를 사용해야 편한 경우라면 그냥 `` ifstream``을 사용한다. 


왜냐면, ``c char*``에서 `` string``으로 변환하는건 새로운 `` string``을 만들면서 생성자로 ``c char*``데이터를 집어넣는 수 밖에 없는데 이 때 Deep copy가 발생한다.

Shallow copy하는 방법 없나 찾아봤는데 아마 없는 것 같다.

그래서 문자열 데이터가 큰 경우 copy시 발생하는 오버헤드를 줄일 필요가 있기 때문에 아예 가공할 데이터의 타입을 따라가는 것이 좋다.


```cpp

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

}

```
``cpp pubsetbuf(buf, BUF_SIZE)``는 내부적으로 C++의 ``cpp std::basic_streambuf::setbuf(buf, BUF_SIZE)``를 호출하게 되는데, 
이는 호출 하나 안하나 버퍼 사이즈에 변화를 주지 않는 C의 ``c setbuf()``와는 달리,
user-provided buffer로 변경하면서 SIZE도 지정한 대로 변경하게 되므로 최적화에 사용할 수 있다. 따라서 오히려 C의 ``c setvbuf()``와 비슷하다.