2015-02-19 2 views
1

Я пытаюсь написать wstring в файл UTF-8 с помощью функции WriteFile. Я хочу, чтобы в файле были эти символы «ÑÁ», но я получаю это « ».C++ WriteFile unicode characters

Вот код

#include <iostream> 
#include <cstdlib> 
#include <sstream> 
#include <string> 
#include <fstream> 
#include <windows.h> 
#include <wchar.h> 
#include <stdio.h> 
#include <winbase.h> 
using namespace std; 

const char filepath [] = "unicode.txt"; 

int main() 
{ 
    wstring str; 
    str.append(L"ÑÁ"); 
    wchar_t* wfilepath; 

    // Create a file to work with Unicode and UTF-8 
    ofstream fs; 
    fs.open(filepath, ios::out|ios::binary); 
    unsigned char smarker[3]; 
    smarker[0] = 0xEF; 
    smarker[1] = 0xBB; 
    smarker[2] = 0xBF; 
    fs << smarker; 
    fs.close(); 

    //Open and write in the file with windows functions 
    mbstowcs(wfilepath, filepath, strlen(filepath)); 
    HANDLE hfile; 
    hfile = CreateFileW(TEXT(wfilepath), GENERIC_WRITE, 0, NULL, 
     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
    wstringbuf strBuf (str, ios_base::out|ios::app); 
    DWORD bytesWritten; 
    DWORD dwBytesToWrite = (DWORD) strBuf.in_avail(); 
    WriteFile(hfile, &strBuf, dwBytesToWrite, &bytesWritten, NULL); 
    CloseHandle(hfile); 
} 

Я скомпилировать его Cygwin с помощью этой командной строки:
g++ -std=c++11 -g Windows.C -o Windows

+0

Кстати, вам не нужно использовать венгерскую нотацию, потому что Microsoft делает. Компилятор не заботится о написании идентификаторов; только то, что имена соответствуют правилам языка C++. –

+0

@ThomasMatthews: даже MS не использует (anti-) венгерскую нотацию. Их рекомендации по именованию .NET говорят ** НЕ используйте венгерскую нотацию. ** – DanielKO

+0

Прочтите http://utf8everywhere.org, чтобы узнать, как конвертировать файлы в UTF-8. –

ответ

2

Вам нужно преобразовать UTF-16 данные в UTF-8 перед записью в файл.

И нет необходимости создавать файл с std::ofstream, закройте его и откройте его с помощью CreateFileW(). Просто откройте файл один раз и напишите все, что вам нужно.

Попробуйте это:

#include <iostream> 
#include <cstdlib> 
#include <string> 
//#include <codecvt> 
//#include <locale> 

#include <windows.h> 
#include <wchar.h> 
#include <stdio.h> 

using namespace std; 

LPCWSTR filepath = L"unicode.txt"; 

string to_utf8(const wstring &s) 
{ 
    /* 
    wstring_convert<codecvt_utf8_utf16<wchar_t>> utf16conv; 
    return utf16conv.to_bytes(s); 
    */ 

    string utf8; 
    int len = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), s.length(), NULL, 0, NULL, NULL); 
    if (len > 0) 
    { 
     utf8.resize(len); 
     WideCharToMultiByte(CP_UTF8, 0, s.c_str(), s.length(), &utf8[0], len, NULL, NULL); 
    } 
    return utf8; 
} 

int main() 
{ 
    wstring str = L"ÑÁ"; 

    // Create a UTF-8 file and write in it using Windows functions 
    HANDLE hfile = CreateFileW(filepath, GENERIC_WRITE, 0, NULL, 
     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
    if (hfile != INVALID_HANDLE_VALUE) 
    { 
     unsigned char smarker[3]; 
     DWORD bytesWritten; 

     smarker[0] = 0xEF; 
     smarker[1] = 0xBB; 
     smarker[2] = 0xBF; 
     WriteFile(hfile, smarker, 3, &bytesWritten, NULL); 

     string strBuf = to_utf8(str); 
     WriteFile(hfile, strBuf.c_str(), strBuf.size(), &bytesWritten, NULL); 

     CloseHandle(hfile); 
    } 

    return 0; 
} 
+0

Спасибо за помощь, наконец эта работа для меня –

+0

Спасибо за это, решила мою проблему! –

1

Проблема находится здесь:

wstringbuf strBuf (str, ios_base::out|ios::app); 
WriteFile(hfile, &strBuf, dwBytesToWrite, &bytesWritten, NULL); 

&strBuf является адрес wstringbuf объект, который содержит такие вещи, как указатель на содержимое, положение буфера и статус флаги ... не там, где находится его содержимое.

Вы, вероятно, хотели

WriteFile(hfile, &str[0], /* etc */ 

но это будет просто хранить ту же кодировку, что ваши wstring использует. Чтобы написать в UTF-8, вы можете использовать WideCharToMultiByte (или wcstombs, так как вы уже использовали mbstowcs).

+0

Привет, я пробовал это 'char * strBuf;' 'wcstombs (strBuf, str.c_str(), wcslen (str.c_str());' 'WriteFile (hfile, & strBuf [0], ...) ' Но внешний файл пуст Что я делаю неправильно –

+0

' wcstombs' не выделяет память, вам нужно дать ему указатель на достаточно большой буфер. –

0

Бен прав, что вы пишете необработанный wchar_t файлу, а не UTF-8.

Чтобы написать UTF-8, вы можете рассмотреть возможность пребывания внутри C++ и делать это:

std::locale loc (std::locale(), new std::codecvt_utf8<wchar_t>); 

std::wofstream fs ("unicode.txt"); 
fs.imbue(loc); 

fs << L"ÑÁ"; 
+0

Он на 'Windows'. Вышеупомянутая версия потребует GCC-5.0 alpha/beta build или MSVC. – Brandon

+0

На самом деле я пробовал то, что вы предлагаете, но не работал http://stackoverflow.com/questions/28552985/includecodecvt-file-not-found?noredirect1_comment45540405_28552985 –