Copying Files in Delphi: Using Streams

I'd like to be able to copy files in Delphi, but am having trouble figuring out how to do it. I've been using operating system level calls, but don't want to limited by them. Is there a way to do it in Delphi?

This is one of those topics that I've gotten asked about frequently enough that I decided it's time to write a short article on how to do it. It's funny that something as basic as this is not as visible as might be expected. It falls into a category that I call, "You gotta know what you're looking for..." Essentially, it means that the technique may not be hard to implement, it's just hard to find. In any case, once you know how to do it, it's not that difficult at all.

There are actually a number of ways to copy files. One way is to use untyped files along with BlockRead and BlockWrite. This also entails the use of an intermediary buffer. It works, but it can be a bit unwieldy, especially for novices. An easier way to accomplish file copying in Delphi is to use streams. As the term implies, a stream is sequential stream of data. When copying a file, you stream the file into a buffer, then stream buffer out to another file. Pretty simple in concept. Now in Delphi there are several types of streams which descend from the abstract base class TStream. I encourage you to look them up in the online help since they are beyond the scope of this discussion. But for our purposes, the descendant class that we're interested in is called TFileStream. This class allows applications to read from and write to files on disk. For simplicity's sake, I won't be going into the various intricacies of the class; again, encouraging you to study the online help. Or better yet, Ray Lischner's Book Secrets of Delphi 2 has a great discussion about streams as well (don't worry, the material applies to Delphi 3).

Quick and Dirty File Copying

The easiest method of copying a file with streams is called stream to stream copying. Essentially, this method involves creating a stream for the source file, and creating one for the destination file. Once that's done, it's a simple matter of copying the contents of the source stream to the destination stream. Listing 1 below shows a procedure that encapsulates stream to stream copying:

{Quick and dirty stream copy}
procedure FileCopy(const FSrc, FDst: string);
  dStream: TFileStream;
  sStream := TFileStream.Create(FSrc, fmOpenRead);
    dStream := TFileStream.Create(FDst, fmCreate);
      {Forget about block reads and writes, just copy
       the whole darn thing.}
      dStream.CopyFrom(sStream, 0);

Undoubtedly, you can get a lot more sophisticated with this. But for now, we'll leave it at this...