Как открыть и прочитать содержимое файла с путем Unicode или именем файла с помощью стандартного API?
Как открыть файл, путь или имя файла которого содержит символы Юникода, и читать или записывать его содержимое без использования какого-либо специального API? Как это сделать, используя только библиотеки std, если это возможно, или используя только Windows API? Я попробовал std::wifstream, чтобы открыть файл, как в примере кода ниже, но он не компилируется. Похоже, что он принимает не аргумент const wchar_t*, а const char*. Я использую компилятор TDM-GCC 4.7.1, который входит в состав Dev-C++ IDE.
#ifndef UNICODE
#define UNICODE
#endif
...
#include <clocale>
#include <windows.h>
#include <fstream>
...
int main(int argc, char **argv)
{
setlocale(LC_ALL, "Polish_Poland.852") ;
...
fileCompare(first, second) ;
...
}
...
bool fileCompare(wstring first, wstring second) // This function doesn't compile !
{
using namespace std ;
wifstream fin0(first.c_str(), ios::binary) ;
wifstream fin1(second.c_str(), ios::binary) ;
...
}
Некоторый полный пример:
#ifndef UNICODE
#define UNICODE
#endif
#include <clocale>
#include <conio.h>
#include <windows.h>
#include <fstream>
#include <string>
#include <iostream>
using namespace std ;
bool fileCompare(wstring first, wstring second) ;
int main(int argc, char **argv)
{
setlocale(LC_ALL, "Polish_Poland.852") ;
wstring first, second ;
first = L"C:\\A.dat" ;
second = L"C:\\E.dat" ;
fileCompare(first, second) ;
getch() ;
return 0 ;
}
bool fileCompare(wstring first, wstring second) // This function doesn't compile !
{
wifstream fin0(first.c_str(), ios::binary) ;
wifstream fin1(second.c_str(), ios::binary) ;
}
Также, когда я заменяю L"C:\A.dat" и L"C:\E.dat" на строки, содержащие польские символы, выдается ошибка о недопустимой последовательности байтов.
1 ответ
Вайфстрим не занимается проблемой кодировки имен файлов. Насколько я знаю, имена файлов wifstream и ifstream основаны на char, а не на wchar_t. Вам нужно будет указать имя файла в кодировке char, используемой вашей ОС, например, latin1, utf8 и т. Д.
Однако, wifstream позволяет читать поток wchar_t. Вы можете сообщить потоку, какой вклад вы ожидаете, передав потоку:
например
// We expect the file to be UTF8 encoded
std::locale locale("en_US.utf8");
fin0.imbue(locale);
РЕДАКТИРОВАТЬ: Если вам нужно преобразовать имена файлов (или любую строку) из wchar_t в соответствующую кодировку символов, вы можете глубже погрузиться в тему фасетов codecvt локалей.
// Method translates wchar_t => pl_PL.iso88592" encoding
std::string to_string(const std::wstring & wstr)
{
typedef std::codecvt< wchar_t, char, std::mbstate_t > ccvt_t;
std::locale loc("pl_PL.iso88592");
const ccvt_t & facet = std::use_facet<ccvt_t>( loc );
std::string s;
{
std::mbstate_t st=mbstate_t();
const wchar_t *wac = wstr.c_str();
const wchar_t *wou = wac + wstr.length();
const wchar_t *wnx = wac;
ccvt_t::result r = ccvt_t::ok;
while(wou!=wnx && (r==ccvt_t::ok || r==ccvt_t::partial))
{
static const int l = 100;
static char cou[l];
char *cnx=NULL;
r = facet.out(st,wac,wou,wnx,cou,cou+l,cnx);
s+=std::string(cou,cnx-cou);
wac=wnx;
}
}
return s;
}
Какой тип std::locale поддерживается и как вы можете указать его, может зависеть от ОС.