在 ostream 上使用 std::endl 使我的文件成为二进制文件

Using std::endl on an ostream makes my file binary

我正在开发一个使用 libzip 的项目。我在 c++14 工作,我围绕 libzip 编写了一个小包装器,让我的生活更轻松。

我有一个 std::ostream 对象围绕继承 std::streambuf 的自定义 class 构建。此 streambuf 使用 libzip 函数写入存档中的文件。

在我使用 std::endl 之前,一切都很好。当我这样做时,我的所有文本 readers(仅写入字符串)都将输出文件读取为二进制文件。

我的文本 reader 检测到它是二进制文件,因为在我使用 std::endl 的地方有一个 NUL 字节,任何包含 NUL 字节的文件都被视为二进制文件。

所以我的问题是:这正常吗?我有办法使用 std::endl 吗?

我的代码(提取出来所以可能不完全一样)。

source.hpp

// my attributes
std::unique_ptr<zip_source_t, std::function<void(zip_source_t*)>> _source;
std::unique_ptr<std::ostream> _stream;
std::unique_ptr<_ZipBuffer> _buffer;

class _ZipBuffer : public std::streambuf {
    private:
        zip_source_t* _source;

        std::streamsize xsputn(char const* s, std::streamsize n) override;
        int overflow(int c) override;

    public:
        _ZipBuffer(zip_source_t* file);
};

source.cpp

// create the streambuf and send it to the ostream
_buffer.reset(new _ZipBuffer(_source.get()));
_stream.reset(new std::ostream(_buffer.get()));

// the implementation of _ZipBuffer
Zip::Source::_ZipBuffer::_ZipBuffer(zip_source_t* source) {
    _source = source;
}

std::streamsize Zip::Source::_ZipBuffer::xsputn(char const* s, std::streamsize n) {
    return zip_source_write(_source, s, n * sizeof(char));
}

int Zip::Source::_ZipBuffer::overflow(int c) {
    return zip_source_write(_source, &c, sizeof(int));
}

main.cpp

Zip::Source src;

src << "Some text and a number : " << 2.5 << std::endl;
src << "another line !";

// zip is an object of class Zip that takes my source and write it in the archive
zip.addFile("test.txt", src);

如果我删除主文件中的std::endl,文本文件将被识别为文本文件。如果我添加它,它会被识别为二​​进制文件。

二进制文件是有效的 utf-8 输出(NUL 字节除外):

496c 2065 7374 2070 6f73 7369 626c 6520
6427 c3a9 6372 6972 6520 6465 7320 6e6f
6d62 7265 7320 c3a0 2076 6972 6775 6c65
203a 2032 2e35 0a00 0000 736f 6d65 7468
696e 6720 656c 7365 

谢谢!

好的,刚发现问题...

在我写的 std::streambuf::overflow 重载中,我在接收一个字符时写了一个整数。所以我的int中的前导0写在了文件中。

我不得不将我的 int 转换为 char,问题就消失了:)

您实施 overflow() 如下:

int Zip::Source::_ZipBuffer::overflow(int c) {
   return zip_source_write(_source, &c, sizeof(int));
}

你的 C++ 库显然实现了 std::endl,通过调用 overflow() 并将 '\n' 作为参数传递。

这完全符合 C++ 规范。您的 overflow() 实现有一个错误。

overflow() 的参数是单个字符,作为 int 传递。您的实现将整个二进制 int 写入输出文件,这正是您所看到的。您的 sizeof(int) 显然是 4,因此您会看到 0x0a 和另外三个写入输出的空字节。