У меня есть пользовательский поток CFileManagerOStream
что наследует от std::ostream
, он принимает строки Unicode UTF16 или UTF32 из класса сетевого потока CTcpStream
и сохраняет их на диске в виде строк UTF8. Строки потенциально слишком велики (могут быть несколько терабайт) для преобразования в память UTF8 в памяти, поэтому я думаю, что мне нужно реализовать потоковый манипулятор C ++ для этой работы. Все примеры манипуляторов, которые я нашел, берут всю строку и обрабатывают ее, что не будет в моем случае из-за низких требований к памяти. У меня есть весь готовый код преобразования Unicode, проблема, которую я пытаюсь решить, заключается в выполнении преобразования с минимальным объемом внутренней памяти.
Я надеялся использовать манипуляторы вот так;
CFileManagerOStream outFile("MultipleUtf8Strings.dat"); // Custom std::ostream
...
#ifdef _WINDOWS
CTcpStreamUtf16 largeBlobUtf16Stream;
...
outFile << ToUTF8FromUtf16 << largeBlobUtf16Stream;
#else
CTcpStreamUtf32 largeBlobUtf32Stream;
...
outFile << ToUTF8FromUtf32 << largeBlobUtf32Stream;
#endif
Это возможно, или я подхожу к этому неправильно?
Я узнал, что с помощью std::ios_base::iword
Хранение запрошенной кодировки символов было лучшим решением для рассматриваемой проблемы:
#include <iostream>
/*!
\brief Unicode encoding
*/
enum EUnicodeEnc
{
/** UTF-8 character encoding */
EUnicodeEnc_UTF8 = 1,
/** UTF-16 character encoding */
EUnicodeEnc_UTF16 = 2,
/** UTF-32 character encoding */
EUnicodeEnc_UTF32 = 3
};
/** Allocate the \c std::ios_base::iword storage for use with \c SourceStreamEncoding object instances */
int SourceStreamEncoding::sourceEnc_xalloc = std::ios_base::xalloc();
/*!
\brief Stream I/O manipulator changes the source character encoding to UTF-8
*/
std::ios_base& FromUtf8(std::ios_base& os) {
os.iword(SourceStreamEncoding::sourceEnc_xalloc) = EUnicodeEnc_UTF8;
return os;
}
/*!
\brief Stream I/O manipulator changes the source character encoding to UTF-16
*/
std::ios_base& FromUtf16(std::ios_base& os) {
os.iword(SourceStreamEncoding::sourceEnc_xalloc) = EUnicodeEnc_UTF16;
return os;
}
/*!
\brief Stream I/O manipulator changes the source character encoding to UTF-32
*/
std::ios_base& FromUtf32(std::ios_base& os) {
os.iword(SourceStreamEncoding::sourceEnc_xalloc) = EUnicodeEnc_UTF32;
return os;
}
/*!
\brief Overrides \c std::ostream::flush()
\details Converts the buffer to the correct character encoding then flushes buffer
after writing its content to a storage device
*/
std::ostream &CFileManagerOStream::flush()
{
switch (os.iword(SourceStreamEncoding::sourceEnc_xalloc))
{
case EUnicodeEnc_UTF8:
characterEncoder.FromUTF8(...);
break;
case EUnicodeEnc_UTF16:
characterEncoder.FromUTF16(...);
break;
case EUnicodeEnc_UTF32:
characterEncoder.FromUTF32(...);
break;
}
return (*this);
}
// Now I can do as follows:
int main()
{
CFileManagerOStream outFile("MultipleUtf8Strings.dat"); // Custom std::ostream
...
#ifdef _WINDOWS
CTcpStreamUtf16 largeBlobUtf16Stream;
...
outFile << FromUtf16 << largeBlobUtf16Stream;
#else
CTcpStreamUtf32 largeBlobUtf32Stream;
...
outFile << FromUtf32 << largeBlobUtf32Stream;
#endif
}
Кроме того, я добавил следующий манипулятор, который принимает один параметр:
class FromEnc
{
public:
explicit FromEnc(int i) : i_(i) {}
int i_;
private:
template <class charT, class Traits>
friend std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& os, const FromEnc& w) {
os.iword(SourceStreamEncoding::sourceEnc_xalloc) = w.i_;
return os;
}
};
, так что теперь я могу сделать следующее:
outFile << FromEnc(EUnicodeEnc_UTF16) << largeBlobUtf16Stream;