2012-04-05 15 views
6

Programuję (tylko okazjonalnie) w C++ z VisualStudio i MFC. Piszę plik z fopen i fprintf. Plik powinien być zakodowany w UTF8. Czy jest taka możliwość? Cokolwiek próbuję, plik jest albo kodowany w standardzie dwubajtowym, albo w kodowaniu ISO-8859-2 (latin2).Jak napisać plik UTF-8 z fprintf w C++

Glanebridge

+1

Zobacz inne posty o Unicode w C++ http://stackoverflow.com/questions/55641/unicode-in-c – Dave

+0

Można spróbować, aby zobaczyć ten wątek [enter opis Link tutaj] [1] [1]: http://stackoverflow.com/questions/2543346/how-to-write-unicode-hello-world-in-c-on-windows – Jepessen

Odpowiedz

1

Teoretycznie należy po prostu ustawić ustawienia regionalne, które używa UTF-8 jako zewnętrznego kodowania. Moje zrozumienie - nie jestem programistą Windows - jest to Windows has no such locale, więc musisz uciekać się do wdrożenia konkretnych środków lub nie standard libraries (link z komentarza Dave'a).

2

Tak, ale potrzebujesz programu Visual Studio 2005 lub nowszego. Można wtedy zadzwonić fopen z parametrami:

LPCTSTR strText = "абв"; 
FILE *f = fopen(pszFilePath, "w,ccs=UTF-8"); 
_ftprintf(f, _T("%s"), (LPCTSTR) strText); 

Pamiętaj, to jest rozszerzenie Microsoft, to prawdopodobnie nie będzie działać z gcc lub innych kompilatorów.

+0

I don Myślę, że wpłynie to na dane zapisane w pliku przy użyciu fprintf. – bames53

+0

Musisz użyć _ftprintf. Zobacz zmiany w mojej odpowiedzi. – sashoalm

+0

Lub po prostu użyj fwprintf. Chodzi o to, że 'ccs = UTF-8' ustawia tryb _O_U8TEXT na pliku, więc zapisanie szerokich znaków do pliku spowoduje wyprowadzenie UTF-8. Wpisanie wąskich znaków za pomocą tego zestawu trybów spowoduje błąd. – bames53

2

Nie powinieneś potrzebować ustawiania ustawień regionalnych lub ustawiania żadnych specjalnych trybów w pliku, jeśli chcesz tylko użyć fprintf. Po prostu musisz używać kodowanych łańcuchów UTF-8.

#include <cstdio> 
#include <codecvt> 

int main() { 
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> convert; 
    std::string utf8_string = convert.to_bytes(L"кошка 日本国"); 

    if(FILE *f = fopen("tmp","w")) 
     fprintf(f,"%s\n",utf8_string.c_str()); 
} 

Zapisz program jako UTF-8 z podpisem lub UTF-16 (czyli nie używać UTF-8 bez podpisu, w przeciwnym razie nie będzie produkować VS prawy ciąg dosłowny). Plik napisany przez program będzie zawierał wersję UTF-8 tego łańcucha. Albo można zrobić:

int main() { 
    if(FILE *f = fopen("tmp","w")) 
     fprintf(f,"%s\n","кошка 日本国"); 
} 

W tym przypadku należy zapisać plik jako UTF-8 bez podpisu, ponieważ chcesz kompilator myśleć kodowanie źródło jest takie samo jak kodowanie wykonanie ... To to trochę hack, który polega na kompilacji, IMO, złamanym zachowaniu.

Możesz zrobić zasadniczo to samo z każdym innym interfejsem API do pisania wąskich znaków do pliku, ale pamiętaj, że żadna z tych metod nie działa przy zapisywaniu UTF-8 na konsoli Windows. Ponieważ środowisko uruchomieniowe C i/lub konsola są nieco uszkodzone, możesz napisać kodowanie UTF-8 bezpośrednio do konsoli, wykonując SetConsoleOutputCP (65001), a następnie używając jednej z różnorodnych funkcji puts.

Jeśli chcesz używać szerokich znaków zamiast wąskich znaków, wówczas można zastosować metody oparte na locale i tryby ustawień deskryptorów plików.

#include <cstdio> 
#include <fcntl.h> 
#include <io.h> 

int main() { 
    if(FILE *f = fopen("tmp","w")) { 
     _setmode(_fileno(f), _O_U8TEXT); 
     fwprintf(f,L"%s\n",L"кошка 日本国"); 
    } 
} 

#include <fstream> 
#include <codecvt> 

int main() { 
    if(auto f = std::wofstream("tmp")) { 
     f.imbue(std::locale(std::locale(), 
       new std::codecvt_utf8_utf16<wchar_t>)); // assumes wchar_t is UTF-16 
     f << L"кошка 日本国\n"; 
    } 
} 
+0

Działa to tylko z obsługą C++ 11 w VC10 +. –

+1

@NicolBolas Pierwszy przykład wykorzystuje wstring_convert z C++ 11, ale działa też jakakolwiek inna metoda uzyskiwania kodowania UTF-8, np. WideCharToMultiByte. Ostatni przykład wykorzystuje aspekt kodeku C++ 11, dla którego nie ma wbudowanego zamiennika pre-C++ 11. Pozostałe dwa przykłady nie używają C++ 11. – bames53