异常可能会增加某些 C++ 实现的内存和运行时开销。这对于现代的、维护良好的 C++ 实现来说不是问题 - 但 Qt 必须在一些非常过时或尴尬的平台上运行和编译。不仅如此 - Qt(至少是核心)必须在禁用编译器异常支持的情况下正确编译和运行。
您的错误代码检查几乎是正确的。在你的情况下,如果write
返回除以下以外的任何大小readed
,应将其视为错误。语法挑剔:正确的形式是“read”,而不是“readed”。是的,你已经“写”了,但只是“读”了。英语就是这么奇怪;)
没有必要使用flush()
. Just waitForBytesWritten
然后检查还有多少字节需要写入,并据此报告进度。由于您的方法无法分摊磁盘文件访问的延迟,因此您的运行速度会变慢:您不会并行进行网络发送和文件读取。
所以,你所做的事情有点复杂。您不需要使用阻止waitForX
完全没有功能。您正在线程中运行,因此我们只使用由QIODevice
并使用默认的事件循环QThread
's run()
方法是旋转。这样您就可以在同一个工作线程中处理多个文件。您的实现需要一个专用线程来并行处理每个文件。
下面的代码应该可以工作。只需使用moveToThread
将其转移给工人QThread
- 不源自QThread
。要开始发送,请调用start()
投币口。要取消发送,您只需致电sender->deleteLater()
.
#include <QTcpSocket>
#include <QByteArray>
class Sender : public QObject {
Q_OBJECT
QIODevice * m_src;
QAbstractSocket * m_dst;
QByteArray m_buf;
qint64 m_hasRead;
qint64 m_hasWritten;
qint64 m_srcSize;
bool m_doneSignaled;
bool signalDone() {
if (!m_doneSignaled &&
((m_srcSize && m_hasWritten == m_srcSize) || m_src->atEnd())) {
emit done();
m_doneSignaled = true;
}
return m_doneSignaled;
}
Q_SLOT void dstBytesWritten(qint64 len) {
if (m_dst->bytesToWrite() < m_buf.size() / 2) {
// the transmit buffer is running low, refill
send();
}
m_hasWritten += len;
emit progressed((m_hasWritten * 100) / m_srcSize);
signalDone();
}
Q_SLOT void dstError() {
emit errorOccurred(tr("Unable to send data. Probably the other side"
"cancelled or there are connection problems."));
qDebug() << m_dst->error();
}
void send() {
if (signalDone()) return;
qint64 read = m_src->read(m_buf.data(), m_buf.size());
if (read == -1) {
emit errorOccurred(tr("Error while reading file."));
return;
}
m_hasRead += read;
qint64 written = m_dst->write(m_buf.constData(), read);
if (written == -1) {
emit errorOccurred(tr("Unable to send data. Probably the other side "
"cancelled or there are connection problems."));
qDebug() << m_dst->error();
return;
}
if (written != read) {
emit errorOccurred(tr("Internal error while filling write buffer."));
qDebug() << m_dst->error();
return;
}
}
public:
/*! Requires a source device open for reading, and a destination socket open
for writing. */
Sender(QIODevice * src, QAbstractSocket * dst, QObject * parent = 0) :
QObject(parent), m_src(src), m_dst(dst), m_buf(8192, Qt::Uninitialized),
m_hasRead(0), m_hasWritten(0), m_doneSignaled(false)
{
Q_ASSERT(m_src->isReadable());
Q_ASSERT(m_dst->isWritable());
connect(m_dst, SIGNAL(bytesWritten(qint64)), SLOT(dstBytesWritten(qint64)));
connect(m_dst, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(dstError()));
m_srcSize = m_src->size();
}
Q_SLOT void start() { send(); }
Q_SIGNAL void done();
Q_SIGNAL void errorOccurred(const QString &);
Q_SIGNAL void progressed(int percent);
};