2009-11-29 7 views
12

임시 버퍼를 생성하지 않고 알려진 바이트 수를 직접 std :: string으로 읽는 방법이 있습니까?std :: istream에서 std :: string으로 직접 읽기

예를 들어, 현재 내가

boost::uint16_t len; 
is.read((char*)&len, 2); 
char *tmpStr = new char[len]; 
is.read(tmpStr, len); 
std::string str(tmpStr, len); 
delete[] tmpStr; 
+0

당신이'벡터 '대신'string'을 사용하는 방법에 대한 생각 했습니까? 데이터가 "문자열 형"보다 "원시"인 경우 더 잘 작동 할 수 있으며 직접 액세스보다 혼동이 적습니다. (벡터는 연속적으로 저장해야하므로'& v [0]'을 사용하십시오.) –

+0

대부분의 경우 문자열 데이터이며 큰 바이너리 파일에 포함됩니다.또한 나는 단지 로딩 루틴을 바꾸기를 원합니다. 1000 라인의 코드 라인은 한번로드 된 데이터를 사용하는 것이 아니라 std :: string의 변경이 필요합니다. –

+0

그런 다음 특정 문자열 구현을 확인한 다음 GMan의 대답을 사용하여 'is.read'다음에 스트림을 확인하십시오. –

답변

11

std::string에 의해 그것을 할 수있는 것은 동일한 기능을 수행 할 수 있습니다 당신이 사용할 수있는 resize 함수 또는 생성자가 :

boost::uint16_t len; 
is.read((char*)&len, 2); 

std::string str(len, '\0'); 
is.read(&str[0], len); 

이 안된이며, I 문자열에 연속 된 저장 공간이 있어야하는지 여부는 알 수 없습니다.

+0

문자열은 벡터로 정의됩니다. 같은 연속성. – bmargulies

+4

이들은 벡터로 정의되지 않지만 21.3.4/1은 연속적인 저장을 의미합니다. 그러나 그 특정 섹션에 대한 혼란과 결함 보고서가 있으며, 현재의 합의가 무엇인지, 그 해석에 따라 어떻게 이식성이 있는지는 확실하지 않습니다. –

+2

@Roger. 나는 21.3.4/1이 연속적인 저장을 의미한다는 것에 동의하지 않는다. 효율적인 구현에는 연속 된 저장소가 구현되어 있어야하기 때문에 c_str() 및 data()가 해당되는 것을 의미합니다. 나는 표준의 다음 버전이 또한 상황을 모호하게한다고 믿는다. –

0

코드 길이를 최적화하거나 여기에 사본을 저장하려고합니까? 임시 버퍼의 문제점은 무엇입니까?

나는 직접 작성하려고하는 문자열의 보호를 우회하고 있다고 주장 할 것입니다. std :: string에 대한 복사본의 성능이 응용 프로그램의 성능에 어떤 영향을 미치는지 확인했기 때문에 성능이 걱정된다면 char *로 직접 작업 할 것입니다.

편집 :. 활용하기 찾고 ... 두 번째 대답에서 initializing std::string from char* without copy

, 당신이 달성하기 위해 무엇을 찾고있어 달성 할 수 꽤 단호하게 언급 한 것 (즉, 표준을 채울 : 문자열을하지 않고 char *를 복사 할 때의 반복)

로드 루틴을 살펴보고 할당을 최소화하십시오. new 및 delete는 자유롭지 않으므로 적어도 버퍼를 계속해서 다시 만들 필요는 없습니다. 나는 언제나 도움이 버퍼를 0으로 memset'ing 또는 null 각 배열의 첫 번째 인덱스를 종료하여 null을 찾을 수 있지만 신속하게 알고리즘의 성능에 대한 관심에서 코드를 제거 할 수 있습니다 귀하의 알고리즘에 자신감이야.

+0

std :: string의 성능은 양호합니다. 문제는 현재 받아 들일 수 없을만큼 오랜 시간 동안 걸리는 바이너리 파일에서 데이터를로드하는 것입니다. 프로파일 링은로드 시간의 70 %가 문자열을 읽는 것으로 나타났습니다. 단 30 %만이 다른 이진 데이터 또는 작은 비트로 처리되므로 문자열 읽기 속도가 빨라지므로 모든 것을 주요 마진으로 가속화하는 확실한 해결책이 될 수 있습니다. 그래서 나는 프로그램의 나머지 부분에서 std :: string을 바꾸고 싶지 않다. 단지 문자열 로딩 루틴을 바꾸는 것보다 1000 줄을 바꾸는 것을 의미한다. –

+0

모든 반복에서 char *의 alloc, dealloc은 얼마나 큰 이슈입니까? 만약 당신이 단순히 충분한 크기의 char *를 유지하고 (분명히 각 반복을 체크하는 것), 그 단일 char *로부터 새로운 문자열을 생성한다면 어떨까요? – antik

2

당신의 getline 같은 것을 사용할 수 있습니다

#include <iostream> 
#include <string> 
using namespace std; 

int main() { 
    string str; 
    getline (cin,str,' '); 
} 
+1

이것은 다른 문제에 대한 좋은 제안이지만,이 문제는 아닙니다. 특정 바이트 수의 형식이 지정되지 않은 입력입니다. –

+0

이것은 지정된 바이트 수를 읽지 않기 때문에 질문에 대답하지 않습니다. 비록 그것이했다면, getline은 바이트 수를 지정할 때 값 비싸고 불필요한 분리 문자를 읽는 모든 바이트를 조사해야합니다. 이 답변은 삭제해야합니다. – xaxxon

2

나는 버퍼로 벡터를 사용합니다.

boost::uint16_t len; 
is.read((char*)&len, 2); // Note if this file was saved from a different architecture 
         // then endianness of these two bytes may be reversed. 

std::vector buffer(len); // uninitialized. 
is.read(&buffer[0], len); 

std::string str(buffer.begin(),buffer.end()); 

(GMan에서 설명한대로) 버퍼로 문자열을 사용하지 않을 수도 있습니다. 문자열 멤버가 연속 된 위치에 있다는 것이 표준에 의해 보장되지는 않습니다 (따라서 현재 구현을 확인하고 다른 컴파일러/플랫폼으로 이식 할 때 검사해야한다는 큰 의견을 말합니다).

+0

"문자열 멤버가 연속 된 위치에 있음을 표준으로 보장하지 않습니다."<== 분명히 '11 – xaxxon

+0

@ xaxxon : True였습니다. 그러나 위의 코드는 연속적인 위치에 요소를 저장하기 위해 문자열을 요구하지 않습니다. 이제 벡터 (그리고 우연히 언급 된 문자열)를 언급한다면이 코드는 그 가정을합니다. 그러나 C++ 11부터 언급했듯이 이것이 보장되었습니다. 또한 2011 년 C++ 표준이 업데이트되기 전에 모든 주요 구현에 대한 설문 조사가 있었으며 (모두 2007 년) 연속 벡터로 구현 된 벡터가 표준을 쉽게 업데이트했습니다. –

5

당신은 copy_n의 조합과 insert_iterator

void test_1816319() 
{ 
    static char const* fname = "test_1816319.bin"; 
    std::ofstream ofs(fname, std::ios::binary); 
    ofs.write("\x2\x0", 2); 
    ofs.write("ab", 2); 
    ofs.close(); 

    std::ifstream ifs(fname, std::ios::binary); 
    std::string s; 
    size_t n = 0; 
    ifs.read((char*)&n, 2); 
    std::istream_iterator<char> isi(ifs), isiend; 
    std::copy_n(isi, n, std::insert_iterator<std::string>(s, s.begin())); 
    ifs.close(); 
    _unlink(fname); 

    std::cout << s << std::endl; 
} 

없이 복사, 아니 해킹, 오버런, 아니 정의되지 않은 동작없이 가능성을 사용할 수 있습니다.

+0

내가하고있는 일을하고 있다면,이 [link] (http://www.boost.org/doc/libs/1_46_0/libs/serialization/doc/index.html)와 코드를 읽으십시오. 그것은 그것과 함께 간다. –

+0

여기에 해당하지 않지만 파일의 끝이나 오류가 발생하면'copy_n'이 안전합니까? – Liviu

+0

[code review] (http://codereview.stackexchange.com/questions/38148/updating-a-file-through-c-streams) 메소드를 사용하여 몇 가지 코드를 만들었습니다. 감사! – Liviu

0

쉬운 방법은 다음과 같습니다

std::istream& data 
const size_t dataSize(static_cast<size_t>(data.rdbuf()->in_avail())); 
std::string content; 
content.reserve(dataSize); 
data.read(&content[0], dataSize); 
관련 문제