How do I copy a file in Delphi?

How do I copy a file in Delphi?

Question:
How do I copy a file in Delphi?

Answer:
H3>Reminiscing on Days Gone By…

Back in the old DOS days, we took for granted copying a file from one place to another with the copy command. But with Windows, everything changed. We now use File Manager or Explorer to copy files from one place to another, which is a huge improvement over typing in the fully qualified path for both source and destination files.

But at the programming level, performing the copying of one file to another is not as apparent as one would think. In fact, there are no native Delphi calls for copying a file whatsoever. So what do you do if you want to copy a file? You have to write the routine yourself.

Interestingly enough, there is a pretty good example of copying a file that is in the FMXUTILS.PAS file in the DelphiDemosDocFilmanex directory that will perform a file copy using native Delphi file-related commands. While this method works just fine, I decided to go another route; that is, to use a file stream to copy a file from one place to another. Streams are interesting animals. They’re used internally in Delphi to read and write components, forms and data, and they’re pretty handy. Unfortunately, they aren’t well-documented so they can be a bit tricky to use. I went through a lot of trial and error to get them to work, and referenced several sources outside of the online help (which is just about the only place you’ll find anything on streams in Delphi) before I got a handle on streams. But once I figured them out, they became what I use for reading and writing files almost exclusively.

There’s Almost Always More
Than One Way of Doing Things…

Once you’ve programmed for a while, you realize that it’s possible to solve a particular problem in a variety of ways; which way is valid is dependent upon your knowledge and experience (one way may be more optimized than another) or, at times, even the situation will dictate that one methodology is better suited for a task than another.

For instance, with file copying, there are times you just want to copy a file in the background using a quick and dirty method, and you don’t care if the user knows what’s going on at all. But there are other times, such as when file utilities are part of an interface, when you want the user to be aware of the copying progress.

What I’m going to show you here are two ways to perform file copying: one quick and dirty; the other, a more snazzy, graphical way of copying a file, though it uses a few more resources and is a bit slower.

Quick and Dirty Copying

Traditionally, copying a file involves using a loop to move a series of blocks from one file into a temporary buffer, then copying the contents of the buffer into another file. Let’s look at the CopyFile function found in the FMXUTILS.PAS:

{============================================================================= CopyFile procedure found in the FMXUTILS.PAS file in DelphiDemosDocFilmanex This is an example of copying a file using a buffer. =============================================================================}procedure CopyFile(const FileName, DestName: TFileName);var  CopyBuffer: Pointer; { buffer for copying }  TimeStamp, BytesCopied: Longint;  Source, Dest: Integer; { handles }  Destination: TFileName; { holder for expanded destination name }const  ChunkSize: Longint = 8192; { copy in 8K chunks }begin  Destination := ExpandFileName(DestName); { expand the destination path }  if HasAttr(Destination, faDirectory) then { if destination is a directory… }    Destination := Destination + ” + ExtractFileName(FileName); { …clone file name }  TimeStamp := FileAge(FileName); { get source’s time stamp }  GetMem(CopyBuffer, ChunkSize); { allocate the buffer }  try    Source := FileOpen(FileName, fmShareDenyWrite); { open source file }    if Source < 0 then raise EFOpenError.Create(FmtLoadStr(SFOpenError, [FileName]));    try      Dest := FileCreate(Destination); { create output file; overwrite existing }      if Dest < 0 then raise EFCreateError.Create(FmtLoadStr(SFCreateError, [Destination]));      try        repeat          BytesCopied := FileRead(Source, CopyBuffer^, ChunkSize); { read chunk }          if BytesCopied > 0 then { if we read anything… }            FileWrite(Dest, CopyBuffer^, BytesCopied); { …write chunk }        until BytesCopied < ChunkSize; { until we run out of chunks }      finally        FileClose(Dest); { close the destination file }      end;    finally      FileClose(Source); { close the source file }    end;  finally    FreeMem(CopyBuffer, ChunkSize); { free the buffer }  end;end;

But Delphi implements a method of TStream called CopyFrom that allows you to copy the entire contents of one stream into another in one fell swoop. Here’s an implementation of copying a file using the CopyFrom method:

{============================================================= Quick and dirty copying using the CopyFrom method of TStream. =============================================================}procedure FileCopy(const FSrc, FDst: string);var  sStream,  dStream: TFileStream;begin  sStream := TFileStream.Create(FSrc, fmOpenRead);  try    dStream := TFileStream.Create(FDst, fmCreate);    try      {Forget about block reads and writes, just copy       the whole darn thing.}      dStream.CopyFrom(sStream, 0);    finally      dStream.Free;    end;  finally    sStream.Free;  end;end;

The declaration of the CopyFrom method is as follows:

function CopyFrom(Source: TStream; Count: LongInt) : LongInt;.

Source is the TStream you’re going to copy from, and Count is the number of bytes to copy from the stream. If Count is zero (0), the entire contents of the source stream is copied over. This makes for a quick one-liner copying.

Notice that in both the examples above, all the functionality is enclosed in nested try..finally blocks. This is extremely important because just in case something goes wrong, all resources and pointers that are created are freed. You don’t want to have stray pointers or unreleased memory in your system, so providing at least this level of exception handling is key to ensuring that you don’t.

A Sexier File Copy

If you write robust user interfaces, practically everything that you do involves interacting with the user by providing visual cues to let the user know what’s going on. File copying is one of those types of operations that when performed within the context of a user interface must provide some status as to the progress of the copy operation. Therefore, a quick and dirty copy like the one I just described above won’t do. What we need then is something with a bit more pizazz.

In order to get status, we need to copy the file in chunks. That way, as we copy each chunk from one file to another, we can let the user know how far we’ve proceeded. What this implies is that we need two pieces. The first is the unit that performs the copying; the other a status window used for notification. For me, the best way to get both pieces to work in concert was to build a custom component which encapsulates the file copy operation and uses another unit to perform the notification.

The notification unit is just a simple form with a TGauge and a TButton placed on it. The unit code is as follows:

unit copyprg;interfaceuses  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  StdCtrls, Gauges;type  TFileProg = class(TForm)    Gauge1: TGauge;    Button1: TButton;    procedure Button1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);  private    { Private declarations }    fCancel : Boolean;  public    property CancelIt : Boolean read fCancel;  end;var  FileProg: TFileProg;implementation{$R *.DFM}procedure TFileProg.Button1Click(Sender: TObject);begin  fCancel := True;end;procedure TFileProg.FormCreate(Sender: TObject);begin  fCancel := False;end;end.

Nothing odd here. I simply added a custom property to the form called CancelIt, which is a simple Boolean flag used to cancel the copying operation midstream should the user desire to do so. The real work happens in the custom component itself. Let’s look at its code, then discuss it:

unit FileCopy;interfaceuses  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;type  TFileCopy = class(TComponent)  private    FSource,    FDest     : String;    procedure DoCopyFile(const SrcFile, DstFile: string);  public    procedure CopyFile; virtual;  published    property FileSource       : String read FSource write FSource;    property FileDestination  : String read FDest write FDest;  end;procedure Register;implementationuses copyprg;procedure TFileCopy.CopyFile;begin  DoCopyFile(FileSource, FileDestination);end;procedure TFileCopy.DoCopyFile(const SrcFile, DstFile: string);const  bufSize = 16384; {Use a 16K buffer. You can use whatever size suits you, though.}var  sStream,  dStream : TFileStream;  pBuf    : Pointer;  cnt     : Integer;  prgFrm  : TFileProg;  totCnt,  X,   strmSize    : LongInt;begin  totCnt := 0;  {Open up the Source File to read it}  sStream := TFileStream.Create(SrcFile, fmOpenRead or fmShareDenyWrite);  {Create the copying progress form and set property values}  prgFrm := TFileProg.Create(Application);  with prgFrm.Gauge1 do begin    MinValue := 0;    MaxValue := 100;    Progress := 0;  end;  prgFrm.Show;  {Get the size of the entire stream to use for the progress gauge. Note   we have to call FileSeek first because it will place the pointer   at the end of the file when we get the file first return value.}  strmSize := sStream.size;  try    { Create the destination file. If it already exists,      overwrite it. }    dStream := TFileStream.Create(DstFile, fmCreate or fmShareExclusive);    try      GetMem(pBuf, bufSize);      try        {Read and write first bufSize bytes from source into the buffer         If the file size is smaller than the default buffer size, then         all the user will see is a quick flash of the progress form.}        cnt := sStream.Read(pBuf^, bufSize);        cnt := dStream.Write(pBuf^, cnt);        totCnt := totCnt + cnt;        {Loop the process of reading and writing}        while (cnt > 0) do begin          {Let things in the background proceed while loop is processing}          Application.ProcessMessages;          {Read bufSize bytes from source into the buffer}          cnt := sStream.Read(pBuf^, bufSize);          {Now write those bytes into destination}          cnt := dStream.Write(pBuf^, cnt);          {Increment totCnt for progress and do arithmetic to update the           gauge}          totcnt := totcnt + cnt;          if NOT prgFrm.CancelIt then            with prgFrm.Gauge1 do begin              Progress := Round((totCnt / strmSize) * 100);              Update;            end          else            Break;       {If user presses cancel button, then break out of loop}                         {which will make program go to finally blocks}        end;      finally        FreeMem(pBuf, bufSize);      end;    finally      dStream.Free;      if prgFrm.CancelIt then {If copying was cancelled, delete the destination file}        DeleteFile(DstFile);  {after stream has been freed, which will close the file.}    end;  finally    sStream.Free;    prgFrm.Close;  end;end;procedure Register;begin  {You can change the palette entry to something of your choice}  RegisterComponents(‘BD’, [TFileCopy]);end;end.

Like the CopyFile routine in FMXUTILS.PAS, the concept behind copying for this component is the same: Grab a chunk of the source file, then dump it into the destination file. Repeat this process until all possible data has been copied over. Notice that I used a TFileStream once again. But this time, I didn’t copy the entire file over in one fell swoop. That would’ve defeated the whole purpose of providing user status.

I’ve commented the code extensively, so I won’t go into real detail here. I’ll leave it up to you to study the code to learn about what’s going on in it.

Notice the method declaration for CopyFile is declared as a virtual method. I’ve done this on purpose so that this class can be used a template class for specialized copy operations. The CopyFile method is actually rather trivial at this level — all it does is call the DoCopyFile method and pass the FileSource and FileDestination property values.

However, it is the only public interface for actually performing the copying operation. This is an important point for all you component designers out there. Providing limited method visibility ensures that the core features of your components remain intact. Remember, you want other users of your component to see only what is absolutely necessary.

How is this useful? It allows you to have a bit of control over how the hierarchy develops. By hiding the basic functionality from descendant classes, you can ensure that the basic functionality of your class is retained throughout the inheritance tree. Granted, users can completely override the behavior of the CopyFile method, but that doesn’t mean that the original capability will be lost. It will still be there, just not implemented.

Obviously, the meat of the work is performed by the DoCopyFile method. Study the code to see what happens from point to point. Note that I used a Pointer for the buffer. You can use just about any type as a buffer, but a pointer makes sense because its a simple 4-byte value. If you are copying a text file and want to treat the pointer like a string, you can cast it as a PChar, so long as you append a #0 byte to the end of the buffer. Neat stuff, huh?

A Little Note About TFileStream

TFileStream is not a direct assignment of TStream. In fact, it’s a descendant of THandleStream which, when created, fills a property value called Handle which is the handle to an external file. TFileStream inherits the Handle property. The significance of this is really neat: File operations that take a handle as input can be applied to a TFileStream. That has interesting implications in that you can do file operations on a TFileStream object before you write it to another place. Try experimenting with this.

Okay, we’ve come a long way. And no, I haven’t delved into the depths of Stream classes. That’s probably best left to another article or series of articles. In any case, play around with the TCopyFile class. It could prove to be a useful addition to your applications.

devx-admin

devx-admin

Share the Post:
Chinese 5G Limitation

Germany Considers Limiting Chinese 5G Tech

A recent report has put forth the possibility that Germany’s Federal Ministry of the Interior and Community may consider limiting the use of Chinese 5G

Modern Warfare

The Barak Tank is Transforming Modern Warfare

The Barak tank is a groundbreaking addition to the Israeli Defense Forces’ arsenal, significantly enhancing their combat capabilities. This AI-powered military vehicle is expected to

AI Cheating Growth

AI Plagiarism Challenges Shake Academic Integrity

As generative AI technologies like ChatGPT become increasingly prevalent among students and raise concerns about widespread cheating, prominent universities have halted their use of AI

US Commitment

US Approves Sustainable Battery Research

The US Department of Energy has revealed a $325 million commitment in the research of innovative battery types, designed to enable solar and wind power

Netanyahu Musk AI

Netanyahu and Musk Discuss AI Future

On September 22, 2023, Israeli Prime Minister Benjamin Netanyahu met with entrepreneur Elon Musk in San Francisco prior to attending the United Nations. In a

Chinese 5G Limitation

Germany Considers Limiting Chinese 5G Tech

A recent report has put forth the possibility that Germany’s Federal Ministry of the Interior and Community may consider limiting the use of Chinese 5G technology by local network providers

Modern Warfare

The Barak Tank is Transforming Modern Warfare

The Barak tank is a groundbreaking addition to the Israeli Defense Forces’ arsenal, significantly enhancing their combat capabilities. This AI-powered military vehicle is expected to transform the way modern warfare

AI Cheating Growth

AI Plagiarism Challenges Shake Academic Integrity

As generative AI technologies like ChatGPT become increasingly prevalent among students and raise concerns about widespread cheating, prominent universities have halted their use of AI detection software, such as Turnitin’s

US Commitment

US Approves Sustainable Battery Research

The US Department of Energy has revealed a $325 million commitment in the research of innovative battery types, designed to enable solar and wind power as continuous, 24-hour energy sources.

Netanyahu Musk AI

Netanyahu and Musk Discuss AI Future

On September 22, 2023, Israeli Prime Minister Benjamin Netanyahu met with entrepreneur Elon Musk in San Francisco prior to attending the United Nations. In a live-streamed discussion, Netanyahu lauded Musk

Urban Gardening

Creating Thriving Cities Through Urban Gardening

The rising popularity of urban gardening is receiving increased recognition for its numerous advantages, as demonstrated in a recent study featured in the Environmental Research Letters journal. Carried out by

What You Need to Know About Cloud Security Strategies

What You Need to Know About Cloud Security Strategies

Today, many businesses are adopting cloud computing services. As a result, it’s important to recognize that security measures for data in the cloud are different from those in traditional on-premises

Romanian Energy Security

Eastern Europe is Achieving Energy Security

Canada and Romania have solidified their commitment to energy security and independence from Russian energy exports by signing a $3-billion export development agreement. The deal is centered on constructing two

Seamless Integration

Unlocking Seamless Smart Home Integration

The vision of an intelligently organized and interconnected smart home that conserves time, energy, and resources has long been desired by many homeowners. However, this aspiration has often been hindered

New Algorithm

MicroAlgo’s Groundbreaking Algorithm

MicroAlgo Inc. has revealed the creation of a knowledge-augmented backtracking search algorithm, developed through extensive research in evolutionary computational techniques. The algorithm is designed to boost problem-solving effectiveness, precision, and

Poland Energy Future

Westinghouse Builds Polish Power Plant

Westinghouse Electric Company and Bechtel have come together to establish a formal partnership in order to design and construct Poland’s inaugural nuclear power plant at the Lubiatowo-Kopalino site in Pomerania.

EV Labor Market

EV Industry Hurting For Skilled Labor

The United Auto Workers strike has highlighted the anticipated change towards a future dominated by electric vehicles (EVs), a shift which numerous people think will result in job losses. However,

Soaring EV Quotas

Soaring EV Quotas Spark Battle Against Time

Automakers are still expected to meet stringent electric vehicle (EV) sales quotas, despite the delayed ban on new petrol and diesel cars. Starting January 2023, more than one-fifth of automobiles

Affordable Electric Revolution

Tesla Rivals Make Bold Moves

Tesla, a name synonymous with EVs, has consistently been at the forefront of the automotive industry’s electric revolution. The products that Elon Musk has developed are at the forefront because

Sunsets' Technique

Inside the Climate Battle: Make Sunsets’ Technique

On February 12, 2023, Luke Iseman and Andrew Song from the solar geoengineering firm Make Sunsets showcased their technique for injecting sulfur dioxide (SO₂) into the stratosphere as a means

AI Adherence Prediction

AI Algorithm Predicts Treatment Adherence

Swoop, a prominent consumer health data company, has unveiled a cutting-edge algorithm capable of predicting adherence to treatment in people with Multiple Sclerosis (MS) and other health conditions. Utilizing artificial

Personalized UX

Here’s Why You Need to Use JavaScript and Cookies

In today’s increasingly digital world, websites often rely on JavaScript and cookies to provide users with a more seamless and personalized browsing experience. These key components allow websites to display

Geoengineering Methods

Scientists Dimming the Sun: It’s a Good Thing

Scientists at the University of Bern have been exploring geoengineering methods that could potentially slow down the melting of the West Antarctic ice sheet by reducing sunlight exposure. Among these

why startups succeed

The Top Reasons Why Startups Succeed

Everyone hears the stories. Apple was started in a garage. Musk slept in a rented office space while he was creating PayPal with his brother. Facebook was coded by a

Bold Evolution

Intel’s Bold Comeback

Intel, a leading figure in the semiconductor industry, has underperformed in the stock market over the past five years, with shares dropping by 4% as opposed to the 176% return

Semiconductor market

Semiconductor Slump: Rebound on the Horizon

In recent years, the semiconductor sector has faced a slump due to decreasing PC and smartphone sales, especially in 2022 and 2023. Nonetheless, as 2024 approaches, the industry seems to

Elevated Content Deals

Elevate Your Content Creation with Amazing Deals

The latest Tech Deals cater to creators of different levels and budgets, featuring a variety of computer accessories and tools designed specifically for content creation. Enhance your technological setup with

Learn Web Security

An Easy Way to Learn Web Security

The Web Security Academy has recently introduced new educational courses designed to offer a comprehensible and straightforward journey through the intricate realm of web security. These carefully designed learning courses