如何在std :: iostream中使用QFile?

时间:2011-03-05 14:19:07

标签: qt stl iostream

是否可以使用像std :: iostream这样的QFile?我很确定那里必须有一个包装纸。问题是在哪里?

我有另一个libs,它需要一个std :: istream作为输入参数,但在我的程序中我此时只有一个QFile。

5 个答案:

答案 0 :(得分:7)

我使用以下代码提出了自己的解决方案:

#include <ios>
#include <QIODevice>

class QStdStreamBuf : public std::streambuf
{
public:
    QStdStreamBuf(QIODevice *dev) : std::streambuf(), m_dev(dev)
    {
        // Initialize get pointer.  This should be zero so that underflow is called upon first read.
        this->setg(0, 0, 0);
    }

protected:
virtual std::streamsize xsgetn(std::streambuf::char_type *str, std::streamsize n)
{
    return m_dev->read(str, n);
}

virtual std::streamsize xsputn(const std::streambuf::char_type *str, std::streamsize n)
{
    return m_dev->write(str, n);
}

virtual std::streambuf::pos_type seekoff(std::streambuf::off_type off, std::ios_base::seekdir dir, std::ios_base::openmode /*__mode*/)
{
    switch(dir)
    {
        case std::ios_base::beg:
            break;
        case std::ios_base::end:
            off = m_dev->size() - off;
            break;
        case std::ios_base::cur:
            off = m_dev->pos() + off;
            break;
    }
    if(m_dev->seek(off))
        return m_dev->pos();
    else
        return std::streambuf::pos_type(std::streambuf::off_type(-1));
}
virtual std::streambuf::pos_type seekpos(std::streambuf::pos_type off, std::ios_base::openmode /*__mode*/)
{
    if(m_dev->seek(off))
        return m_dev->pos();
    else
        return std::streambuf::pos_type(std::streambuf::off_type(-1));
}

virtual std::streambuf::int_type underflow()
{ 
    // Read enough bytes to fill the buffer.
    std::streamsize len = sgetn(m_inbuf, sizeof(m_inbuf)/sizeof(m_inbuf[0]));

    // Since the input buffer content is now valid (or is new)
    // the get pointer should be initialized (or reset).
    setg(m_inbuf, m_inbuf, m_inbuf + len);

    // If nothing was read, then the end is here.
    if(len == 0)
        return traits_type::eof();

    // Return the first character.
    return traits_type::not_eof(m_inbuf[0]);
}


private:
    static const std::streamsize BUFFER_SIZE = 1024;
    std::streambuf::char_type m_inbuf[BUFFER_SIZE];
    QIODevice *m_dev;
};

class QStdIStream : public std::istream
{
public:
    QStdIStream(QIODevice *dev) : std::istream(m_buf = new QStdStreamBuf(dev)) {}
    virtual ~QStdIStream()
    {
        rdbuf(0);
        delete m_buf;
    }

private:
    QStdStreamBuf * m_buf;
};

我可以正常阅读本地文件。我还没有测试它来写文件。这段代码肯定不完美,但它确实有用。

答案 1 :(得分:5)

我提出了自己的解决方案(使用了与Stephen Chu建议相同的想法)

#include <iostream>
#include <fstream>
#include <cstdio>

#include <QtCore>

using namespace std;

void externalLibFunction(istream & input_stream) {
    copy(istream_iterator<string>(input_stream),
         istream_iterator<string>(),
         ostream_iterator<string>(cout, " "));
}

ifstream QFileToifstream(QFile & file) {
    Q_ASSERT(file.isReadable());        
    return ifstream(::_fdopen(file.handle(), "r"));
}

int main(int argc, char ** argv)
{
    QFile file("a file");
    file.open(QIODevice::WriteOnly);
    file.write(QString("some string").toLatin1());
    file.close();
    file.open(QIODevice::ReadOnly);
    std::ifstream ifs(QFileToifstream(file));
    externalLibFunction(ifs);
}

输出:

some string

此代码使用Working Draft, Standard for Programming Language C++ 27.9.1.7 basic_ifstream构造函数部分中指定的std :: ifstream移动构造函数(C ++ x0特性):

  

basic_ifstream(basic_ifstream&& rhs);
  效果:移动构造   rvalue rhs。这是通过   移动构建基类,和   包含的basic_filebuf。下一个   调用basic_istream :: set_rdbuf(&amp; sb)来安装包含的   basic_filebuf。

有关此主题的讨论,请参阅How to return an fstream (C++0x)

答案 2 :(得分:4)

如果您获得的QFile对象尚未打开以供读取,您可以从中获取文件名并打开ifstream对象。

如果它已经打开,你可以使用handle()获取文件句柄/描述符并从那里开始。从平台句柄获取fstream没有可移植的方法。您必须为您的平台找到解决方法。

答案 3 :(得分:1)

这是将std :: streambuf子类化以提供不可搜索的只读std :: istream:https://stackoverflow.com/a/14086442/316578

的很好指南

这是基于该方法的简单类,该类将QFile适配到std :: streambuf中,然后可以将其包装在std :: istream中。

#include <iostream>
#include <QFile>

constexpr qint64 ERROR = -1;
constexpr qint64 BUFFER_SIZE = 1024;

class QFileInputStreamBuffer final : public std::streambuf {
private:
    QFile &m_file;
    QByteArray m_buffer;
public:
    explicit QFileInputStreamBuffer(QFile &file)
        : m_file(file),
          m_buffer(BUFFER_SIZE, Qt::Uninitialized) {
    }

    virtual int underflow() override {
        if (atEndOfBuffer()) {
            // try to get more data
            const qint64 bytesReadIntoBuffer = m_file.read(m_buffer.data(), BUFFER_SIZE);
            if (bytesReadIntoBuffer != ERROR) {
                setg(m_buffer.data(), m_buffer.data(), m_buffer.data() + bytesReadIntoBuffer);
            }
        }
        if (atEndOfBuffer()) {
            // no more data available
            return std::char_traits<char>::eof();
        }
        else {
            return std::char_traits<char>::to_int_type(*gptr());
        }
    }

private:
    bool atEndOfBuffer() const {
        return gptr() == egptr();
    }
};

如果您希望能够进行诸如查找,写入等更多操作,那么您将需要此处其他更复杂的解决方案之一,以覆盖更多的streambuf函数。

答案 4 :(得分:0)

如果您对性能不太关心,您可以随时从文件中读取所有内容并将其转储到std::stringstream中,然后将其传递给您的库。 (或者,将所有内容缓冲到字符串流,然后写入QFile)

除此之外,两者看起来并不相互影响。无论如何,如果Qt编译的STL版本与您正在使用的STL版本有任何不同,那么Qt到STL的操作通常会导致模糊的错误和微妙的不一致。例如,如果您更改Visual Studio的版本,就会发生这种情况。