2013-02-08 106 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*慢。

我有一個確認也是在下面的測試:

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

與VS2010 SP1(VC10)編譯:

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兆字節的數據;無論你如何做,這都需要一些時間。

你不明確你正在做什麼。 (我猜測真正的問題不涉及千萬次"Hi"。)根據這一點,可能會使用低級IO,甚至可能使用mmap。但是這些都沒有格式化,如果你首先格式化爲ostringstream,你可能會發現它們並沒有明顯更快。

1

通過C FILE *接口將大量字符串寫入文件的最快方法是(很可能)。當然,C++流接口的性能不如FILE *。理想情況下,如果您建立幾KB(一次4KB)的緩衝區,並使用fwrite(buffer, size_of_buffer, 1, outfile);編寫該緩衝區,則應該非常接近系統的性能。是的,您可以分別使用writeWriteFile的本機接口分別對Linux/Unix和Windows調整0.5%左右。

當然缺點是你沒有簡單的方法來爲任意新類型添加一個輸出方法。

與往常一樣,當涉及到性能時,測量不同的選項,並查看哪些出現最佳。如果在不同環境下許多機器上都會使用它,那麼使用不同的硬件,不同的內存和系統負載進行測試也是很好的選擇,以確定您不僅僅是讓機器運行得更快,對具有不同條件的系統給出合理的改進[或者至少沒有壞的缺點]。