STL and UTF-8 file input/output. How to do it?

c++, stl, utf-8

Solution

Use std::codecvt_facet template to perform the conversion.

You may use standard std::codecvt_byname, or a non-standard codecvt_facet implementation.

#include <locale>
using namespace std;
typedef codecvt_facet<wchar_t, char, mbstate_t> Cvt;
locale utf8locale(locale(), new codecvt_byname<wchar_t, char, mbstate_t> ("en_US.UTF-8"));
wcout.pubimbue(utf8locale);
wcout << L"Hello, wide to multybyte world!" << endl;

Beware that on some platforms codecvt_byname can only emit conversion only for locales that are installed in the system.

Problem

I use `wchar_t` for internal strings and UTF-8 for storage in files. I need to use STL to input/output text to screen and also do it by using full Lithuanian charset. It's all fine because I'm not forced to do the same for files, so the following example does the job just fine: ``` #include <io.h> #include <fcntl.h> #include <iostream> _setmode (_fileno(stdout), _O_U16TEXT); wcout << L"AaĄąfl" << endl; ``` But I became curious and attempted to do the same with files with no success. Of course I could use formatted input/output, but that is... discouraged. ``` FILE* fp; _wfopen_s (&fp, L"utf-8_out_test.txt", L"w"); _setmode (_fileno (fp), _O_U8TEXT); _fwprintf_p (fp, L"AaĄą\nfl"); fclose (fp); _wfopen_s (&fp, L"utf-8_in_test.txt", L"r"); _setmode (_fileno (fp), _O_U8TEXT); wchar_t text[256]; fseek (fp, NULL, SEEK_SET); fwscanf (fp, L"%s", text); wcout << text << endl; fwscanf (fp, L"%s", text); wcout << text << endl; fclose (fp); ``` This snippet works perfectly (although I am not sure how it handles malformed chars). So, is there any way to: - get `FILE*` or integer file handle form a `std::basic_*fstream`? - simulate `_setmode ()` on it? - extend `std::basic_*fstream` so it handles UTF-8 I/O? Yes, I am studying at an university and this is somewhat related to my assignments, but I am trying to figure this out for myself. It won't influence my grade or anything like that.

Original source

Related problems