PDA

View Full Version : Copy with QDataStream



wirasto
8th July 2009, 19:48
I just try copy image with QDataStream. But failed :(



QFile file("../olongia.png");
file.open(QIODevice::ReadOnly);

QDataStream ods(&file);
ods.setVersion(QDataStream::Qt_4_2);



QFile ftulis("../coba.png");
ftulis.open(QIODevice::WriteOnly);

QDataStream wds(&ftulis);
wds.setVersion(QDataStream::Qt_4_2);

wds << ods;

ftulis.close();

file.close();



Have any suggestion ?


Sorry, my english is bad :)

nish
9th July 2009, 02:08
datastream wont work because it puts some header information in the file.. which will corrupt the png file.
just use simple fopen, fread, and fwrite or C library or use fstream of c++. If you just want to copy a file.. take a look at QFile::copy()

wirasto
9th July 2009, 03:30
I want learn how to send file with socket. So before that, i must learn how to copy file with use QDataStream. Or, you can give me simple code about send file with socket ? I have read some sample code how to send file via socket, but complex and so hard for me :(


<i>Sorry, my english is bad :)</i>

nish
9th July 2009, 03:38
why data stream is needed for socket?
just read the file

QFile f;
//open file, check error etc...
QByteArray b=f.readAll();
QTcpSocket t;
//open...
t.write(b);

wirasto
9th July 2009, 10:07
I just try. But failed. This in my code. Can you help me for fix it ?

Thank's before


Btw, I created project with Qt-creator


Server Code


main.cpp




#include <QtCore/QCoreApplication>
#include "server.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

Server server;
if( !server.listen( QHostAddress::Any, 9876 ) )
{
qCritical( "Cannot listen to port 9876." );
return 1;
}

return a.exec();
}






server.h




#ifndef SERVER_H
#define SERVER_H

#include <QtNetwork>

class Server : public QTcpServer
{

public:
Server();

protected:
void incomingConnection( int descriptor );

};

#endif







server.cpp






#include "server.h"
#include "thread.h"

Server::Server() : QTcpServer()
{
}

void Server::incomingConnection( int descriptor )
{
ServerThread *thread = new ServerThread( descriptor, this );

connect( thread, SIGNAL(finished()), thread, SLOT(deleteLater()) );

thread->start();
}








thread.h




#ifndef THREAD_H
#define THREAD_H

#include <QtNetwork>
#include <QtGui>

class ServerThread : public QThread
{
public:
ServerThread( int descriptor, QObject *parent );
void run();

private:
int m_descriptor;
};

#endif







thread.cpp




#include "thread.h"

ServerThread::ServerThread( int descriptor, QObject *parent ) : QThread( parent )
{
m_descriptor = descriptor;
}

void ServerThread::run()
{
QTcpSocket socket;
if( !socket.setSocketDescriptor( m_descriptor ) )
{
qDebug( "Socket error!" );
return;
}


QFile file("images/linux.png");
QByteArray data=file.readAll();
socket.write( data );
socket.disconnectFromHost();
//socket.waitForDisconnected();
}









Client Code



main.cpp




#include <QtGui/QApplication>
#include "dialog.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}





dialog.h




#ifndef DIALOG_H
#define DIALOG_H

#include <QtGui>
#include <QtNetwork>

namespace Ui
{
class Dialog;
}

class Dialog : public QDialog
{
Q_OBJECT

public:
Dialog(QWidget *parent = 0);
~Dialog();

private:
Ui::Dialog *ui;

QTcpSocket socket;


private slots:
void on_pushButton_clicked();

void tcpReady();
void tcpError( QAbstractSocket::SocketError error );

};

#endif // DIALOG_H







dialog.cpp




#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent)
: QDialog(parent), ui(new Ui::Dialog)
{
ui->setupUi(this);

connect( &socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(tcpError(QAbstractSocket::SocketError)) );
connect( &socket, SIGNAL(readyRead()), this, SLOT(tcpReady()) );

}

Dialog::~Dialog()
{
delete ui;
}

void Dialog::on_pushButton_clicked()
{

socket.abort();
socket.connectToHost( ui->lineEdit->text(), 9876 );

}


void Dialog::tcpReady()
{


QByteArray ar=socket.readAll();
QFile file("linuxmu.png");
file.open(QIODevice::WriteOnly);
QDataStream ds(&file);
ds << ar;

file.close();
}

void Dialog::tcpError( QAbstractSocket::SocketError error )
{
if( error == QAbstractSocket::RemoteHostClosedError )
return;
QMessageBox::warning( this, tr("Error"),
tr("TCP error: %1").arg( socket.errorString() ) );
ui->label->setText( tr("<i>No Image</i>") );
ui->pushButton->setEnabled( true );
}

nish
9th July 2009, 10:18
what is the error?
a quick look shows that at the server side you did not open the file before readAll().

faldzip
9th July 2009, 11:24
1. open the file before reading it on server side
2. dont use QDataStream on client side - use just file.write(data);
3. When you send data through the network there is possibility that not all your data would be send in one network packet so the clients readAll() can give you less data than you sent from server! in your case it can result in corrupted image file. The best way is to make some header to your sent data like this:


QByteArray data = file.readAll();
int size = data.size();
// now send size and then data

client:


int size = readSize(socket.read(sizeof(int));
// now check withc bytesAvailable()if you got all data
// and read them, if not all you have to wait for next part and append
// it to the already downloaded part
data = socket.readAll();
// or
data.append(socket.readAll());

if your image is quite small then there is high possibility that it would be sent in one part,
so the method I described would be necessary, but who knows :]

wirasto
9th July 2009, 12:04
Server



QFile file("images/linux.png");
file.open(QIODevice::ReadOnly)
QByteArray data=file.readAll();
int size=data.size();
socket.write( data );
socket.disconnectFromHost();

How send size and data ?


Client



int size=readSize(socket.read(sizeof(int)));
QByteArray ar=socket.readAll();
QFile file("linuxmu.png");
file.open(QIODevice::WriteOnly);
file.write(ar)
file.close();


How declared readSize ?

faldzip
9th July 2009, 12:50
you can assume that you size can be stored in 32-bit (4 byte) long int - you can use qint32 (or even quint32 - size can't be less then 0).
so you have to convert quint32 into QByteArray, writing there byte by byte of your quint32, something like this:


quint32 size = ...; // your size
QByteArray intBytes;
for (int i = 0; i < 4; ++i) {
quint8 b = (size >> (i*8)) & 0x000000ff;
intBytes.append(b);
}
on the client side you have to create a valid quint32 from a byte array:


QByteArray intBytes = socket.read(4); // 4*8 = 32 bits
quint32 size = 0; // init with 0 to be sure there is really 0
for (int i = 0; i < 4; ++i) {
quint8 b = intBytes.at(i);
size |= (((quint32)b) & 0x000000ff) << i*8;
}
(should work but i did not check so try to print the int first to see if it is what you have sent :])
now you have the size, so whenever readyRead() comes from socket you have to check int the slot if you have to start reading new image (read size and some of data) or you are in the middle of image data. Whenever you read image data just check if bytesAvailable() are equal to the needed size, if less than readAll() and decrease size by a number of bytes you already read. and so on... In other words reading data becomes a little state machine :] so you have to react adequately to the state you are in.

P.S. And it is nice to check if file was opened succesfully, so instead of this:


file.open(QIODevice::ReadOnly);
better do it like this:


if (!file.open(QIODevice::ReadOnly)) {
// do something proper if cannot open file, e.g.:
qDebug("Cannot open file!");
return;
}

wirasto
9th July 2009, 14:19
Not work. But thank's

I think not right to me for learn about QtNetwork now. Maybe next time



QTcpSocket socket;
if( !socket.setSocketDescriptor( m_descriptor ) )
{
qDebug( "Socket error!" );
return;
}


QFile file("images/linux.png");
if (!file.open(QIODevice::ReadOnly))
{
qDebug("Cannot open file!");
return;
}

QByteArray data=file.readAll();
int size=data.size();

for(int i=0; i< 4; ++i)
{
quint8 b=(size >> (i*8)) & 0x000000ff;
data.append(b);
}

socket.write(data);
socket.disconnectFromHost();



Client


void Dialog::tcpReady()
{

QByteArray ar=socket.read(4);
quint32 size=0;
for(int i=0; i < 4; ++i)
{
quint8 b=ar.at(i);
size |= (((quint32)b) & 0x000000ff) << i*8;
}

QFile file("linuxmu.png");
file.open(QIODevice::WriteOnly);
file.write(ar);

file.close();
}



Once more, thank's for your help

faldzip
9th July 2009, 18:51
Not work. But thank's



QTcpSocket socket;
if( !socket.setSocketDescriptor( m_descriptor ) )
{
qDebug( "Socket error!" );
return;
}


QFile file("images/linux.png");
if (!file.open(QIODevice::ReadOnly))
{
qDebug("Cannot open file!");
return;
}

QByteArray data=file.readAll();
int size=data.size();

for(int i=0; i< 4; ++i)
{
quint8 b=(size >> (i*8)) & 0x000000ff;
data.append(b);
}

socket.write(data);
socket.disconnectFromHost();


Men you have appended your size to the end of the data! What is the sense of doing that if you have to know the size at the very beginning of receiving data??? You have to send the size, and then the data:


QTcpSocket socket;
if( !socket.setSocketDescriptor( m_descriptor ) )
{
qDebug( "Socket error!" );
return;
}


QFile file("images/linux.png");
if (!file.open(QIODevice::ReadOnly))
{
qDebug("Cannot open file!");
return;
}

QByteArray data=file.readAll();
int size=data.size();

QByteArray sizeBytes;
for(int i=0; i< 4; ++i)
{
quint8 b=(size >> (i*8)) & 0x000000ff;
sizeBytes.append(b);
}

sizeBytes.append(data);
socket.write(sizeBytes);
socket.disconnectFromHost();

it is not that hard to invent that idea.
And you dont even use that information about size on the client side.
Tell me what happend if you do it like this:


void Dialog::tcpReady()
{
int bytesAvail = socket.bytesAvailable() - 4;
QByteArray ar=socket.read(4);
quint32 size=0;
for(int i=0; i < 4; ++i)
{
quint8 b=ar.at(i);
size |= (((quint32)b) & 0x000000ff) << i*8;
}

if (size > bytesAvail)
qDebug("Different sizes!!!");
else
qDebug("All data have been delivered!");

ar = socket.readAll();
QFile file("linuxmu.png");
file.open(QIODevice::WriteOnly);
file.write(ar);

file.close();
}




I think not right to me for learn about QtNetwork now.
As I see you have to read about network at all...

wirasto
9th July 2009, 20:17
Thank's because you keep teach me....
And... your sample code work now :)

Btw, I must put this line in server side



socket.waitForDisconnected();



Sorry, my english is so bad :(