views:

117

answers:

3

I am using the following program to try to copy the contents of a file, src, to another, dest, in C++. The simplified code is given below:

#include <fstream>
using namespace std;
int main()
{
  fstream src("c:\\tplat\test\\secClassMf19.txt", fstream::binary);
  ofstream dest("c:\\tplat\\test\\mf19b.txt", fstream::trunc|fstream::binary);
  dest << src.rdbuf();
  return 0;
}

When I built and executed the program using CODEBLOCKS ide with GCC Compiler in windows, a new file named "....mf19.txt" was created, but no data was copied into it, and filesize = 0kb. I am positive I have some data in "...secClassMf19.txt".

I experience the same problem when I compiled the same progeam in windows Visual C++ 2008.

Can anyone please help explain why I am getting this unexpected behaviour, and more importantly, how to solve the problem?

+2  A: 

You need to check whether opening the files actually succeeds before using those streams. Also, it never hurts to check if everything went right afterwards. Change your code to this and report back:

int main()
{
    std::fstream src("c:\\tplat\test\\secClassMf19.txt", std::ios::binary);
    if(!src.good())
    {
        std::cerr << "error opening input file\n";
        std::exit(1);
    }
    std::ofstream dest("c:\\tplat\\test\\mf19b.txt", std::ios::trunc|std::ios::binary);
    if(!dest.good())
    {
        std::cerr << "error opening output file\n";
        std::exit(2);
    }
    dest << src.rdbuf();
    if(!src.eof())
        std::cerr << "reading from file failed\n";
    if(!dst.good())
        std::cerr << "writing to file failed\n";
    return 0;
}

I bet you will report that one of the first two checks hits.

If opening the input file fails, try opening it using std::ios::in|std::ios::binary instead of just std::ios::binary.

sbi
+1  A: 

Hi

Do you have any reason to not use CopyFile function?

Best

Vagaus
I have tried the suggestions by sbi (using std::ios::in|std::ios::binary instead of just std::ios::binary), still the program fails to read the input file (return 1). Even using ifstream as suggested by gavinb yiels no joy.
T J
I have just seen Vagaus suggestion wrt. CopyFile. But I have tried that earlier (adding #include <windows.h>. The code I used then was: CopyFile( (LPCWSTR)"c:\\tplat\test\\secClassMf19.txt", (LPCWSTR)"c:\\tplat\\test\\mf19b.txt",true); But it did not work either. Perhaps I'm doing something wrong.
T J
+1  A: 

As it is written, your src instance is a regular fstream, and you are not specifying an open mode for input. The simple solution is to make src an instance of ifstream, and your code works. (Just by adding one byte!)

If you had tested the input stream (as sbi suggests), you would have found that it was not opened correctly, which is why your destination file was of zero size. It was opened in write mode (since it was an ofstream) with the truncation option to make it zero, but writing the result of rdbuf() simply failed, with nothing written.

Another thing to note is that while this works fine for small files, it would be very inefficient for large files. As is, you are reading the entire contents of the source file into memory, then writing it out again in one big block. This wastes a lot of memory. You are better off reading in chunks (say 1MB for example, a reasonable size for a disk cache) and writing a chunk at a time, with the last one being the remainder of the size. To determine the source's size, you can seek to the end and query the file offset, then you know how many bytes you are processing.

And you will probably find your OS is even more efficient at copying files if you use the native APIs, but then it becomes less portable. You may want to look at the Boost filesystem module for a portable solution.

gavinb
I've tried the suggestion of sbi, and it shows the error reading the input file (retuen 1).
T J
I have tried the suggestions by sbi (using std::ios::in|std::ios::binary instead of just std::ios::binary), still the program fails to read the input file (return 1). Even using ifstream as suggested by gavinb yiels no joy. I have just seen Vagaus suggestion wrt. CopyFile. But I have tried that earlier (adding #include <windows.h>. The code I used then was: CopyFile( (LPCWSTR)"c:\\tplat\test\\secClassMf19.txt", (LPCWSTR)"c:\\tplat\\test\\mf19b.txt",true); But it did not work either. And the file opens in NOTEPAD, size is only 1kb.
T J
@T J: Does it fail to _open_ the file or fail to _read_ it?
sbi
(Note that, with a user name yours, doesn't start with at least three alphanumerical characters, you won't be notified when addressed in comments using the @username syntax. You see this here, because it's added to an answer to your question, but in any other question, when someone replies to one of your comments, it won't show up in your "Responses" tab.)
sbi
Input file "...secClassMf19.txt" fails to open.
T J
You're missing a double-backslash between "tplat" and "test" in your source filename. So you'd be getting an error code telling you the file is not found. If you use forward slashes instead, it will work just fine, also work on POSIX systems, and is easier to read. I tested my modification on OS X and it works fine.
gavinb
"Oh! Silly me! Thanks mate. I was looking for a "camel of a proglem", while overlooking a "gnat". Although the following part of the earlier suggestion by sbi is hit, I do not think I need the check anyway. So I guess I will simply remove it from the code. if(!src.eof()) std::cerr << "reading from file failed\n"; The main thing is the file is correctly copied as expected.
T J
@T J: Removing tests because they have never hit is like removing a balustrade because nobody ever fell down.
sbi