Results 1 to 20 of 30

Thread: Saving a file using a relative path

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Apr 2014
    Posts
    59
    Thanks
    7
    Qt products
    Qt5
    Platforms
    Windows

    Default Saving a file using a relative path

    Hi,

    It is simple enough to open a file with a relative path using QApplication::applicationDirPath(). If I use that for saving, however, I end up with an absolute path. Since I intend to have my program run from a thumb drive, that can be problematic when a different computer is used. I currently have "debug" hard coded as the root, but when I switch to a release build, I will need to find all the instances, and change them. All my searches turn up solutions to opening files, which is not an issue. If someone could suggest a solution, it would be appreciated.

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Saving a file using a relative path

    If you can open a file for reading using a path relative to your application's directory, you can open it for writing the same way. I think you are going to have to post the code that demonstrates the problem you are having because somehow you must be converting the relative path to an absolute path somewhere along the line.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. #3
    Join Date
    Apr 2014
    Posts
    59
    Thanks
    7
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Saving a file using a relative path

    Oops, I guess I did a bad job of explaining.

    In one instance what I am doing is saving the path, as a string, in a QTableView. In that case I have a dialog that opens a QFileDialog to get the path to an image.
    Qt Code:
    1. void AddImageDialog::on_selectBtn_clicked()
    2. {
    3. QString home = "debug";
    4. QString path = QFileDialog::getOpenFileName(this, "Select Imagae", home + "/images",
    5. "Images(*.jpg);;All Files(*.*)");
    6. if(ui->relativeCB->isChecked())
    7. {
    8. QFileInfo relativePath(path);
    9. ui->pathTxt->setText(home + "/images/" + relativePath.fileName());
    10. }
    11. else
    12. ui->pathTxt->setText(path);
    13. }
    To copy to clipboard, switch view to plain text mode 
    The path is then retrieved from pathTxt by the delegate, and put in the model.
    Qt Code:
    1. else if(header == "Image")
    2. {
    3. AddImageDialog *dialog = new AddImageDialog(parent);
    4. dialog->exec();
    5.  
    6. model->setData(index, dialog->getPath());
    7. }
    To copy to clipboard, switch view to plain text mode 
    I then display the image in the cell.

    If I use QApplication::applicationDirPath(), then the path ends up being hard coded to my development directory, witch will break the path, if I move the folder. I have several other, similar, situations scattered throughout various classes, so you can imagine how unmanageable it is.

  4. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Saving a file using a relative path

    One way I avoid this is to not use the QFileDialog::getOpenFileName() static method. Instead, I use the non-static mechanism of creating a QFileDialog instance on the stack and connecting slots to the QFileDialog::fileSelected() and QFileDialog::directoryEntered() signals. I then call QFileDialog::exec() and let the slots handle it.

    In particular, I use the directoryEntered() signal to keep track of where the user last browsed for a file, and can use that location to initialize the dialog the next time I use it. If I want to remember between executions, I use QSettings to put it in an ini file. The first time I run the program, I can choose to either use the applicationDirPath -or- (better) use something appropriate from QStandardPaths.

    An additional remedy is to give the user a way to browse for the directory containing the images if the stored path doesn't exist. You can do that with QFileDialog with FileMode set to Directory and Option set to ShowDirsOnly. Once you get the name of the directory (from the directoryEntered() or maybe fileSelected() signal). You can then update your table to use this for subsequent image loads.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  5. #5
    Join Date
    Apr 2014
    Posts
    59
    Thanks
    7
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Saving a file using a relative path

    If I understand you correctly, you are suggesting I make the user set a new path every time they switch machines. I also have another column that links to a PDF. While it is not an issue if the PDF is online, it defeats the purpose if it is stored locally.

    Let me give a use case example of what I am trying to accomplish. If I am working on a project in Qt, for example, and want to move to another machine, I just need to move the project folder. In school, we used Android Studio, in a class, and I could not easily work on a project at home, and in class, because the path was hard coded into the project, I forget were. I could put it on a thumb drive and switch, as long as I made sure the root directory was the same, which meant plugging in various USB devices, until it was the same. Alternately, I could go into the setting, somewhere, and change the root manually, each time. Neither of those options were convenient, and making the root the same was the easiest. While making sure the root of the thumb drive is the same, compared to changing, possibly, hundreds of links when switching machines, is one way around it, I want the user to not have to worry about any of that, and have it just work, like a Qt project would.

  6. #6
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Saving a file using a relative path

    If I understand you correctly, you are suggesting I make the user set a new path every time they switch machines.
    No, I am suggesting that you ask the user to browse for the correct path if the path that is saved can't be found on a different machine (or maybe also, if the path exists, the images aren't there).

    We use this method in some of our apps. Most of the information is stored in the app's "project" file, but this file can refer to external files that contain experimental data that is too big or not appropriate to store in the project file. These are stored with absolute paths. When we open the project file, we also try to automatically find the external files. If we can't (eg. we're working on our laptop instead of our desktop PC) we put up a dialog that says, "Can't find XYZ. Do you want to browse for it?" If they say yes and browse to the new location, we remember that and correct the absolute paths to point to the new location so we won't have to ask again. If the user says "no", then you have to go to Plan B, which in our case is to allow the user to do as much processing as possible in the absence of the external data.

    Storing relative paths doesn't avoid this problem, because the relative path on one PC might not be the same (or even exist) on a different PC and you're stuck in the same boat. The only way relative paths work is if everything you need is stored under a single "root" directory, so all you need remember is the directory where your project file lives on the system where you are now using it, and everythings else lives in or beneath that.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  7. #7
    Join Date
    Apr 2014
    Posts
    59
    Thanks
    7
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Saving a file using a relative path

    OK, I understand what you are saying now. I guess I am still not explaining myself well as that is not really what I am going for. I only need it to work if the file is saved in a folder, inside the application folder, or the one that opens by default in my code. It sounds like my only other option is to store the files as BLOBs in the data base, as opposed to saving the paths as a strings. I might try setting a global is main(), but I am not sure if that will even work.

  8. #8
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Saving a file using a relative path

    I only need it to work if the file is saved in a folder, inside the application folder
    Well, if you're on Windows 7 or 10, this isn't going to work because most users don't have permission to create files in the application's install directory except at install time. Sometimes they aren't even allowed to write to files that already exist there. So using the application directory only works when you're the developer and the application directory is just a normal location on your disk somewhere.

    It is better to use QStandardPaths to find a directory and use that as the default location to create and save project files instead of hard-coding a fixed path in your source code. Using QStandardPaths is basically finding a relative location; it just changes as a function of the PC and user.

    It sounds like my only other option is to store the files as BLOBs in the data base
    If your app won't work if the files aren't present somewhere in the file system, then this is about your only viable solution.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  9. #9
    Join Date
    Apr 2014
    Posts
    59
    Thanks
    7
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Saving a file using a relative path

    Hi, I missed the notification, so sorry for my late reply.

    Well, if you're on Windows 7 or 10, this isn't going to work because most users don't have permission to create files in the application's install directory except at install time
    I think you are misunderstanding my purpose, I do not intend to use an installer as this is meant to be portable, run on a thumb drive. The user should be able to put the application anyplace they want, or easily move it around. They should have no problem copying a PDF or image into the application folder.

    I am trying to avoid using BLOBs as I do not believe this is how they were intended to be used. Databases are far from my strong point, so I could be mistaken about that.

  10. #10
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Saving a file using a relative path

    You have completely baffled me about what you are trying to accomplish. If you are storing everything on a thumb drive, and everything is stored relative to the directory the program is running in, then why are you having such a hard time getting the current (application) directory and creating paths relative to that?

    If you are storing images or whatever as separate files, then either they are stored relative to the program directory or they aren't. And if they aren't stored in the relative location where you expect them to be then either a) the user has moved or deleted them (or they weren't there to begin with) or b) the relative path you think you are constructing isn't correctly pointing where you think it is.

    So if your app can't find the files it needs, then you have the choice of a) running without them or b) trying to find them in an alternative location. The easiest way to do this is to simply ask the user where he or she put them. If the answer to that is "I deleted them" then you are back to Plan A.

    By the way, if you are using SQLite as a database, BLOBs in the database take basically the same space as a file on disk (and possibly less because there is less file system overhead), so you can guarantee you'll always have the files you need by storing them in a database. Then you just have the problem of finding the database at runtime.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  11. #11
    Join Date
    Apr 2014
    Posts
    59
    Thanks
    7
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Saving a file using a relative path

    I apologize for not doing a very good job of describing my situation, but I think you hit on the problem with
    then why are you having such a hard time getting the current (application) directory and creating paths relative to that?
    I am storing the path, in the database, as a string(VARCHAR), either absolute, or relative, I am leaving it to the user to select which. So, once it is entered into the database, it basically becomes an absolute path (which is why I cannot use QApplication::applicationDirPath()). For example, this is how I handle it in the model.
    Qt Code:
    1. QVariant TableModel::data(const QModelIndex &idx, int role) const
    2. {
    3. QString header = QSqlTableModel::headerData(idx.column(), Qt::Horizontal).toString();
    4. if(header == "Datasheet")
    5. {
    6. QString link = QSqlTableModel::data(idx, Qt::DisplayRole).toString();
    7.  
    8. switch(role)
    9. {
    10. case Qt::DisplayRole:
    11. return QString();
    12. break;
    13. case Qt::DecorationRole:
    14. if(QStringRef(&link, 0, 4) == "http")
    15. {
    16. QPixmap pixmap(":/Images/Images/internet.png");
    17. return pixmap;
    18. }
    19. else if(link == "")
    20. return QVariant();
    21. else
    22. {
    23. QPixmap pixmap(":/Images/Images/pdf.png");
    24. return pixmap;
    25. }
    26. break;
    27. case Qt::UserRole:
    28. return link;
    29. break;
    30. }
    31. }
    32.  
    33. if(header == "Image")
    34. {
    35. QString link = QSqlTableModel::data(idx, Qt::DisplayRole).toString();
    36.  
    37. switch(role)
    38. {
    39. case Qt::ToolTipRole:
    40. return QString("<img scr='%1'>").arg(link);
    41. break;
    42. }
    43. }
    44.  
    45. return QSqlTableModel::data(idx, role);
    46. }
    To copy to clipboard, switch view to plain text mode 

    And just for completeness, unless I forgot something, the PDFs are handled this way
    Qt Code:
    1. void MainWindow::on_dataView_activated(const QModelIndex &index)
    2. {
    3. QString header = model->headerData(index.column(), Qt::Horizontal).toString();
    4.  
    5. if(header == "Datasheet")
    6. {
    7. QString link = index.data(Qt::UserRole).toString();
    8.  
    9. if(QStringRef(&link, 0, 4) == "http")
    10. QDesktopServices::openUrl(link);
    11. else if(link == "")
    12. return;
    13. else
    14. QDesktopServices::openUrl("file///" + link);
    15. }
    16. }
    To copy to clipboard, switch view to plain text mode 
    Then you just have the problem of finding the database at runtime.
    There is no problem using QApplication::applicationDirPath() for that, since it is not based on a string.

    This has gotten me to thinking that I might be able to use similar mechanics, like I do in the last bit using QStringRef(), to determine if the link has been truncated, to a relative link, in which case I should then be able to use QApplication::applicationDirPath(). I am going to have to think on that a bit.

    <edit> I expect the user to not worry about the relative path part, if they are not interested having the application portable.</edit>
    Last edited by admkrk; 28th June 2017 at 05:15.

Similar Threads

  1. Replies: 0
    Last Post: 14th September 2013, 10:14
  2. Replies: 16
    Last Post: 24th January 2013, 02:52
  3. Downloading a file and saving in a path
    By StarRocks in forum Qt Programming
    Replies: 19
    Last Post: 3rd January 2013, 06:43
  4. qmake absolute vs relative LIBS path
    By TheShow in forum Newbie
    Replies: 7
    Last Post: 12th October 2010, 14:40
  5. Replies: 8
    Last Post: 17th October 2009, 08:10

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.