6

I'd like to make a copy of some/path/myfile in $TMPDIR/myprog-<random-string>.ext, such that I can then pass it on to a 3rd party procedure that chokes on extensionless files.

Here's what I'd like to work:

QString originalPath = "some/path/myfile";

QTemporaryFile f(
    QDir::temp().absoluteFilePath("mprog-XXXXXX.ext")
);

// f.open(); ?

QFile(originalPath).copy(f.fileName());

However, I now have a problem - either the file doesn't yet exist, and thus hasn't been assigned a temporary fileName(), or the file name has been assigned but the file itself already exists, preventing the new file being copied on top.

How can I copy a file to a temporary location in QT, and have the temporary copy removed when the destructor of QTemporaryFile is called?

Eric
  • 95,302
  • 53
  • 242
  • 374

3 Answers3

2

If the file doesn't exist, create the QTemporaryFile object exactly as you have done, open it and then close it immediately. This will generate the random filename and create it on the disk.

When your QTemporaryFile object gets destroyed, the file will be deleted from the disk.

RobbieE
  • 4,280
  • 3
  • 22
  • 36
  • 2
    At the point that it exists on disk, `.copy(` will refuse to make the copy and overwrite it – Eric Jul 29 '14 at 12:42
  • From docs: "Note that if a file with the name newName already exists, copy() returns false..." – vahancho Jul 29 '14 at 12:46
  • Also from the docs: "The name of the temporary file is guaranteed to be unique (i.e., you are guaranteed to not overwrite an existing file), and the file will subsequently be removed upon destruction of the QTemporaryFile object" – RobbieE Jul 29 '14 at 13:15
1

Unfortunately, Qt (5.3) doesn't support copying to an existing file. The only correct, race-free use of QTemporaryFile is to open() it, creating it in the process, and then operate on it.

You'll need to implement the copy yourself, I'm afraid :(

On Windows, if you expect there to be some gain from using CopyFileEx, I have a complete example that wraps it for Qt's perusal, with progress signals.

The real question is: do you really need to create a copy? Wouldn't a hard link do? Since Qt runs, for the most part, on Unices and Windows, you can create a symbolic link wrapper that will wrap POSIX link() and winapi CreateHardLink. If hard link creation fails, or the temporary folder is on a different volume, you can then try CreateSymbolicLink. Of course you'd need to look up CreateSymbolicLinkW using QLibrary if you intend your executable to start un XP at all. If that fails, you're either running on XP or on a FAT partition, and the final fallback is copying.

Would it be out of the question to rename the file, run the 3rd-party application on it, then rename it back?

Community
  • 1
  • 1
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
0

If you're not going to be actually using the file / stream to the file QTemporaryFile created for you, you're better off using QUuid instead to just generate a guaranteed unique filename. This generates a unique filename, roughly equivalent to QTemporaryFile:

QUuid uuid = QUuid::createUuid();
QString tempFileFullPath = QDir::toNativeSeparators(QDir::tempPath() + "/" + qApp->applicationName().replace(" ", "") + "_" + uuid.toString(QUuid::WithoutBraces) + ".dat");

I like the temporary filename to not contain spaces, so I removed that from the app name used for the filename prefix. (You should call QApplication::setApplicationName in your main() function so this will work.)

Also, you should probably change the .dat extension to something suitable for your file type.

savolai ᯓ
  • 666
  • 5
  • 20