2013-02-08 4 views
1

내가 쓰고 문자열을 파일에 쓰기 :C++ : 문자열을 사용하여 텍스트 파일에

ofstream ofs("ofs.txt", ios_base::binary); 
std::string str = "Hi"; 
for (int i = 0 ; i < 10000000 ; i++) { 
    ofs << str.c_str(); 
    ofs << "\n" ; 
} 

그러나, 이것은 실행 시간이 오래 걸립니다. 아무도 나에게 위의 성능을 향상시키는 방법을 알려줄 수 있습니까? 또는 파일에 문자열을 쓰는 다른 빠른 방법.

감사합니다.

+0

왜 바이너리 모드에서 문자열을 쓰고 있습니까? –

+0

텍스트 모드로만 파일을 열어야합니다. – Subhajit

+0

@BartekBanachewicz, 성능 상 오버 헤드가 발생합니까? – user1838343

답변

1

몇 가지 경우에 C++ I/O 스트림이 C <stdio.h> FILE*보다 느린 경향이 있다는 것을 발견했습니다. VS2010 SP1 (VC10)로 컴파일

#define _CRT_SECURE_NO_WARNINGS // for stupid fopen_s warning 
#include <stdio.h> 
#include <exception> 
#include <fstream> 
#include <iostream> 
#include <ostream> 
#include <stdexcept> 
#include <string> 
#include <vector> 
#include <windows.h> 
using namespace std; 

long long Counter() 
{ 
    LARGE_INTEGER li; 
    QueryPerformanceCounter(&li); 
    return li.QuadPart; 
} 

long long Frequency() 
{ 
    LARGE_INTEGER li; 
    QueryPerformanceFrequency(&li); 
    return li.QuadPart; 
} 

void PrintTime(long long start, long long finish, const char * s) 
{ 
    cout << s << ": " << (finish - start) * 1000.0/Frequency() << " ms" << endl; 
} 

// RAII wrapper to FILE* 
class File 
{ 
public: 
    explicit File(FILE * f) 
    : m_file(f) 
    {} 

    ~File() 
    { 
    fclose(m_file); 
    } 

    FILE* Get() const 
    { 
    return m_file; 
    } 

    bool IsOpen() const 
    { 
    return (m_file != nullptr); 
    } 

private: 
    FILE* m_file; 

    File(const File&); 
    File& operator=(const File&); 
}; 

void TestIoStream(const vector<string>& lines) 
{ 
    ofstream ofs("ofs.txt", ios_base::binary); 
    for(auto it = lines.begin(); it != lines.end(); ++it) 
    { 
    ofs << it->c_str(); 
    ofs << "\n" ; 
    } 
} 

void TestStdioFile(const vector<string>& lines) 
{ 
    File file(fopen("cfile.txt", "wt")); 
    if (! file.IsOpen()) 
    throw runtime_error("Can't open C FILE*."); 

    for(auto it = lines.begin(); it != lines.end(); ++it) 
    { 
    fputs(it->c_str(), file.Get()); 
    fputs("\n", file.Get()); 
    } 
} 

int main() 
{ 
    static const int kExitOk = 0; 
    static const int kExitError = 1; 
    try 
    { 
    cout << "Building test lines..."; 
    vector<string> lines; 
    for (int i = 0; i < 10000000; i++) 
     lines.push_back("Hi"); 
    cout << "done. "; 
    cout << "(Count = " << lines.size() << ")" << endl; 

    long long start = 0; 
    long long finish = 0; 

    start = Counter(); 
    TestIoStream(lines); 
    finish = Counter(); 
    PrintTime(start, finish, "C++ I/O stream"); 

    start = Counter(); 
    TestStdioFile(lines); 
    finish = Counter(); 
    PrintTime(start, finish, "C FILE*"); 

    return kExitOk; 
    } 
    catch(const exception& e) 
    { 
    cerr << "\n*** ERROR: " << e.what() << endl; 
    return kExitError; 
    } 
} 

:

cl /EHsc /W4 /nologo /MT /O2 /GL test.cpp 

시험 결과 :

Building test lines...done. (Count = 10000000) 
C++ I/O stream: 2892.39 ms 
C FILE*: 2131.09 ms 

나는 다음과 같은 시험도 확인했다

1

단지 ofs << str;을 사용하면 조금 더 빨라질 수 있습니다 (그렇지 않을 수도 있지만 확실히 더 관용적입니다). 그러나 당신은 20 메가 바이트의 데이터를 쓰고 있습니다. 그것은 당신이 어떻게하는지에 관계없이 시간이 좀 걸릴 것입니다.

정확히 무엇을 하려는지 말하지 않습니다. (나는 실제 문제가 천만 시간과 관련이 없다고 생각한다.) . 그것에 따라 저수준 IO 또는 심지어 mmap을 사용할 수도있다. 그러나 이들 중 어느 것도 서식을 지정하지 않으며, 먼저 ostringstream으로 서식을 지정해야하는 경우 상당히 빠르지 않을 수 있습니다.

1

파일에 많은 문자열을 쓰는 가장 빠른 방법은 C FILE * 인터페이스를 통해 (대부분) 가능합니다. 확실히 C++ 스트림 인터페이스가 FILE *만큼 성능이 좋지 않다는 것이 꽤 잘 설명되어 있습니다.

이상적으로는 한 번에 몇 KB (완벽하게 4KB)의 버퍼를 작성하고 fwrite(buffer, size_of_buffer, 1, outfile);을 사용하여 작성하면 시스템에서 생성 할 수있는 성능에 매우 근접해야합니다. 예, 리눅스/유닉스와 윈도우 각각에 대해 write 또는 WriteFile의 네이티브 인터페이스를 사용하여 반으로 조정할 수 있습니다.

물론 단점은 임의의 새로운 유형에 출력 방법을 추가하는 쉬운 방법이 없다는 것입니다.

언제나 성능면에서 다양한 옵션을 측정하고 어떤 것이 가장 잘 나오는 지 확인하십시오. 다른 환경에서 여러 머신에서 사용하게 될 것이라면 다른 하드웨어, 다양한 메모리 및 시스템로드로 테스트하여 머신을 더 빠르게 실행할 수는 없지만 실제로는 조건이 다른 시스템에서 합리적인 개선 [또는 적어도 나쁜 단점]을 제공합니다.

관련 문제