Copy a file using a SAS program: another method

A couple of years ago I shared a method for copying any file within a SAS program. It was a simple approach, copying the file byte-by-byte from one fileref (SAS file reference) to another.

My colleague Bruno Müller, a SAS trainer in Switzerland, has since provided a much more robust method. Bruno's method has several advantages:

It's coded as a SAS macro, so it is simple to reuse -- similar to a function.

It copies the file content in chunks rather than byte-by-byte, so it's more efficient.

It provides good error checks and reports any errors and useful diagnostics to the SAS log.

It's an excellent example of a well-documented SAS program!

Bruno tells me that "copying files" within a SAS program -- especially from nontraditional file systems such as Web sites -- is a common need among his SAS students. I asked Bruno for his permission to share his solution here, and he agreed.

To use the macro, you simply define two filerefs: _bcin (source) and _bcout (target), then call the %binaryFileCopy() macro. Here is an example use that copies a file from my Dropbox account:

filename _bcin TEMP;
filename _bcout "C:\temp\streaming.sas7bdat";
proc http method="get"
url="https://dl.dropbox.com/s/pgo6ryv8tfjodiv/streaming.sas7bdat"
out=_bcin
;
run;

%binaryFileCopy()
%put NOTE: _bcrc=&_bcrc;

filename _bcin clear;
filename _bcout clear;

The following is partial log output from the program:

NOTE: BINARYFILECOPY start 17SEP2013:20:50:33
NOTE: BINARYFILECOPY infile=_bcin C:\SASTempFiles\_TD5888\#LN00066
NOTE: BINARYFILECOPY outfile=_bcout C:\temp\streaming.sas7bdat

NOTE: BINARYFILECOPY processed 525312 bytes
NOTE: DATA statement used (Total process time):
real time 0.20 seconds
cpu time 0.07 seconds

NOTE: BINARYFILECOPY end 17SEP2013:20:50:34
NOTE: BINARYFILECOPY processtime 00:00:00.344

You can download the program -- which should work with SAS 9.2 and later -- from here: binaryfilecopy.sas

Update: using FCOPY in SAS 9.4

Updated: 18Sep2013
Within hours of my posting here, Vince DelGobbo reminded me about the new FCOPY function SAS 9.4. With two filerefs assigned to binary-formatted files, you can use FCOPY to copy the content from one to the other. When I first tried it with my examples, I had problems because of the way FCOPY treats logical record lengths. However, Jason Secosky (the developer for FCOPY and tons of other SAS functions) told me that if I use RECFM=N on each FILENAME statement, the LRECL would not be a problem. And of course, he was correct.

Here's my example revisited:

filename _bcin TEMP recfm=n /* RECFM=N needed for a binary copy */;
filename _bcout "C:\temp\streaming.sas7bdat" recfm=n;

proc http method="get"
url="https://dl.dropbox.com/s/pgo6ryv8tfjodiv/streaming.sas7bdat"
out=_bcin
;
run;

data _null_;
length msg $ 384;
rc=fcopy('_bcin', '_bcout');
if rc=0 then
put 'Copied _bcin to _bcout.';
else do;
msg=sysmsg();
put rc= msg=;
end;
run;

filename _bcin clear;
filename _bcout clear;