これは、この質問の拡張です: fstream がパス名にアクセント記号を含むファイルを開かない
問題は次のとおりです。プログラムが、パス名にアクセント記号が付いた単純な NTFS テキスト ファイル(例: à、ò、...) を開きます。私のテストでは、パス名が I:\università\foo.txt のファイルを使用しています( università はUniversityのイタリア語訳です)
以下はテストプログラムです。
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
#include <errno.h>
#include <Windows.h>
using namespace std;
LPSTR cPath = "I:/università/foo.txt";
LPWSTR widecPath = L"I:/università/foo.txt";
string path("I:/università/foo.txt");
void tryWithStandardC();
void tryWithStandardCpp();
void tryWithWin32();
int main(int argc, char **argv) {
tryWithStandardC();
tryWithStandardCpp();
tryWithWin32();
return 0;
}
void tryWithStandardC() {
FILE *stream = fopen(cPath, "r");
if (stream) {
cout << "File opened with fopen!" << endl;
fclose(stream);
}
else {
cout << "fopen() failed: " << strerror(errno) << endl;
}
}
void tryWithStandardCpp() {
ifstream s;
s.exceptions(ifstream::failbit | ifstream::badbit | ifstream::eofbit);
try {
s.open(path.c_str(), ifstream::in);
cout << "File opened with c++ open()" << endl;
s.close();
}
catch (ifstream::failure f) {
cout << "Exception " << f.what() << endl;
}
}
void tryWithWin32() {
DWORD error;
HANDLE h = CreateFile(cPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) {
error = GetLastError();
cout << "CreateFile failed: error number " << error << endl;
}
else {
cout << "File opened with CreateFile!" << endl;
CloseHandle(h);
return;
}
HANDLE wideHandle = CreateFileW(widecPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (wideHandle == INVALID_HANDLE_VALUE) {
error = GetLastError();
cout << "CreateFileW failed: error number " << error << endl;
}
else {
cout << "File opened with CreateFileW!" << endl;
CloseHandle(wideHandle);
}
}
ソース ファイルは UTF-8 エンコーディングで保存されます。Windows 8 を使用しています。
これは、VC++ (Visual Studio 2012) でコンパイルされたプログラムの出力です。
fopen() failed: No such file or directory
Exception ios_base::failbit set
CreateFile failed: error number 3
CreateFileW failed: error number 3
これは MinGW g++ を使用した出力です
fopen() failed: No such file or directory
Exception basic_ios::clear
CreateFile failed: error number 3
File opened with CreateFileW!
それでは、質問に行きましょう:
- fopen() と std::ifstream が Linux の同様のテストで機能するのに、Windows では機能しないのはなぜですか?
- CreateFileW() が g++ でのコンパイルでのみ機能するのはなぜですか?
- CreateFile のクロスプラットフォームの代替手段はありますか?
プラットフォーム固有のコードを必要とせずに汎用パス名で汎用ファイルを開くことができることを願っていますが、その方法がわかりません。
前もって感謝します。