54

The Windows API function CopyFile has an argument BOOL bFailIfExists that allows you to control whether or not you want to overwrite the target file if it exists.

The boost::filesystem copy_file function has no such argument, and will fail if the target file exists. Is there an elegant way to use the boost copy_file function and overwrite the target file? Or is it better to simply use the Windows API? My current target platform is Windows, but I prefer to use STL and boost where possible to keep my code platform independent.

Thank you.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
Dani van der Meer
  • 6,169
  • 3
  • 26
  • 45

4 Answers4

77

There's a third enum argument to copy_file, boost::filesystem::copy_option::overwrite_if_exists

copy_file(source_path, destination_path, copy_option::overwrite_if_exists);

https://www.boost.org/doc/libs/1_75_0/libs/filesystem/doc/reference.html

Sergei Krivonos
  • 4,217
  • 3
  • 39
  • 54
anno
  • 5,970
  • 4
  • 28
  • 37
  • Thanks anno. I wasn't aware of this. It seems that this option was added sometime between version 1.35 that I was using when I asked the question, and version 1.41 that I'm using now. I can't find the change in the change history of the library. But anyway, problem solved. I'm not sure if I should now accept your answer, maybe I'll ask on meta. – Dani van der Meer Apr 27 '10 at 06:21
  • 3
    Beware: there seems to be an issue with this third argument in the POSIX implementation. See answer by Vitaly. – Dani van der Meer Dec 05 '10 at 08:09
  • 3
    @DanivanderMeer for the benefit of visitors to this page, [that bug was fixed years ago](https://svn.boost.org/trac/boost/ticket/4930). – Drew Dormann Oct 12 '14 at 13:58
19

Beware of boost::copy_file with copy_option::overwrite_if_exists! If the destination file exists and it is smaller than the source, the function will only overwrite the first size(from_file) bytes in the target file.

At least for me this was a caveat since I presumed copy_option::overwrite_if_exists affects files and not content

Vitaly P
  • 1,121
  • 3
  • 11
  • 21
  • I tried to reproduce on my platform (Windows), but couldn't. the overwrite does affect the complete file, regardless of size. What platform did you test on? – Dani van der Meer Nov 18 '10 at 16:53
  • IFAIK copy_option::overwrite_if_exists only exists on *nix (at least in boost-1.44 for filesystem v2). But you can easily see it in the the source code, the file is opened for writing with O_WRONLY but without O_TRUNC flag set. – Vitaly P Nov 18 '10 at 21:21
  • I am using boost 1.41. copy_option::overwrite_if_exists exists also for Windows. copy_file calls win32 API CopyFile (the A or W version) with bFailIfExists according to the option you pass to boost::copy_file. So possibly the behavior for Windows and POSIX is different? – Dani van der Meer Nov 19 '10 at 06:12
  • 3
    Yes it is different. I just submitted the bug to boost. See ISSUE #4930 (https://svn.boost.org/trac/boost/ticket/4930) – Vitaly P Dec 04 '10 at 17:05
  • 9
    According to boost this issue has been just fixed in rev. 67067 (so I expect it will be included in the upcoming boost-1.46) – Vitaly P Dec 07 '10 at 21:09
8

Test if the destination file exists first and if it does then remove it :

if (exists (to_fp))
    remove (to_fp);
copy_file (from_fp, to_fp);

Or if you're worried about the file appearing between the test and the copy then you could write to a temporary file and then rename it to the destination file.

jon hanson
  • 8,722
  • 2
  • 37
  • 61
  • Yes this is possible. But what if the copy operation fails? You already deleted the target. It doesn't have the same transaction-like semantics as CopyFile. – Dani van der Meer May 06 '09 at 13:23
  • Does the rename alternative not give you this? Anyway from looking at the boost source the API doesn't allow you to optionally overwrite the file. You could suggest this to them as an improvement. In the meantime you could take your own copy of the boost copy_file function and modify it to take an extra "overwrite" bool parameter. – jon hanson May 06 '09 at 13:58
  • Well, I guess the rename logic will work, but I was hoping there was something in the library that solves this, and that I won't have to solve it myself :). I will try to suggest it as an improvement. I think this is a logical and helpful feature. Anyway, thanks for your help. I will probably use CopyFile for now. – Dani van der Meer May 06 '09 at 15:37
  • Dani, the purpose to use boost is to write portable code, why to being so lazy you jeopardize the main reason to use boost ? – Gaetano Mendola May 11 '09 at 22:37
  • Portability is definitely an important reason for using Boost, but not necessarily the main reason. I would argue that the main reason for using a library like boost, but also the Windows API, is not having to implement basic functionality yourself (and test, debug, etc.). In this case these two reasons conflict, and I have to make the right trade-off. What is the right trad-off is of course a matter of opinion :). – Dani van der Meer May 13 '09 at 11:25
  • I decided to accept this answer, even though it is not a complete answer to the question. Apparently there is no better answer, and this answer describes the best approach. – Dani van der Meer Aug 24 '09 at 07:39
  • You might want to raise it with boost. Obviously Windows supports this, and Unix does through the O_CREAT & O_EXCL flags to open(), so I don't see why boost can't support it as well. – jon hanson Aug 25 '09 at 08:07
2

Is there an elegant way to use the boost copy_file function and overwrite the target file?

Apparently there's no direct API to do this.

Or is it better to simply use the Windows API? My current target platform is Windows, but I prefer to use STL and boost where possible to keep my code platform independent.

From the documentation:

A proposal, N1975, to include Boost.Filesystem in Technical Report 2 has been accepted by the C++ Standards Committee. The Boost.Filesystem library will stay in alignment with the TR2 Filesystem proposal as it works its way through the TR2 process. Note, however, that namespaces and header granularity differs between Boost.Filesystem and the TR2 proposal.

Which strongly suggests that sticking with boost::filesystem is a good idea.

dirkgently
  • 108,024
  • 16
  • 131
  • 187