This is an extension of this question: fstream not opening files with accent marks in pathname
The problem is the following: a program opening a simple NTFS text file with accent marks in pathname (e.g. à, ò, ...). In my tests I'm using a file with pathname I:\università\foo.txt (università is the Italian translation of university)
The following is the test program:
#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);
}
}
The source file is saved with UTF-8 encoding. I'm using Windows 8.
This is the output of the program compiled with 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
This is the output using MinGW g++
fopen() failed: No such file or directory
Exception basic_ios::clear
CreateFile failed: error number 3
File opened with CreateFileW!
So let's go to the questions:
- Why fopen() and std::ifstream works in a similar test in Linux but they don't in Windows?
- Why CreateFileW() works only compiling with g++?
- Does exist a cross-platform alternative to CreateFile?
I hope that opening a generic file with a generic pathname could be done without the necessity of platform-specific code, but I have not idea how to do it.
Thanks in advance.