2017-03-26 185 views
1

一個std :: ifstream的我有一個阿拉伯語的文件(ASCII),其中包含: 121101الزبونكمال 121102الزبونسعيد 121103الزبونعمار閱讀ASCII文本文件,使用C++

我想用閱讀該文件一個std :: ifstream的在C++如:

std::ifstream ifs(file.GetFileName()); 
std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()); 

當我觀看過使用VS IDE內容變量,我得到了字符編碼錯誤: 121101ÇáÒÈæäßãÇá 121102ÇáÒÈæäOUII 121103 ÇáÒÈæäUACN

另外我有一個托盤的std :: wifstream:

std::wifstream ifs2(file.GetFileName()); 
std::string content2((std::istreambuf_iterator<wchar_t>(ifs2)), std::istreambuf_iterator<wchar_t>()); 

我已經得到了同樣的錯誤。 有人可以幫我嗎? 謝謝。

+1

ASCII沒有阿拉伯字符。找出它實際上是什麼編碼並讀取它,但'iostream'不是那麼好,所以你可能想使用一個OS特定的函數或其他庫來爲你做。 – nwp

+0

據我所知ASCII有一個代碼頁參數,我怎麼能通過這個參數ifstream! –

+0

你可以用'wifstream :: imbue()'方法做到這一點,看我的答案。 – zett42

回答

1

I have an Arabic file (ASCII), which contains: 121101 الزبون كمال 121102 الزبون سعيد 121103 الزبون عمار

一些澄清後,OP想:

to write general function which read uft8 and ANSI files

爲了能夠治療以同樣的方式的內容,我建議轉換爲UTF-16編碼std::wstring。 OP似乎是針對Windows平臺開發的,其中UTF-16是大多數API所期望的編碼。在其他平臺(Linux)上,可能更適合將所有內容轉換爲UTF-8。

閱讀ANSI文本文件轉換成UTF-16編碼的wstring

爲了能夠ANSI(又稱擴展ASCII)解碼,我們必須知道文件的codepage

可以通過流的imbue()方法來定義代碼頁(或更準確地說,區域設置)。在你的情況下,代碼頁是1256

下面的示例讀取被編碼與ANSI代碼頁1256和顯示使用MessageBoxW()其預計的UTF-16編碼的字符串的文本的文本文件的內容:

#include <fstream> 
#include <string> 
#include <codecvt> 
#include <Windows.h> 

int main() 
{ 
    // Use wifstream because we want to read content into a wstring. 
    std::wifstream f{"test.txt"}; 

    // Define the code page of the text file (1256 = Arabic) 
    f.imbue(std::locale(".1256")); 

    // Read the whole file into a wstring. 
    // The stream converts from ANSI to UTF-16 encoding. 
    std::wstring s{ std::istreambuf_iterator<wchar_t>(f), std::istreambuf_iterator<wchar_t>() }; 

    // Display the string which is now UTF-16 encoded.  
    ::MessageBoxW(NULL, s.c_str(), L"test", 0); 

    return 0; 
} 

:本std::locale參數是平臺特定的。 「.1256」適用於Windows平臺,但這可能不適用於Linux。

閱讀UTF-8編碼的文本文件轉換成UTF-16編碼的wstring

爲此,我們可以採用std::codecvt_utf8_utf16方面。 用下面的代碼替換imbue()呼叫前面的例子中:

f.imbue(std::locale(f.getloc(), 
     new std::codecvt_utf8_utf16< wchar_t, 1114111UL, std::consume_header>)); 

std::consume_header跳過byte order mark如果它存在的標誌。

注:

  • 代碼樣本已與VS2017的Windows 10下進行了測試與德國的本地化。
  • 爲簡潔起見,我省略了錯誤處理。流狀態應在打開後和流之後檢查。

創建一個通用的解決方案

以上的代碼示例需要你知道的文本文件的編碼事前。以真正通用的方式檢測文本文件的編碼是一項艱鉅的任務,因爲沒有這樣做的標準方法。它不能可靠地完成,你必須使用一些啓發式。

如果你可以對你必須處理的文件做一些假設,你可以編寫一個簡單的檢測函數。說這些文件只分爲以下幾類:

  • ANSI與代碼頁1256
  • UTF-8編碼的文件,BOM編碼的文件(byte order mark

然後,你可以閱讀前3個字節使用std::ifstream的文件,並將它們與{0xEF, 0xBB, 0xBF}進行比較。如果相等,則可以相對確定該文件是UTF-8編碼的,因爲非UTF-8編碼文件不太可能以這些字節開始。如果不相等,則會假設代碼頁1256.

+0

謝謝@ zett42 您的代碼工作正常,但爲什麼當我嘗試imbu方法爲: std :: ifstream ifs(「test.txt」); ifs.imbue(std :: locale(「.1256」)); ((std :: istreambuf_iterator (ifs)),std :: istreambuf_iterator ()); std :: istreambuf_iterator () 這不起作用?!!!!! –

+0

@Bassam如果你使用'ifstream'而不是'wifstream'就沒有轉換,所以'imbue()'什麼也不做。你得到的字符串與文件中的編碼相同。你想用'content'做什麼? – zett42

+0

@Bassam我在其他答案下閱讀_我的函數有時讀取一個utf8文件,有時讀取一個ASCII文件_。如果你願意,我可以添加一個例子來用'wifstream'讀取UTF-8文件。 – zett42

-3

爲什麼不使用FILE *呢?例如,這是我的代碼摘錄,我正在閱讀包含不同保存遊戲條目的我的遊戲的save.ini。我喜歡fopen()的是你可以真正知道文件的格式(如UTF-8,UTF-16等)。

FILE* pFini = fopen ("save\\save.ini", "rt,ccs=UTF-8"); 
int iLine = 0; 

if (pFini == NULL) 
{ 
    cout << "WARNING: cannot open save.ini file." << endl; 
    return; 
} 

while (!feof (pFini)) 
{ 
    fgetws (wSaveGames [iLine], 125, pFini); 
    iLine++; 
    if (iLine >= MAX_SAVEGAME_NUMBER) 
     break; 
} 
fclose (pFini); 
+0

問題標記爲'C++'和'ifstream',因此提出一個C解決方案是沒有用的。 – zett42

+0

Pfft,試圖幫助我的知識在這裏。適用於c的工具也適用於C++。我個人使用兩種,爲什麼不使用。 – Andy8888

+0

我的函數有時會讀取一個utf8文件,有時讀取一個ASCII文件,所以我使用了一個ifstream和std :: string。 –