Assume that I have executed a QNetworkRequest and got the appropriated QNetworkReply. If it be a large file (say 1 GB) how can I create a say 4k byte array buffer and read data 4k by 4k into that array and write it at same time into an open file stream?
For example the equivalent C# code would be this (I'm familiar with C# not Qt):
public static void CopyStream(Stream input, Stream output)
{
// input is web stream, output is filestream
byte[] buffer = new byte[4096];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write (buffer, 0, read);
}
}
---- edit
Actually what i am trying to do is a download resume capability on every run of my application. every time i try to resume the download i set the range header of QNetworkRequest and just get the rest of data so need to write data not at once but step by step.
You probably want a solution in c++ as Qt is a library. One possibility is to use QIODevice class, which is inherited by both QFile and QNetworkReply
void copyStream(QIODevice& input, QIODevice& output){
std::vector<char> buffer(4096);
qint64 bytesRead;
while ((bytesRead=input.read(&buffer[0],buffer.size()))>0){
output.write(&buffer[0],bytesRead);
}
}
Related
I have a QByteArray which created like this:
QByteArray data;
QFile file("/path/to/music.mp3");
if (file.open(QIODevice::ReadOnly))
{
data = file.readAll();
}
And i get it somewhere else, how could i play it using QMediaPlayer without save it to file ?
If you have .mp3 file directly, you can call it by directly setting the URL to QMediaPlayer.
You can find below example in documentation.
QMediaPlayer* player = new QMediaPlayer;
connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64)));
player->setMedia(QUrl::fromLocalFile("/path/to/music.mp3"));
player->setVolume(50);
player->play();
https://doc.qt.io/qt-5/qmediaplayer.html#setMedia
If for obvious reasons, you have to go with QByteArray, May be you can try as said below (Not tried and tested):
//BYTE ARRAY
QByteArray data;
if (file.open(QIODevice::ReadOnly))
{
data = file.readAll();
}
//CREATE A BUFFER OBJECT WITH BYTE ARRAY
QBuffer buffer(&data);
buffer.open(QIODevice::ReadOnly);
//CREATE MEDIA PLAYER OBJECT
QMediaPlayer* player = new QMediaPlayer;
//SET MEDIA CONTENT AND BUFFER.
player->setMedia(QUrl::fromLocalFile("/path/to/music.mp3"),&buffer);
player->play();
When in model methods rowCount() and columnCount() I try to retrieve data from server using QTcpSocket, the model calls these methods few times but not calls data() afterwards. The associated QTableView displays nothing. I checked with debugger and it shows that rowCount() and columnCount() are returning valid data.
The model is derived from QAbstractTableModel. Here's the code of TcpTableModel::rowCount():
//Setup waiting for server response
QTimer timer;
timer.setSingleShot(true);
QEventLoop eventLoop;
connect(&m_tcpSocket, &QTcpSocket::readyRead, &eventLoop, &QEventLoop::quit);
connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);
timer.start(TIMEOUT);
//Using QDataStream to send and receive model information
QDataStream dataStream(&m_tcpSocket);
dataStream << MSG_REQUEST_ROWS_COUNT;//Sending request for number of rows
eventLoop.exec();
//If no response received
if(!timer.isActive())
{
connect(&m_tcpSocket, &QTcpSocket::readyRead, this, &TcpTableModel::readyRead);
return 0;
}
timer.stop();
//Receiving information from server
dataStream.startTransaction();
int msgType = -1;
int rowCount = -1;
dataStream >> msgType;
dataStream >> rowCount;
if((msgType != MSG_REQUEST_ROWS_COUNT) || (rowCount == -1))
{
dataStream.commitTransaction();
return 0;
}
dataStream.commitTransaction();
return rowCount;
The server uses same approach to process the request. It receives MSG_REQUEST_ROWS_COUNT and then sends back MSG_REQUEST_ROWS_COUNT and an int containing the number of rows.
What could be the source of such behavior in my program? Maybe QTableView can't work properly if its requests to model are satisfied with delay. Or maybe I should use completely different approach to get model data from server?
I'm creating a socket-based program to send a screenshot from one user to another user. I need to convert a screenshot to a byte array before sending. After I convert my screenshot to a QByteArray I insert 4 bytes to the beginning of the array to mark that it is a picture (it is the number 20 to tell me it is a picture and not text or something else).
After I send the byte array via a socket to other user, when it is received I read the first 4 bytes to know what it is. Since it was a picture I then convert it from a QByteArray to QPixmap to show it on a label. I use secondPixmap.loadFromData(byteArray,"JPEG") to load it but it not load any picture.
This is a sample of my code:
void MainWindow::shootScreen()
{
originalPixmap = QPixmap(); // clear image for low memory situations
// on embedded devices.
originalPixmap = QGuiApplication::primaryScreen()->grabWindow(0);
scaledPixmap = originalPixmap.scaled(500, 500);
QByteArray bArray;
QBuffer buffer(&bArray);
buffer.open(QIODevice::WriteOnly);
originalPixmap.save(&buffer,"JPEG",5);
qDebug() << bArray.size() << "diz0";
byteArray= QByteArray();
QDataStream ds(&byteArray,QIODevice::ReadWrite);
int32_t c = 20;
ds << c;
ds<<bArray;
}
void MainWindow::updateScreenshotLabel()
{
this->ui->label->setPixmap(secondPixmap.scaled(this->ui->label->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
void MainWindow::on_pushButton_clicked()
{
shootScreen();
}
void MainWindow::on_pushButton_2_clicked()
{
secondPixmap = QPixmap();
QDataStream ds(&byteArray,QIODevice::ReadOnly);
qint32 code;
ds>>code;
secondPixmap.loadFromData(byteArray,"JPEG");
updateScreenshotLabel();
}
Your MainWindow::on_pushButton_2_clicked implementation looks odd. You have...
QDataStream ds(&byteArray,QIODevice::ReadOnly);
which creates a read-only QDataStream that will read it's input data from byteArray. But later you have...
secondPixmap.loadFromData(byteArray,"JPEG");
which attempts to read the QPixmap directly from the same QByteArray -- bypassing the QDataStream completely.
You can also make use of the QPixmap static members that read from/write to a QDataStream. So I think you're looking for something like...
QDataStream ds(&byteArray,QIODevice::ReadOnly);
qint32 code;
ds >> code;
if (code == 20)
ds >> secondPixmap;
And likewise for your MainWindow::shootScreen implementation. You could reduce your code a fair bit by making use of QDataStream & operator<<(QDataStream &stream, const QPixmap &pixmap).
i try write media stream to buffer and then to file
buf.open(QBuffer::ReadWrite);
file.setFileName("out.mp3");
file.open(QIODevice::WriteOnly|QFile::Truncate);
mp3file.setDevice(&file);
attempts:
1.
void MainWindow::reply_readyRead()
{
QByteArray qa;
qa = reply->read(16 * 1024);
buf.write(qa.data(),qa.size());
}
2.
void MainWindow::reply_readyRead()
{
QByteArray qa;
qa = reply->read(16 * 1024);
buf.write(qa.data(),qa.size());
mp3file.writeRawData(qa.data() ,qa.size());
}
always out-file/buffer is broken(missed parts). you can listen this file here MP3 FILE
writing mp3 from static files(from url) goes well!
You don't read all the data that is available. Either read all the data at once:
QByteArray qa = reply->readAll();
or try doing it in a loop:
QByteArray qa;
while (reply->bytesAvailable() > 0)
qa += reply->read(16 * 1024);
I am trying to rewrite in c++ an application written in python.
All it does is to open a serial port and read some xml. In python i was using pyserial to read the xml and beautifulsoup to retrieve information. The output was like this.
<file><property>xx32</property></file>
Now i am using qextserialport to read from the serial port and the xml i get is something like this.
<
fil
e>
<prope
rty>xx32
</prop
erty>
</
file>
My problem is that i cant parse an xml like this. I get errors.
EDIT:
Qextserialport reads data from the serial port in set of bytes that are not fixed.
So how do i concatenate my xml into one string? I get an xml string every 4-5 seconds from the serial port.
here is my code
this->port = new QextSerialPort(com_port,QextSerialPort::EventDriven);
port->setBaudRate(BAUD57600);
port->setFlowControl(FLOW_OFF);
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setStopBits(STOP_1);
port->setTimeout(0);
if (port->open(QIODevice::ReadOnly) == true)
{
//qDebug()<< "hello";
connect(port,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
}
and the function that actually reads from the serial port
void CurrentCost::onReadyRead()
{
QByteArray bytes;
bytes = port->readAll();
//qDebug() << "bytes read:" << bytes.size();
//qDebug() << "bytes:" << bytes;
ui->textBrowser->append(bytes);
}
I mean something like this:
class CurrentCost...{
private:
QByteArray xmlData;
private slots:
void onReadyRead();
};
void CurrentCost::onReadyRead()
{
xmlData.append(port->readAll());
if(xmlData.endsWith(/*what your port sending then xml is over&*/))
{
ui->textBrowser->append(xmlData);
xmlData.clear();
}
}