0

我想读取和写入使用 CR LF 行分隔符 (L"\r\n") 的 utf-16 文件。使用 C++ (Microsoft Visual Studio 2010) iostreams。我希望将写入流的每个 L"\n" 透明地转换为 L"\r\n" 。使用 codecvt_utf16 语言环境方面需要以 ios::binary 模式打开 fstream,从而失去通常的文本模式 \n 到 \r\n 的翻译。

std::wofstream wofs;
wofs.open("try_utf16.txt", std::ios::binary);
wofs.imbue(
    std::locale(
        wofs.getloc(),
        new std::codecvt_utf16<wchar_t, 0x10ffff, std::generate_header>));
wofs << L"Hi!\n"; // i want a '\r' to be inserted before the '\n' in the output file
wofs.close();++

我想要一个不需要像 BOOST 这样的额外库的解决方案。

4

1 回答 1

1

我想我自己找到了解决方案,我想分享它。欢迎您的意见!

#include <iostream>
#include <fstream>

class wcrlf_filebuf : public std::basic_filebuf<wchar_t>
{
    typedef std::basic_filebuf<wchar_t> BASE;
    wchar_t awch[128];
    bool bBomWritten;
public:
    wcrlf_filebuf() 
        : bBomWritten(false)
    { memset(awch, 0, sizeof awch); }

    wcrlf_filebuf(const wchar_t *wszFilespec, 
                  std::ios_base::open_mode _Mode = std::ios_base::out) 
        : bBomWritten(false)
    {
        memset(awch, 0, sizeof awch);
        BASE::open(wszFilespec, _Mode | std::ios_base::binary);
        pubsetbuf(awch, _countof(awch));
    }

    wcrlf_filebuf *open(const wchar_t *wszFilespec, 
                        std::ios_base::open_mode _Mode = std::ios_base::out)
    {   
        BASE::open(wszFilespec, _Mode | std::ios_base::binary);
        pubsetbuf(awch, _countof(awch));
        return this;
    }

    virtual int_type overflow(int_type ch = traits_type::eof())
    {
        if (!bBomWritten) {
            bBomWritten = true;
            int_type iRet = BASE::overflow(0xfeff);
            if (iRet != traits_type::not_eof(0xfeff)) return iRet;
        }
        if (ch == '\n') {
            int_type iRet = BASE::overflow('\r');
            if (iRet != traits_type::not_eof('\r')) return iRet;
        }
        return BASE::overflow(ch);
    }
};

class wcrlfofstream : public std::wostream
{
    typedef std::wostream BASE;
public:
    wcrlfofstream(const wchar_t *wszFilespec, 
                  std::ios_base::open_mode _Mode = std::ios_base::out) 
        : std::wostream(new wcrlf_filebuf(wszFilespec, _Mode))
    {}

    wcrlf_filebuf* rdbuf()
    {
        return dynamic_cast<wcrlf_filebuf*>(std::wostream::rdbuf());
    }

    void close()
    {
        rdbuf()->close();
    }
};
于 2013-11-26T22:55:20.447 回答