How to move files in Qt? - c++

Is there a cross-platform function in Qt that is equivalent to the MoveFile function in Windows and the mv command in Linux?

Sure, QDir::rename() following the old Unix / POSIX tradition of calling this rename.
Which makes sense if you think of a file with its complete path: the underlying inodes just get assigned a different path/file label.

You would use QDir::rename() but be beware of the special cases when rename() can fail:
On most file systems, rename() fails
only if oldName does not exist, if
newName and oldName are not on the
same partition or if a file with the
new name already exists. However,
there are also other reasons why
rename() can fail. For example, on at
least one file system rename() fails
if newName points to an open file.

QUrlOperator::copy() is an alternative to QDir::rename() that may also work for you.

Related

How to open a file ending with a particular extension in C++

I am trying to write a lexer using flex, and want to open and read from a file ending with a particular extension. E.g filename.k. I am only able to do it if I specify the file name as well as the extension.
FILE *myfile = fopen("a.k", "r");
if (!myfile) {
cout << "I can't open a.k!" << endl;
Can someone show me the way to open *.k files in C++.
I am running flex on Ubuntu. What I am trying to do is to run a flex program. The above code executes fine. I wanted a way where I can open a file with .k extension irrespective of the file name. Example. ./myprogram a.k or ./myprogram b.k. In the above example I always have to specify the file name in the code itself all the time.
Comment to Basile's anser:
[...] Such as ./myprogram a.k, I wanted a way where I can write any filename instead of a but ending with a .k extension.
While the cited answer technically is correct, I think your true problem is how to get some arbitrary, but specific file path from the command line:
Example: ./myprogram a.k or ./myprogram b.k
The thing is quite easy: you get the command line parameters passed directly to your main function, provided you use the variant accepting them:
int main(int argc, char* argv[]);
First parameter (argv[0]) is always the name of your programme (or an empty string, if not available), so argc will always be at least one. Afterwards the parameters provided follow, so invoking "./myprogram b.k" will result in argc being two and argv pointing to a char* array equivalent to the following:
char* argv[] =
{
"./myprogram",
"b.k",
nullptr // oh, yes, the array is always null terminated...
};
And then, the matter gets easy: Check, if the parameter is given at all: if(argc == 2) or, if you are willing to accept but ignore any additional parameters, if(argc >= 2) or simply if(argv[1]) (as it will be nullptr, if no parameter given, or the first parameter otherwise) and then use it for fopen or, if you prefer a more C++ like way, to open a std::ifstream. You might want to have additional checks, e. g. if the file name really ends with ".k", but that's up to you now...
Your fopen-ing code is good, but running in conditions (e.g. in some weird working directory, or without sufficient permissions) which make the fopen fail.
I recommend to use errno (perhaps implicitly thru perror) in that failure case to get an idea of the failure reason:
FILE *myfile = fopen("a.k", "r");
if (!myfile) {
perror("fopen of a.k");
exit(EXIT_FAILURE);
}
See e.g. fopen(3), perror(3), errno(3) (or their documentation for your particular implementation and system).
Notice that file extensions don't really exist in standard C++11 (but C++17 has filesystem). On Linux and POSIX systems, file extensions are just a convention.
Can someone show me the way to open *.k files in C++.
If you need to open all files with a .k extension, you may rely on globbing (on POSIX, run something like yourprog *.k in your shell, which will expand the *.k into a sequence of file names ending with .k before running your program, whose main would get an array of arguments; see glob(7)), or you have to loop explicitly using operating system primitives or functions (perhaps with glob(3), nftw(3), opendir(3), readdir(3), ... on Linux; for Windows, read about FindFirstFile etc...)
Standard C++11 don't provide a way to iterate on all files matching a given pattern. Some framework libraries (Boost, Poco, Qt) do provide such a way. Or you need to use operating system specific functions (e.g. to read the current directory. But directories are not known to C++11 and are an abstraction provided by your operating system). But C++17 has filesystem, but you need a very recent compiler and C++ standard library to get that.
BTW, on Unix or POSIX systems, you could have one single file named *.k. Of course that is very poor taste and should be avoided (but you might run touch '*.k' in your shell to make such a file).
Regarding your edit, for Linux, I recommend running
./myprogram *.k
(then your shell will expand *.k into one or several arguments to myprogram)
and code the main of your program myprog appropriately to iterate on arguments. See this.
If you want to run just myprogram without any additional arguments, you need to code the globbing or the expansion inside it. See glob(3), wordexp(3). Or scan directories (with opendir(3), readdir(3), closedir, stat(2) or nftw(3))

Is there any difference between unlink() and remove() on a file? [duplicate]

What is the difference between remove and unlink functions in C++?
Apart from the fact that unlink is unix-specific (as pointed out by Chris), we read in the POSIX manual:
If path does not name a directory, remove(path) is equivalent to unlink(path).
If path names a directory, remove(path) is equivalent to rmdir(path).
As for the directory-passed unlink, we read:
The path argument must not name a directory unless the process has appropriate privileges and the implementation supports using unlink() on directories. (...) Applications should use rmdir() to remove a directory.
remove is portable, and unlink is Unix-specific. :-P
The remove() function removes the file or directory specified by path.
If path specifies a directory, remove(path) is the equivalent of
rmdir(path). Otherwise, it is the equivalent of unlink(path).
From: man remove.
Good Luck ;)
unlink is not unix-specific, i don't know why people're saying that. see io.h. although you'll probably have to do something like
#define unlink _unlink
http://msdn.microsoft.com/en-us/library/1c3tczd6%28v=VS.100%29.aspx
http://msdn.microsoft.com/en-us/library/2da4hk1d%28v=VS.100%29.aspx
remove() is part of the C++ standard (N4860 29.11.14.30). unlink() is not.

How do you determine full paths from filename command line arguments in a c++ program?

I am writing a program in c++ that accepts a filename as an argument on the command line:
>> ./myprogram ../path/to/file.txt
I know I can simply open an fstream using argv[1], but the program needs more information about the exact location (ie. full pathname) of the file.
I thought about appending argv[1] to getcwd(), however obviously in the example above you'd end up with /path/../path/to/file.txt. Not sure whether fstream would resolve that path automatically, but even if it did, I still don't have the full path without a lot of string processing.
Of course, that method wouldn't work at all if the path provided was already absolute. And since this program may be run on Linux/Windows/etc, simply detecting a starting '/' character won't work to determine whether the argument was a full path or not.
I would think this is a fairly common issue to deal with path names across multiple OSs. So how does one retreive the full path name of a command line argument and how is this handled between operating systems?
Pathname handling is highly OS-specific: some OS have a hierarchy with just one root (e.g. / on Unix ), some have several roots a la MS-DOS' drive letters; some may have symbolic links, hard links or other kinds of links, which can make traversal tricky. Some may not even have the concept of a "canonical" path to a file (e.g. if a file has hard links, it has multiple names, none of which is more "canonical").
If you've ever tried to do path-name manipulation across multiple OS in Java, you know what I mean :-).
In short, pathname handling is system-specific, so you'll have to do it separately for each OS (family), or use a suitable library.
Edit:
You could look at Apache Portable Runtime, or at Boost (C++ though), both have pathname handling functions.
...you'd end up with /path/../path/to/file.txt. Not sure
whether fstream would resolve that
path automatically, but even if it
did, I still don't have the full path
without a lot of string processing.
It does, and you can use /path/../path/ for everything you want without problems.
Anyway there is no standard function in C++ to do what you want. You would have to do it manually, and it wouldn't be trivial.. I suggest you keep the path as it is, it shouldn't cause any problems.
It is OS-dependent. If you are using linux you can look at realpath(). No doubt Windows has something comparable.
AFAIK there is no standard way.
however you could try this approach (written in pseudocode):
string raw_dirname=get_directory_part(argv[1])
string basename=get_filename_part(argv[1])
string cwd=getcwd()
chdir(relative_dirname)
string absolute_dirname=getcwd()
chdir(cwd)
string absolute_filename=absulute_dirname + separator + basename
but note: I am not quite sure if there are issues when symbolic links come into play.

How can I create a temporary file for writing in C++ on a Linux platform?

In C++, on Linux, how can I write a function to return a temporary filename that I can then open for writing?
The filename should be as unique as possible, so that another process using the same function won't get the same name.
Use one of the standard library "mktemp" functions: mktemp/mkstemp/mkstemps/mkdtemp.
Edit: plain mktemp can be insecure - mkstemp is preferred.
tmpnam(), or anything that gives you a name is going to be vulnerable to race conditions. Use something designed for this purpose that returns a handle, such as tmpfile():
#include <stdio.h>
FILE *tmpfile(void);
The GNU libc manual discusses the various options available and their caveats:
http://www.gnu.org/s/libc/manual/html_node/Temporary-Files.html
Long story short, only mkstemp() or tmpfile() should be used, as others have mentioned.
man tmpfile
The tmpfile() function opens a unique temporary file in binary
read/write (w+b) mode. The file will be automatically deleted when it
is closed or the program terminates.ote
mktemp should work or else get one of the plenty of available libraries to generate a UUID.
The tmpnam() function in the C standard library is designed to solve just this problem. There's also tmpfile(), which returns an open file handle (and automatically deletes it when you close it).
You should simply check if the file you're trying to write to already exists.
This is a locking problem.
Files also have owners so if you're doing it right the wrong process will not be able to write to it.

How do I find the 'temp' directory in Linux?

How do I find the 'temp' directory in Linux? I am writing a platform neutral C++ function that returns the temp directory. In Mac and Windows, there is an API that returns these results. In Linux, I'm stumped.
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Check following variables:
The environment variable TMPDIR
The value of the P_tmpdir macro
If all fails try to use the directory /tmp.
You can also use tempnam function to generate a unique temporary file name.
Edit: Fair point from the commenter. tmpnam isn't a good choice these days; use mktemp/mkstemp instead.
Historical answer: Be POSIX compliant, and use tmpnam (which will give you a full filename in a temporary location).
Use the value of the $TMPDIR environment variable, and if that doesn't exist, use /tmp.
The accepted sequence, specifically from a GNU standpoint, is:
Check the environmental variable TMPDIR (getenv("TMPDIR")) only if
the program is not running as SUID/SGID (issetugid() == 0)
Otherwise use P_tmpdir if it is defined and is valid
and finally, should those fail, use _PATH_TMP available from paths.h
If you are adding an extension or module, check to see if the core provides a function for this purpose. For example, PHP exports php_get_temporary_directory() from main/php_open_temporary_file.h.
In standard c, you could try: P_tmpdir