是否可以使用像std :: iostream这样的QFile?我很确定那里必须有一个包装纸。问题是在哪里?
我有另一个libs,它需要一个std :: istream作为输入参数,但在我的程序中我此时只有一个QFile。
答案 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的版本,就会发生这种情况。