April 16, 2011

harry harry
Lab Rat
108 posts

Accessing files from a file server with a cross-platform app

Page  
1

This is not directly Qt related, but I’m hoping there might be a clever solution:

In my cross-platform app I need to open a well known (meaning the user doesn’t select it) file located on a file server (using QFile).
The file server is running under Windows 2003 server.
Under windows, I can use UNC notation (\\FILESRV\myShare\myFile).
Under Linux and Mac, I need to mount the share from what I understand (using smb) , but that would mean the path will be different on each platform.

Has anyone had to deal with something like this?

 Signature 

If you can’t say what you mean, you’ll never be able to mean what you say.

19 replies

April 16, 2011

Denis Kormalev Denis Kormalev
Lab Rat
1654 posts

You can use next command:

  1. smbclient \\\\FILESERV\\myShare --command="get myFile"

It will download your remote file to current directory.

April 16, 2011

harry harry
Lab Rat
108 posts

I don’t want to use a command line.
I want to use in my code for example

  1. QFile file;
  2. file.setFileName( fileName );
  3. if ( !file.open( QIODevice::ReadOnly ) ) { ...}

but I need the fileName to be the same for all platforms.

 Signature 

If you can’t say what you mean, you’ll never be able to mean what you say.

April 16, 2011

Denis Kormalev Denis Kormalev
Lab Rat
1654 posts

You can use QProcess to download it from share. I’m not sure you will be able to open remote samba file from linux without mounting samba share.

April 16, 2011

harry harry
Lab Rat
108 posts

if the file server was something different, would there be a cross-platform solution?

 Signature 

If you can’t say what you mean, you’ll never be able to mean what you say.

April 16, 2011

Denis Kormalev Denis Kormalev
Lab Rat
1654 posts

I’m not sure that there will be truly cross platform solution. But simple #ifdef sections will help you.

April 16, 2011

harry harry
Lab Rat
108 posts

The problem is I’d like to have a list of files in a table on a database server (eg. Descr and FilePath).

I would show this table in QTableView, and the user can select one and the app would open it.

 Signature 

If you can’t say what you mean, you’ll never be able to mean what you say.

April 16, 2011

Denis Kormalev Denis Kormalev
Lab Rat
1654 posts

You can store filePath in one string and for *nix remove filename from it and run QProcess with smbclient
Something like this (not tested, maybe not even compiling)

  1. QString path = "\\\\FILESRV\\myShare\\myFile";
  2. int lastDelimiterIndex = path.lastIndexOf("\\");
  3. QString shareName = path.left(lastDelimiterIndex).replace("\\", "\\\\");
  4. QString fileName = path.mid(lastDelimiterIndex+1);

So you will have in shareName name of share (first arg for smbclient) and in fileName you will have file name (part of second arg for smbclient)

April 16, 2011

harry harry
Lab Rat
108 posts

ok… that could work.
what about stuff like nfs? does that work at all?

 Signature 

If you can’t say what you mean, you’ll never be able to mean what you say.

April 16, 2011

Denis Kormalev Denis Kormalev
Lab Rat
1654 posts

Never worked with nfs, so I can’t help you in this, sorry.

April 16, 2011

harry harry
Lab Rat
108 posts

the other option I’ve been thinking about is to store the files in the database… they aren’t that big, but I’ve been trying to avoid it…

 Signature 

If you can’t say what you mean, you’ll never be able to mean what you say.

April 17, 2011

ZapB ZapB
Robot Herder
1356 posts

Rather than using a windows share/samba where the path on each system is dependent upon where the share is mounted how about using some other protocol such as http or (WebDAV if you need write support too)?

 Signature 

Nokia Certified Qt Specialist
Interested in hearing about Qt related work

April 17, 2011

harry harry
Lab Rat
108 posts

Well the problem is that Qt is very limited (to my knowledge) in this respect.
Whereas in Obj-C there are truly great functions where one can easily load the contents of a url (which can be anything) in a string (through functions like initWithContentsOfURL) or file (with fileHandleForReadingFromURL), I’m surprised there are no such functions in the generally rich classes of QString and QFile.

The best I’ve managed to do when I have to do something similar, is use a helper function like

  1. QString MyHelperClass::downloadFile(const QString url)
  2. {
  3.     QNetworkAccessManager manager;
  4.     QEventLoop loop;
  5.     QNetworkReply *reply = manager.get(QNetworkRequest(QUrl(url)));
  6.     QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
  7.  
  8.     loop.exec();
  9.  
  10.    QString fname = QString("%1/tmp_%2")
  11.                     .arg(QDesktopServices::storageLocation(QDesktopServices::TempLocation))
  12.                     .arg(QDateTime::currentDateTime().toString("yyyyMMddHHmmss"));
  13.  
  14.     if (QFile::exists(fname))
  15.         QFile::remove(fname);
  16.  
  17.     QFile *tf = new QFile(fname);
  18.     if (!tf->open(QIODevice::WriteOnly)) {
  19.          QMessageBox::information(this, tr("Download file"), tr("Unable to save the file %1: %2.").arg(fname).arg(tf->errorString()));
  20.          delete tf;
  21.     };
  22.     tf->write(reply->readAll());
  23.     delete reply;
  24.  
  25.     tf->flush();
  26.     tf->close();
  27.     delete tf;
  28.  
  29.     QFileInfo fi(fname);
  30.     return fi.canonicalFilePath();
  31. }

to generate a temporary copy of a file locally, and then use the filename this function returns as an argument to QFile.
I’m pretty sure my implementation is terrible and that’s why I would like to avoid this approach, but I haven’t been able to come up with something better.

 Signature 

If you can’t say what you mean, you’ll never be able to mean what you say.

April 17, 2011

ZapB ZapB
Robot Herder
1356 posts

What do you need to do with the file(s) after you get access to them? Why are you saving it locally in the above example? It would be more efficient just to read from the QNetworkReply into whatever data structure is appropriate.

Also, please be aware that using local event loops like this are (in general) a bad idea. Other events are still processed which could result in your instance of MyHelperClass being deleted, then when your local event loop exits you are into the realms of undefined behaviour.

 Signature 

Nokia Certified Qt Specialist
Interested in hearing about Qt related work

April 17, 2011

harry harry
Lab Rat
108 posts

I need an actual filepath in this case, because it is passed to a 3rd party library (which uses QFile open as far as I know).
I’m pretty sure my function does not work without the loop.exec() call, and that’s why I added it.

That is why I mentioned I’m surprised that there is no helper function to perform such a common ( I would think) task.

 Signature 

If you can’t say what you mean, you’ll never be able to mean what you say.

April 18, 2011

ZapB ZapB
Robot Herder
1356 posts

Your function does not work without the local event loop as you are trying to use QNAM in a synchronous manner when it is designed for asynchronous use. The easiest way is to connect a slot up to the finished() signal of QNetworkReply. Something like this:

  1. void MtHelperClass::sendRequest( const QUrl& url )
  2. {
  3.     QNetworkRequest request;
  4.     request.setUrl( url );
  5.  
  6.     QNetworkReply* reply = m_nam->get( request );
  7.     connect( reply, SIGNAL( finished() ),
  8.              SLOT( processReply() ) );
  9.     connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ),
  10.              SLOT( onReplyError( QNetworkReply::NetworkError ) ) );
  11. }

where m_nam is a pointer to your application’s QNetworkAccessManager. Then in the two referenced slots you either handle the reply as you do in your example function or you handle the error.

There are also other signals that you can connect to. These allow you to show download progrerss for example or to check the http metadata (e.g. response code).

 Signature 

Nokia Certified Qt Specialist
Interested in hearing about Qt related work

Page  
1

  ‹‹ QScrollQArea and EnsureWidgetVisible      Load the object from dll ››

You must log in to post a reply. Not a member yet? Register here!