C++fstream文件流處理對中文字符不支持的解決辦法


  今天由於要寫代碼規總,提交文檔。由於文件太多一個個復制覺得麻煩,就想着自己寫一個程序完成這項任務。

  任務目標:就是把指定文件夾里的所有簡單文檔的內容全部寫入到一個文檔內!!!

【以下內容轉自:我住包子山 讓VS2005中的fstream支持中文路徑文件打開 】

  前幾天發了這篇《用fstream對二進制文件的讀寫》,有朋友指出了VS2005的fstream對於中文路徑支持不好的bug。我想大概是因為VS2005更加重視了對字符串的全球化支持,所以鼓勵我們使用unicode編碼的字符串,對於MBCS之類的支持可能就疏忽了吧。

  我搜索了一下這個問題的解決,參考了如下資料寫了演示代碼。

   我綜合了以上的內容,總結了3種方法,能夠較好解決大家的困擾,包括可能無法使用cout的問題。

  PS: 補充一下,第一種方法,如果不是靜態字符串當作路徑的話,記得傳入TCHAR*類型字符串作為路徑,應該就沒問題了。

View Code
/********************************************************************
*    created:    2008/05/10
*    created:    10:5:2008   23:56
*    filename:     k:\sj\fstreamTest\fstreamTest\main.cpp
*    file path:    k:\sj\fstreamTest\fstreamTest
*    file base:    main
*    file ext:    cpp
*    author:        Gohan
*********************************************************************/
#include <tchar.h>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
    /************************************************************************/
    /* 方法1,使用_TEXT()宏定義將字符串常量指定為TCHAR*類型                 */
    /* 如果是我,首選此類型                                                 */
    /************************************************************************/
    fstream file;
    file.open(_TEXT("c:\\測試\\測試文本.txt"));
    cout<<file.rdbuf();
    file.close();

    /************************************************************************/
    /* 方法2,使用STL中的locale類的靜態方法指定全局locale                   */
    /* 使用該方法以后,cout可能不能正常輸出中文,十分蹊蹺                    */
    /* 我發現了勉強解決的方法:不要在還原區域設定前用cout或wcout 輸出中文   */
    /* 否則后果就是還原區域設定后無法使用cout wcout輸出中文                 */
    /************************************************************************/
    locale::global(locale(""));//將全局區域設為操作系統默認區域
    file.open("c:\\測試\\測試文本2.txt");//可以順利打開文件了
    locale::global(locale("C"));//還原全局區域設定
    cout<<file.rdbuf();
    file.close();

    /************************************************************************/
    /* 方法3,使用C函數setlocale,不能用cout輸出中文的問題解決方法同上      */
    /************************************************************************/
    setlocale(LC_ALL,"Chinese-simplified");//設置中文環境
    file.open("c:\\測試\\測試文本3.txt");//可以順利打開文件了
    setlocale(LC_ALL,"C");//還原
    cout<<file.rdbuf();
    file.close();
}

運行結果

【我的編寫結果和結論】

  前面的對錯暫且不論。(事實上我用過其中的方法,大致是可行的,而且從代碼風格和嚴謹的布局注釋來看,作者必成牛人!)
  1. C++流處理是不支持中文字符的。包括標准以及非標准流輸入、輸出、以讀、寫方式打開文件名、以及操作文件的路徑。
  2. C++的流處理以二進制讀寫,“endl” 符號用txt打開后,只能看見一個黑方塊。
  3. C++文件以單個字符方式讀寫,會把換行符丟失。

【code 1】測試code1

#include <iostream>
#include <fstream>
#include <string>
#include <locale>

#include <windows.h>

using namespace std;
int main()
{
    locale &loc=locale::global(locale(locale(),"",LC_CTYPE));  // 不論以輸出文件流還是輸入文件流,此操作應放在其兩邊 
    ifstream ofs(".\\op\\工作所得.txt");
    wifstream wofs(L".\\op\\工作所得1.txt"); // 當前目錄開始
    locale::global(loc);  

    string bs;
    char ba[1024];
    ofs.getline(ba, 1024);
    cout << ba;

    //ofs<<"test測試"<<1234<<endl;
    //wofs<<L"Another test還是測試"<<1234<<endl;
    return 0;
}

 

【code2】 這個是我最終的成果的簡單版本。(為我解決一大概40M的總代碼匯總,分開匯總零散的運行近30分鍾)

#include <iostream>
#include <fstream>
#include <string>
#include <locale>

#include <windows.h>

using namespace std;

int main(int argc, _TCHAR* argv[])
{
    WIN32_FIND_DATA FindFileData;
    HANDLE hFind = FindFirstFile(_T(".\\op\\*.*"), &FindFileData); // 查找當前目錄下op目錄里的所有文件
    if (hFind == INVALID_HANDLE_VALUE) 
    {        cout << "find file err" << endl;    return 0;    } 
    else 
    {    
        FindNextFile(hFind, &FindFileData); // . 點目錄
        FindNextFile(hFind, &FindFileData); // .. 兩點目錄。 放在循環外面
        do{
            char tempchar[1024];
            string cs_infilename = ".\\op\\" ;
            cs_infilename += FindFileData.cFileName;
            
            // 此操作放在打開操作兩側。(我原來是把out放在程序最前頭,只打開一次。in放在中間每循環一次打開一次。當時沒成功!!!后來改成了追加模式)
            locale &loc=locale::global(locale(locale(),"",LC_CTYPE));  
            ofstream out("unicom.txt", ios_base::app);
            ifstream in(cs_infilename.c_str());
            locale::global(loc); 

            cout <<"// " << cs_infilename.c_str()<<endl;    // 在控制台顯示操作效果
            out <<"// " << cs_infilename.c_str()<<endl;        // 文件內注釋文件名

            if (!in.is_open()) 
            { 
                cout << "Error opening in file: " << cs_infilename <<endl; 
                exit (1);
            }
            string infilebuffer;
            while (getline(in,infilebuffer))
            {
                out << infilebuffer <<endl;
                cout << infilebuffer <<endl;
            }
            out <<"// END: " << cs_infilename.c_str()<<endl; // END:文件內注釋文件名

            out.close();
            in.close();
        }while (FindNextFile(hFind, &FindFileData) != 0);
    }
    FindClose(hFind);
    return 0;
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM