Link to home
Start Free TrialLog in
Avatar of RunBoris
RunBoris

asked on

Copy Files in C++

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?
ASKER CERTIFIED SOLUTION
Avatar of Kent Olsen
Kent Olsen
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of RunBoris
RunBoris

ASKER

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();

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

And of course,

char Command[1000];

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

system (Command);


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!
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