2014-01-30 32 views
0

我正在編譯我的庫,它支持unicode,現在我遇到了需要打開ASCII數據文件的問題,但當然文件名是widechars。那麼我怎麼做到這一點?使用unicode名稱打開輸入文件流,但使用ASCII數據

當我使用此代碼:

std::wstring s = L"path"; 
std::ifstream fl; 
fl.open(s.c_str(), std::fstream::in); 

然後我得到這個錯誤:

error: no matching function for call to 'std::basic_ifstream<char>::open(const wchar_t*, const openmode&)' 

當我使用

std::wifstream fl; 
fl.open(s.c_str(), std::fstream::in); 

我得到同樣的錯誤(? ??)

error: no matching function for call to 'std::basic_ifstream<wchar_t>::open(const wchar_t*, const openmode&)' 

即便如此,當我使用std::wifstream時,流期望輸入數據是否也是unicode?如果是這樣,那麼我將不得不使用std::ifstream,但我仍然需要傳遞它的寬字符串,或者以某種方式將其轉換爲ASCII。什麼是正確的方法來做到這一點?

我使用MingW gcc 4.8.3。

mingw32-g++.exe -pedantic -std=c++11 -Wextra -Wall -g -D_UNICODE -D_WIN32 -Iinclude -c propertyfile.cpp -o propertyfile.o 

回答

-1

事情是這樣的:

std::wstring s = L"path"; 
std::string ansi(begin(s), end(s)); 
std::ifstream fl (ansi); 

如果文件是ASCII,則不能使用wifstream。

注意它只在路徑是純ASCII時才起作用。

+1

這是爲什麼downvoted?轉換是錯誤的,還是僅僅是因爲大括號錯誤? – Devolus

+0

我不知道,這是完全合法的C++ 11代碼。 http://coliru.stacked-crooked.com/a/ab322f7b56e94c71 – galop1n

+0

因爲答案的每個方面都不正確? – Simple

-1

試試這個:

fl.open(s.c_str(), std::ios_base::in); 

我不知道有關的mingw32-G ++,但你應該在MS編譯器使用ios_base。 至於它期望的數據 - 是的,它會期望unicode或ansi取決於類型,但只有當你閱讀它的文本。 將其讀取爲二進制數據,然後將其複製到您的ansi數組中,然後您將從unicode文件中獲取ansi文本。

+0

操作系統詢問有關文件名爲UTF-8的情況。您的解決方案無法打開UTF-8編碼的文件名。 – rents

2

這個問題沒有簡單的解決方案。 我有這兩種想法:

  1. 嘗試與_wfopen創建自己的文件流BUF。
  2. 使用boost-library。 Boost.Filesystem
+1

+1。這很不幸,但是Windows文件名是以UTF-16代碼單元(Windows上的'wchar')來指定的,而Unix文件名則以字節('char',通常在現代Linux/OSX中被解釋爲UTF-8) 。您必須在面向字節的C標準庫調用和特定於Windows的調用(如'_wfopen'或像OpenFileW這樣的直接Win32 API對應項)之間切換,這取決於您正在運行的平臺,這很令人傷心。 (或者,如前所述,請使用圖書館爲您提供幫助。) – bobince

+1

+1,這個答案比接受的答案要好得多。 – Philipp

0

std::ifstream只是一個std::istream有一個簡單的方法來設置一個文件作爲目標。因爲它不允許使用UTF-8,所以您必須以另一種方式設置文件。通過查看istream constructors,您應該注意到std::streambuf(也可以設置/替換爲rdbuf)。現在你可以編寫自己的streambuf派生類,它使用_wfopen,但不需要:MinGW有一個擴展,名爲__gnu_cxx::stdio_filebuf#include <ext/stdio_filebuf.h>)。

從來源:

/** 
    * @param __fd An open file descriptor. 
    * @param __mode Same meaning as in a standard filebuf. 
    * @param __size Optimal or preferred size of internal buffer, 
    *     in chars. 
    * 
    * This constructor associates a file stream buffer with an open 
    * POSIX file descriptor. The file descriptor will be automatically 
    * closed when the stdio_filebuf is closed/destroyed. 
    */ 
    stdio_filebuf(int __fd, std::ios_base::openmode __mode, 
     size_t __size = static_cast<size_t>(BUFSIZ)); 

    /** 
    * @param __f An open @c FILE*. 
    * @param __mode Same meaning as in a standard filebuf. 
    * @param __size Optimal or preferred size of internal buffer, 
    *     in chars. Defaults to system's @c BUFSIZ. 
    * 
    * This constructor associates a file stream buffer with an open 
    * C @c FILE*. The @c FILE* will not be automatically closed when the 
    * stdio_filebuf is closed/destroyed. 
    */ 
    stdio_filebuf(std::__c_file* __f, std::ios_base::openmode __mode, 
     size_t __size = static_cast<size_t>(BUFSIZ)); 

你唯一的工作就是std::ios_base::openmode轉化爲模式的文件描述符或文件指針。 FILE*沒有通過他的所有權,所以您仍然需要關心它,但是具有作爲刪除者的文件關閉功能的std::unique_ptr,以任何方式與您的stdio_filebuf綁定,都可以解決此問題。

MSVC支持通過std::wifstream(utf-8到utf-16轉換MultiByteToWideChar)的Unicode文件名,Clang與MinGW兼容。

現在編寫一個跨平臺的fstream類很容易。首先:從std::fstream派生。在Unix上,你的類應該像std::fstream,所以你只需要複製構造函數(C++ 11方式:using std::fstream::fstream;)。在Windows上,你必須實現構造函數(它只需調用open)並覆蓋open成員函數(最後,所有內容都只轉發到工作所在的一個打開的函數中,僅此而已)。

相關問題