Pages

SyntaxHighlighter

Saturday, April 7, 2018

Copy/Delete/Move files - without XCMD

The ability to copy, delete or move an external file is frequently a requirement of an application. These actions are often performed using an X command, FILENAME, CALL SYSTEM, %SYSEXEC or other tasks that try to execute a shell-level command. Because all of the previously mentioned commands are contingent on the setting of XCMD, which is often set to NOXCMD, they are subject to failure.

One way to get around the XCMD limitation is to use low-level SAS functions found in the SAS Component Language or SCL that are also part of Base SAS language. Those functions include FILENAME(), FEXIST() and FDELETE(). The new SAS 9.4 FCOPY() function is also utilized. Using SAS functions instead of operating system specific calls makes the code independent of settings and portable.

All three of the below macro functions will return a value indicating success (1) or failure (0). The ability to evaluate the return value make these macros more flexible. In the case of the %COPYFILE macro, conditions such as the input and output filenames must exist or the function is not performed. Similarly, the %DELETEFILE macro also requires a valid filename exist. Finally, the %MOVEFILE macro leverages both of the prior macros and requires that the %COPYFILE macro complete successfully or else the subsequent %DELETEFILE action will not take place.

Because of the inherit return value, macro functions need to be called from inside an %IF or using a %LET rc = statement. Here are some examples to help illustrate, followed by the full source code:

  • %if %copyfile(infile=/folder/inf.txt, outfile=/folder/outf.txt) %then %do ;
  • %let rc = %copyfile(infile=/folder/inf.txt, outfile=/folder/outf.txt) ;
/**************************************************************************
*     Program: copyfile.sas
*      Author: Tom Bellmer
*     Purpose: macro to copy a single file from source to destination 
**************************************************************************/
%macro copyfile( 
     infile  =
   , outfile = 
) ;

   %local
      rc
      retval
      _bcin
      _bcout
   ;

   %let retval = 0 ;

         %if not %sysfunc( fileexist( &infile. ) ) %then 
            %put %str(E)RROR: Infile = &infile. does not exist. ;
   %else %if %isblank( &outfile. ) %then 
            %put %str(E)RROR: must supply an outfile= value. ;
   %else %do ;

      /* create a fileref of the file using recfm=n or binary format */
      %let rc = %sysfunc( filename( _bcin, &infile., , recfm = n ) ) ;
      %if &rc. = 0 and %sysfunc( fexist( &_bcin. ) ) %then %do ;

         %let rc = %sysfunc( filename( _bcout, &outfile., , recfm = n ) ) ;
         /* copy the file using FCOPY() */
         %if &rc. = 0 %then %let rc = %sysfunc( fcopy( &_bcin., &_bcout. ) ) ;

         %if &rc = 0 %then %do ;
            %put %str(N)OTE: Copied file: &infile. to &outfile. ;
            /* set retval = 1 to a success value from the function */
            %let retval = 1 ;
         %end ;

         %else %put %sysfunc( sysmsg() ) ;
         /* deassign the file references */
         %let rc = %sysfunc( filename( _bcin ) ) ;
         %let rc = %sysfunc( filename( _bcout ) ) ;

      %end ;

   %end ;
  
   /* return the status of the process where 1 = success */
   &retval.
%mend ;

/*EOF: copyfile.sas */
/**************************************************************************
*     Program: deletefile.sas
*      Author: Tom Bellmer
*     Purpose: macro function to delete a single file
**************************************************************************/
%macro deletefile( filename ) ;
   %local 
      retval 
      rc
      fref
   ;

   %let retval = 0 ;

   %if not %sysfunc( fileexist( &filename. ) ) %then 
      %put %str(E)RROR: &filename. does not exist. ;
   %else %do ;
      /* get a fileref */
      %let rc = %sysfunc( filename( fref, &filename. ) ) ;

      %if &rc. = 0 and %sysfunc( fexist( &fref. ) ) %then %do ;
         /* delete the file */
         %if %sysfunc( fdelete( &fref. ) ) = 0 %then %do ;
            %put %str(N)OTE: Deleted file: &filename.. ;
            %let retval = 1 ;
         %end ;
      %end ;

      /* release the filefref */
      %let rc = %sysfunc( filename( fref ) ) ;
   %end ;

   &retval.
%mend ;

/*EOF: deletefile.sas */
/**************************************************************************
*     Program: movefile.sas
*      Author: Tom Bellmer
*     Created: 20180315
**************************************************************************/
%macro movefile( 
     infile  =
   , outfile = 
) ;

   %local 
      retval 
      rc
      fref
   ;

   %let retval = 0 ;

         %if not %sysfunc( fileexist( &infile. ) ) %then 
            %put %str(E)RROR: Infile = &infile. does not exist. ;
   %else %if %isblank( &outfile. ) %then 
            %put %str(E)RROR: must supply an outfile= value. ;
   %else %do ;

      /* copy then delete the input file */
      %if %copyfile( infile = &infile., outfile = &outfile. ) %then %do ;
         /* delete file only if a successful copy */
         %let retval = %deletefile( &infile. ) ;
      %end ;

   %end ;

   &retval.
%mend ;

/*EOF: movefile.sas */

No comments:

Post a Comment