簡體   English   中英

如何將std :: wstring寫入文件?

[英]How to portably write std::wstring to file?

我有一個聲明的wstring

// random wstring
std::wstring str = L"abcàdëefŸg€hhhhhhhµa";

文字將是UTF-8編碼,因為我的源文件是。

[編輯:根據Mark Ransom,情況不一定如此,編譯器將決定使用什么編碼 - 讓我們假設我從例如UTF-8編碼的文件中讀取此字符串]

我非常希望將其轉換為文件讀取(當文本編輯器設置為正確的編碼時)

abcàdëefŸg€hhhhhhhµa

但是ofstream不是很合作(拒絕接受wstring參數), wofstream據說需要知道語言環境和編碼設置。 我只想輸出這組字節。 通常如何做到這一點?

編輯:它必須是跨平台的, 不應該依賴於UTF-8編碼 我碰巧有一組存儲在wstring的字節,並希望輸出它們。 它很可能是UTF-16或純ASCII。

對於std::wstring您需要std::wofstream

std::wofstream f(L"C:\\some file.txt");
f << str;
f.close();

std::wstring用於UTF-16或UTF-32, 而不是 UTF-8。 對於UTF-8,您可能只想使用std::string ,並通過std::cout寫出來。 只是FWIW,C ++ 0x將具有Unicode文字,這應該有助於澄清這樣的情況。

為什么不把文件寫成二進制文件。 只需在std :: ios :: binary設置中使用ofstream即可。 編輯應該能夠解釋它。 不要忘記開頭的Unicode標志0xFEFF。 你最好用圖書館寫作,試試其中一個:

http://www.codeproject.com/KB/files/EZUTF.aspx

http://www.gnu.org/software/libiconv/

http://utfcpp.sourceforge.net/

C ++具有在輸出或文件寫入時執行從寬字符到本地字符的轉換的方法。 為此目的使用 codecvt facet。

您可以使用標准的std :: codecvt_byname或非標准的codecvt_facet 實現

#include <locale>
using namespace std;
typedef codecvt_facet<wchar_t, char, mbstate_t> Cvt;
locale utf8locale(locale(), new codecvt_byname<wchar_t, char, mbstate_t> ("en_US.UTF-8"));
wcout.imbue(utf8locale);
wcout << L"Hello, wide to multybyte world!" << endl;

請注意,在某些平台上,codecvt_byname只能為系統中安裝的區域設置發出轉換。 因此,我建議在stackoverflow中搜索“utf8 codecvt”,並從列出的自定義codecvt實現的許多參考中做出選擇。

編輯:由於OP聲明字符串已經編碼,他應該做的就是從代碼的每個標記中刪除前綴L和“w”。

有一個(Windows專用)解決方案,它應該為你工作在這里 基本上,將wstring轉換為UTF-8代碼頁然后使用ofstream

#include < windows.h >

std::string to_utf8(const wchar_t* buffer, int len)
{
        int nChars = ::WideCharToMultiByte(
                CP_UTF8,
                0,
                buffer,
                len,
                NULL,
                0,
                NULL,
                NULL);
        if (nChars == 0) return "";

        string newbuffer;
        newbuffer.resize(nChars) ;
        ::WideCharToMultiByte(
                CP_UTF8,
                0,
                buffer,
                len,
                const_cast< char* >(newbuffer.c_str()),
                nChars,
                NULL,
                NULL); 

        return newbuffer;
}

std::string to_utf8(const std::wstring& str)
{
        return to_utf8(str.c_str(), (int)str.size());
}

int main()
{
        std::ofstream testFile;

        testFile.open("demo.xml", std::ios::out | std::ios::binary); 

        std::wstring text =
                L"< ?xml version=\"1.0\" encoding=\"UTF-8\"? >\n"
                L"< root description=\"this is a naïve example\" >\n< /root >";

        std::string outtext = to_utf8(text);

        testFile << outtext;

        testFile.close();

        return 0;
}

請注意,寬流只輸出char *變量,因此您可能應該嘗試使用c_str()成員函數轉換std::wstring ,然后將其輸出到文件中。 它應該可行嗎?

我前段時間遇到了同樣的問題,並寫下了我在博客上找到的解決方案。 您可能需要查看它是否有幫助,尤其是函數wstring_to_utf8

http://pileborg.org/b2e/blog5.php/2010/06/13/unicode-utf-8-and-wchar_t

如果你想寫可以移植的代碼,你應該使用UTF-8編碼的源文件。 抱歉。

std::wstring str = L"abcàdëefŸg€hhhhhhhµa";

(我不確定這是否真的傷害了標准,但我認為是。但即使為了安全,你也不應該。)

是的,純粹使用std::ostream行不通的。 有很多方法可以將wstring轉換為UTF-8。 我最喜歡的是使用Unicode國際組件 這是一個很大的庫,但它很棒。 你會得到很多額外的東西以及將來可能需要的東西。

根據我使用不同字符編碼的經驗,我建議您只在加載時處理UTF-8並節省時間。 如果您嘗試將內部表示存儲在UTF-8中,那么您將陷入痛苦的世界,因為單個字符可以是1字節到4之間的任何內容。因此像strlen這樣的簡單操作需要查看每個字節來決定len而不是分配緩沖區(盡管您可以通過查看char序列中的第一個字節進行優化,例如00..7f是單字節char,c2..df表示2字節char等)。

人們經常在稱為UTF-16時引用“Unicode字符串”,而在Windows上,wchar_t是固定的2字節。 在Windows中,我認為wchar_t只是:

typedef SHORT wchar_t;

完整的UTF-32 4字節表示很少需要且非常浪費,這就是Unicode標准(5.0)必須說的:

“平均而言,超過99%的UTF-16使用單一代碼單元表達...... UTF-16提供了緊湊尺寸的正確組合,能夠處理BMP之外的偶然角色”

簡而言之,使用whcar_t作為內部表示,並在加載和保存時進行轉換(除非您知道需要,否則不要擔心完整的Unicode)。

關於執行實際轉換,請查看ICU項目:

http://site.icu-project.org/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM