수색…
비고
std::istream_iterator
의 디폴트의 constructor은, 스트림의 마지막을 나타내는 반복자를 구축합니다. 따라서 std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(), ....
는 ifs
의 현재 위치에서 끝까지 복사하는 것을 의미합니다.
문자열 스트림
std::ostringstream
은 객체가 출력 스트림처럼 보이는 클래스입니다 (즉, operator<<
를 통해 객체에 쓸 수 있지만 실제로 쓰기 결과를 저장하고 스트림 형식으로 제공합니다).
다음 단축 코드를 고려하십시오.
#include <sstream>
#include <string>
using namespace std;
int main()
{
ostringstream ss;
ss << "the answer to everything is " << 42;
const string result = ss.str();
}
라인
ostringstream ss;
그러한 객체를 만듭니다. 이 객체는 먼저 일반 스트림과 같이 조작됩니다.
ss << "the answer to everything is " << 42;
그 다음에, 결과 스트림은 다음과 같이 얻을 수 있습니다.
const string result = ss.str();
(문자열 result
는 "the answer to everything is 42"
).
이는 주로 스트림 직렬화가 정의되어 있고 문자열 형식이 필요한 클래스가있는 경우에 유용합니다. 예를 들어, 어떤 클래스가 있다고 가정합니다.
class foo
{
// All sort of stuff here.
};
ostream &operator<<(ostream &os, const foo &f);
foo
객체의 문자열 표현을 얻으려면,
foo f;
우리는
ostringstream ss;
ss << f;
const string result = ss.str();
그런 다음 result
에는 foo
객체의 문자열 표현이 포함됩니다.
끝까지 파일 읽기
텍스트 파일을 한 줄씩 읽음
ifstream
문서에서 텍스트 파일을 한 줄씩 끝까지 읽는 적절한 방법은 일반적으로 명확하지 않습니다. 초보자 C ++ 프로그래머가 자주 범하는 실수와 파일을 읽는 적절한 방법을 생각해 보겠습니다.
공백 문자가없는 행
간단히하기 위해 파일의 각 줄에 공백 기호가 없다고 가정 해 봅시다.
ifstream
에는 스트림에 오류가없고 읽을 준비가되었을 때 true를 반환하는 operator bool()
이 있습니다. 게다가, ifstream::operator >>
는 스트림 자체에 대한 참조를 리턴하므로 매우 우아한 구문으로 한 행에서 EOF (오류는 물론 오류)를 읽고 확인할 수 있습니다.
std::ifstream ifs("1.txt");
std::string s;
while(ifs >> s) {
std::cout << s << std::endl;
}
공백 문자가있는 행
ifstream::operator >>
는 공백 문자가 발생할 때까지 스트림을 읽습니다. 따라서 위의 코드는 한 줄의 단어를 별도의 줄에 인쇄합니다. 줄 끝까지 모든 것을 읽으려면 ifstream::operator >>
대신 std::getline
사용하십시오. getline
은 작업 한 스레드에 대한 참조를 반환하므로 동일한 구문을 사용할 수 있습니다.
while(std::getline(ifs, s)) {
std::cout << s << std::endl;
}
분명히 std::getline
은 끝까지 단일 행 파일을 읽는 데에도 사용해야합니다.
한 번에 버퍼로 파일 읽기
마지막으로 공백 문자와 개행 문자를 포함하여 모든 문자에서 멈추지 않고 처음부터 끝까지 파일을 읽으십시오. 정확한 파일 크기 또는 길이의 상한이 허용되는 경우 문자열의 크기를 조정 한 다음 읽을 수 있습니다.
s.resize(100);
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
s.begin());
그렇지 않으면, 우리는 문자열의 끝에 각 문자를 삽입해야하므로 std::back_inserter
가 필요합니다.
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
std::back_inserter(s));
또는 iterator 범위 인수가있는 생성자를 사용하여 스트림 데이터로 컬렉션을 초기화 할 수 있습니다.
std::vector v(std::istreambuf_iterator<char>(ifs),
std::istreambuf_iterator<char>());
다음 예제는 ifs
가 바이너리 파일로 열리는 경우에도 적용됩니다.
std::ifstream ifs("1.txt", std::ios::binary);
스트림 복사 중
스트림과 반복자가있는 파일을 다른 파일에 복사 할 수 있습니다.
std::ofstream ofs("out.file");
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
std::ostream_iterator<char>(ofs));
ofs.close();
또는 호환 가능한 인터페이스로 다른 유형의 스트림으로 재 지정됩니다. 예를 들어 Boost.Asio 네트워크 스트림 :
boost::asio::ip::tcp::iostream stream;
stream.connect("example.com", "http");
std::copy(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
std::ostream_iterator<char>(stream));
stream.close();
배열
반복자는 포인터의 일반화로 생각할 수 있으므로 위 예제의 STL 컨테이너는 기본 배열로 대체 될 수 있습니다. 숫자를 배열로 파싱하는 방법은 다음과 같습니다.
int arr[100];
std::copy(std::istream_iterator<char>(ifs), std::istream_iterator<char>(), arr);
배열을 할당 한 후에는 배열의 크기를 변경할 수 없으므로 버퍼 오버플로에주의하십시오. 예를 들어 위의 코드에 100 개 이상의 정수가 포함 된 파일이 제공되면 배열 외부에 쓰고 정의되지 않은 동작으로 실행하려고 시도합니다.
iostream으로 컬렉션 인쇄하기
기본 인쇄
std::ostream_iterator
사용하면 STL 컨테이너의 내용을 명시 적 루프가없는 출력 스트림에 인쇄 할 수 있습니다. std::ostream_iterator
생성자의 두 번째 인수는 구분 기호를 설정합니다. 예를 들어 다음 코드가 있습니다.
std::vector<int> v = {1,2,3,4};
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ! "));
인쇄 할 것이다.
1 ! 2 ! 3 ! 4 !
암시 적 형식 캐스트
std::ostream_iterator
사용하면 컨테이너의 내용 유형을 암시 적으로 캐스트 할 수 있습니다. 예를 들어, 소수점 이하 3 자리수의 부동 소수점 값을 출력하기 위해 std::cout
을 조정 해보자.
std::cout << std::setprecision(3);
std::fixed(std::cout);
포함 된 값이 int
채로 std::ostream_iterator
를 float
인스턴스화합니다.
std::vector<int> v = {1,2,3,4};
std::copy(v.begin(), v.end(), std::ostream_iterator<float>(std::cout, " ! "));
그래서 위의 코드는 yield
1.000 ! 2.000 ! 3.000 ! 4.000 !
std::vector
에도 불구하고 int
는 보유하고있다.
생성 및 변환
std::generate
, std::generate_n
및 std::transform
함수는 즉석 데이터 조작을위한 매우 강력한 도구를 제공합니다. 예를 들어 벡터가있는 경우 :
std::vector<int> v = {1,2,3,4,8,16};
우리는 각 요소에 대해 "x is even"문을 부울 값으로 쉽게 인쇄 할 수 있습니다.
std::boolalpha(std::cout); // print booleans alphabetically
std::transform(v.begin(), v.end(), std::ostream_iterator<bool>(std::cout, " "),
[](int val) {
return (val % 2) == 0;
});
또는 제곱 된 요소를 인쇄하십시오.
std::transform(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "),
[](int val) {
return val * val;
});
N 개의 공백으로 구분 된 난수 인쇄 :
const int N = 10;
std::generate_n(std::ostream_iterator<int>(std::cout, " "), N, std::rand);
배열
텍스트 파일을 읽는 방법에 대한 섹션에서와 같이, 이러한 모든 고려 사항은 원시 배열에 적용될 수 있습니다. 예를 들어, 네이티브 배열에서 제곱 된 값을 출력합시다.
int v[] = {1,2,3,4,8,16};
std::transform(v, std::end(v), std::ostream_iterator<int>(std::cout, " "),
[](int val) {
return val * val;
});
파일 구문 분석
파일을 STL 컨테이너로 파싱하기
istream_iterator
는 코드에서 명시적인 루프없이 STL 컨테이너에 숫자 또는 다른 구문 분석 가능한 데이터 시퀀스를 읽는 데 매우 유용합니다.
명시 적 컨테이너 크기 사용 :
std::vector<int> v(100);
std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(),
v.begin());
또는 iterator를 삽입하여 :
std::vector<int> v;
std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(),
std::back_inserter(v));
입력 파일의 숫자는 임의의 개수의 공백 문자와 개행으로 나눌 수 있습니다.
이기종 텍스트 테이블 구문 분석
istream::operator>>
는 공백 기호까지 텍스트를 읽으므로 복잡한 조건에서 while
데이터를 사용하여 복잡한 데이터 테이블을 구문 분석 할 수 있습니다. 예를 들어, 두 개의 실수가있는 파일과 각 행에 공백이없는 파일이있는 경우 :
1.12 3.14 foo
2.1 2.2 barr
다음과 같이 파싱 될 수 있습니다.
std::string s;
double a, b;
while(ifs >> a >> b >> s) {
std::cout << a << " " << b << " " << s << std::endl;
}
변환
모든 range-manipulating 함수는 std::istream_iterator
범위와 함께 사용될 수 있습니다. 그 중 하나는 std::transform
, 즉석에서 데이터를 처리 할 수 있습니다. 예를 들어 정수 값을 읽고 3.14를 곱한 다음 결과를 부동 소수점 컨테이너에 저장합니다.
std::vector<double> v(100);
std::transform(std::istream_iterator<int>(ifs), std::istream_iterator<int>(),
v.begin(),
[](int val) {
return val * 3.14;
});