We help IT Professionals succeed at work.

Copy Files in C++

RunBoris
RunBoris asked
on
I'm wondering if there's a way to copy files in C++ using string variables. ALSO, the file paths/names may have spaces.

For example, let's say this C++ app is going through a list of recently modified files:
C:\Folder1\file1.ext
D:\Folder Number 2\File Number 2.ext
E:\Folder #3\File #3.ext
etc.

And I want to copy them as such:
F:\Copied Files\File 1.ext
F:\Copied Files\File 2.ext
F:\Copied Files\File 3.ext
etc.

I have made the appropriate string function to format the output as necessary, but I need to find a C++ function to copy file longer than standard DOS 8.3 filename format. Is there any such beast, or am I in need of a VisualC++ class?
Comment
Watch Question

Data Warehouse / Database Architect
SILVER EXPERT
Commented:
Hi Boris,

It seems that you have already determined what files to copy so the hard part is done.

To copy the files, it's probably easiest to call the system's copy utility.

char Command[1000];

  strcpy (Command, "copy ");   //  For DOS / Windows
  strcpy (Command, "cp ");      //  For unix / linux

  strcat (Command, sourcfilename);
  strcat (Command, " ");
  strcat (Command, "newfilename);

  system (Command);


That should do the trick,

Kent

Author

Commented:
That didn't quite work. Part of the problem is most of the copy function I've seen require a CONST CHAR input. I need it to accept string variables. The strings I have are strSource & strDestination. These strings can be quite extensive. For example, one strSource in the listArray may be "C:\My Documents\My Music\Panic! At The Disco\(2005) A Fever You Can't Sweat Out\02 - The Only Difference Between Martyrdom And Suicide Is Press Coverage.mp3", and the corresponding strDestination might be "D:\Backup Files\Music\Panic! At The Disco - The Only Difference Between Martyrdom And Suicide Is Press Coverage.mp3". And this process would repeat for every item in the listArray, possibly hundreds of times. Anywho, here's the errors I got:

345 \main.cpp no matching function for call to `strcat(char[1000], std::string&)'
note C:\Dev-Cpp\include\string.h:41 candidates are: char* strcat(char*, const char*)
use std::string's c_str() function to get the const char * version of the string:

strSource.c_str();
Kent OlsenData Warehouse / Database Architect
SILVER EXPERT

Commented:

Hi Boris,

system () wants a char*, not an std::string.

To go forward with this approach, you can build the command up in a char* buffer and pass it, or build the command up as a std::string and pass the address of the string's buffer.

Either way you'll call the c_str() method, as Sean indicates.  The only issue when the method gets called.

It's probably a bit cleaner to do the latter.  Build an std::string object.  That pretty much eliminates buffer overruns or other similar problems.

  std::string Command;

  Command = "copy ";   // Command = "cp " for a *nix system
  Command = Command + strSource;
  Command = Command + " ";
  Command = Command + strDestination;

  system (Command.c_str ());

Note that the entire generated string can not be longer than the longest legal command line.


Kent
Kent OlsenData Warehouse / Database Architect
SILVER EXPERT

Commented:

And of course,

char Command[1000];

snprintf (Command, 1000, "copy %s %s", strSource.c_str (), strDestination.c_str ());

system (Command);


Author

Commented:
ok, that actually did work. HOWEVER, for long filenames and spaces, I had to add quotation marks to the beginning and end of the strings. Thanks!
evilrixSenior Software Engineer (Avast)
SILVER EXPERT

Commented:
Using the system() function to copy files means you don't have good control over error handling. What do you do if the file already exists or if the file can't be copied for some reason? There are many things that could go wrong and trying to figure out what and how to deal with it just from the error status code returned by system isn't likely to be very easy. Below I've written you a small function that will copy a file programmatically. It has the option to force overwrite if the file already exists.

I've tested this code using my own test sample and it worked file; however, if you do decide to use this code you should test it thoroughly before putting it into a production environment.

I hope this helps.

-Rx.
#include <io.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>
 
 
void copy_file(std::string const & sOldPath, std::string const & sNewPath, bool bOverWrite = false)
{
	if(!bOverWrite && (0 == access(sNewPath.c_str(), 0x00))) { throw std::runtime_error("Output file already exists"); }
 
	std::ifstream ifs(sOldPath.c_str(), std::ios::binary);
	if(!ifs.is_open()) { throw std::runtime_error("Unable to open input file"); }
 
	std::ofstream ofs(sNewPath.c_str(), std::ios::trunc | std::ios::binary);
	if(!ofs.is_open()) { throw std::runtime_error("Unable to open output file"); }
 
	ifs.seekg(0, std::ios::end);
	std::ifstream::pos_type size = ifs.tellg();
	ifs.seekg(0);
 
	std::string sData(size, std::string::value_type());
 
	ifs.read(&sData[0], size);
	if(!ifs.good()) { throw std::runtime_error("Unable to read input file"); }
 
	ofs.write(sData.data(), size);
	if(!ifs.good()) { throw std::runtime_error("Unable to write output file"); }
}
 
int main()
{
	int nRetval = 0;
 
	try
	{
		std::string sOldPath = "c:\\temp\\test.txt";
		std::string sNewPath = "c:\\temp\\newtest.txt";
 
		copy_file(sOldPath, sNewPath);
 
		std::cout << "Copied " << sOldPath << " to " << sNewPath << " successfully." << std::endl;
	}
	catch(std::exception const & ex)
	{
		std::cerr <<"Error. " << ex.what() << std::endl;
		nRetval = -1;
	}
 
#ifdef WIN32
	system("pause"); // Only works on Windows
#endif
 
	return nRetval;
}

Open in new window

Explore More ContentExplore courses, solutions, and other research materials related to this topic.