- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Has SAS developed a method in the meantime to zip files from the SAS server with encryption ? (password).
I'm not looking for methods such as intalling winzip command line on the SAS server. I mean a home grown SAS method.
Thanks !
Rgds
B
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
There may well be a way; hopefully someone will comment if so.
However, if you launch a WinZip (or whatever Zip tool is on your system) using SYSTASK, you can do it completely from within SAS, no exiting and manually using the command line.
Jim
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Code:
data _null_;
call symput('date',(put(date(),yymmddn8.)));
run;
/* ods begin */
ods package(ProdOutput) open nopf;
ods package(ProdOutput)
add file= "&directory\DONKEY_XX_Conc_HHHH_%sysfunc(today(),YYMMDDN8.).csv";
ods package(ProdOutput)
publish archive
properties
(archive_name= "DONKEY_XX_%trim(&date.).zip"
archive_path="&directory");
ods package(ProdOutput) close;
/* ods end */
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
@kirankp, I wrote a macro to do the zipping for me. We have WinZip.exe on our server. You might have different software on your server. I'll put the macro down below. The macro calls some other macros, but don't get too worried about that. Look at what the macro is doing in terms of the actual zipping, and perhaps you can use this as something of a template.
Jim
/*-------------------------------------------------------------------------------*/
/* Macro: Archive_Data
/* Author: Jim Barbour
/* Date: 26 February 2020
/* Info: This macro calls WinZip to create a Zip archive of whatever file is
/* passed in as an arugument to the macro call. Input parameters are
/* first. Output parameters (pertaining to the zip file) are second.
/*
/* If you are archiving a SAS data set and that SAS data set has an
/* index, you must archive both the SAS data set and the corresponding
/* index data set or SAS will consider the data corrupted.
/*
/* Filename Pre_Zip will verify the existence of a file prior to running
/* the Zip commands.
/*-------------------------------------------------------------------------------*/
/* CHANGE LOG
/*-------------------------------------------------------------------------------*/
/* Name: Jim Barbour Date: 26 February 2020
/* Info: Original implementation.
/*-------------------------------------------------------------------------------*/
&Null %MACRO Archive_Data(File_Path, File_Name, Zip_Path, Zip_Name,
ZipPgmPath=, Width=115, Xmin=XMIN, Xwait=XWAIT,
Run_Mode=PROD, Debug=NO, Trace=NO);
%LOCAL Zip_File;
%LOCAL Full_File;
%LOCAL ZipPgmPath;
%LOCAL Cmnt;
%LOCAL MacroName;
%LOCAL Save_Xwait;
OPTION &Xmin;
%LET MacroName = &SysMacroName;
%Start_Mac(&MacroName, Trace=&Trace)
%IF %QUPCASE(&Debug) = YES %THEN
%DO;
%LET Cmnt = ;
%PUT &Nte1 Debug is on in macro &Sysmacroname;
%END;
%ELSE
%DO;
%LET Cmnt = *;
%END;
%&Cmnt.PUT &Nte2 Initial Xwait option is %SYSFUNC(GETOPTION(XWAIT));
%LET Save_Xwait = %SYSFUNC(GETOPTION(XWAIT));
%&Cmnt.PUT &Nte2 Saved Xwait option is &Save_Xwait;
OPTION &Xwait;
%&Cmnt.PUT &Nte2 Current Xwait option is %SYSFUNC(GETOPTION(XWAIT));
%IF %SYMEXIST(Data_Path) AND
%BQUOTE(&File_Path) = %STR() %THEN
%DO;
%&Cmnt.PUT &Nte2 Setting File_Path to Global variable Data_Path which is equal to &Data_Path;
%LET File_Path = &Data_Path;
%END;
%ELSE
%DO;
%&Cmnt.PUT &Nte2 File_Path was supplied as &File_Path;
%END;
%IF %SYMEXIST(Arch_Path) AND
%BQUOTE(&Zip_Path) = %STR() %THEN
%DO;
%&Cmnt.PUT &Nte2 Setting Zip_Path to Global variable Arch_Path which is equal to &Arch_Path;
%LET Zip_Path = &Arch_Path;
%END;
%ELSE
%DO;
%&Cmnt.PUT &Nte2 Zip_Path was supplied as &Zip_Path;
%END;
%IF %BQUOTE(&ZipPgmPath) = %STR() %THEN
%DO;
%LET ZipPgmPath = E:\%STR("")Program Files%STR("")\WinZip\wzzip.exe;
%&Cmnt.PUT &Nte2 Setting ZipPgmPath to default value of &ZipPgmPath;
%END;
%ELSE
%DO;
%&Cmnt.PUT &Nte2 ZipPgmPath was supplied as |&ZipPgmPath|;
%END;
%IF %BQUOTE(%SYSFUNC(LENGTHN(&File_Path))) > 0 AND
%BQUOTE(%SYSFUNC(SUBSTR(&File_Path, %SYSFUNC(LENGTH(&File_Path)), 1))) ^= %STR(\) %THEN
%DO;
%&Cmnt.PUT &Nte2 Length of &File_Path = %BQUOTE(%SYSFUNC(LENGTHN(&File_Path)));
%&Cmnt.PUT &Nte2 Last char &File_Path = %BQUOTE(%SYSFUNC(SUBSTR(&File_Path, %SYSFUNC(LENGTH(&File_Path)), 1)));
%LET File_Path = &File_Path%STR(\);
%&Cmnt.PUT &Nte2 Added a back slash to File_Path: &File_Path;
%END;
%ELSE
%DO;
%&Cmnt.PUT &Nte2 Length of &File_Path = %BQUOTE(%SYSFUNC(LENGTHN(&File_Path)));
%&Cmnt.PUT &Nte2 Last char &File_Path = %BQUOTE(%SYSFUNC(SUBSTR(&File_Path, %SYSFUNC(LENGTH(&File_Path)), 1)));
%&Cmnt.PUT &Nte2 Did NOT add a new back slash to File_Path: &File_Path;
%END;
%IF %BQUOTE(%SYSFUNC(LENGTHN(&Zip_Path))) > 0 AND
%BQUOTE(%SYSFUNC(SUBSTR(&Zip_Path, %SYSFUNC(LENGTH(&Zip_Path)), 1))) ^= %STR(\) %THEN
%DO;
%&Cmnt.PUT &Nte2 Length of &Zip_Path = %BQUOTE(%SYSFUNC(LENGTHN(&Zip_Path)));
%&Cmnt.PUT &Nte2 Last char &Zip_Path = %BQUOTE(%SYSFUNC(SUBSTR(&Zip_Path, %SYSFUNC(LENGTH(&Zip_Path)), 1)));
%LET Zip_Path = &Zip_Path%STR(\);
%&Cmnt.PUT &Nte2 Added a back slash to Zip_Path: &Zip_Path;
%END;
%ELSE
%DO;
%&Cmnt.PUT &Nte2 Length of &Zip_Path = %BQUOTE(%SYSFUNC(LENGTHN(&Zip_Path)));
%&Cmnt.PUT &Nte2 Last char &Zip_Path = %BQUOTE(%SYSFUNC(SUBSTR(&Zip_Path, %SYSFUNC(LENGTH(&Zip_Path)), 1)));
%&Cmnt.PUT &Nte2 Did NOT add a new back slash to Zip_Path: &Zip_Path;
%END;
%LET Full_File = %SYSFUNC(CATS(&File_Path., &File_Name.));
%LET Zip_File = %SYSFUNC(CATS(&Zip_Path., &Zip_Name., .zip));
%&Cmnt.PUT &Nte2 &=Full_file;
%&Cmnt.PUT &Nte2 &=Zip_file;
FILENAME Pre_Zip "&Full_File";
DATA _NULL_;
LENGTH _RC 4.;
LENGTH _Line $255;
INFILE Pre_Zip;
_RC = INPUT(SYMGET('SYSCC'), 4.);;
IF 0 < _RC < 8 THEN
DO;
PUTLOG "&Err2 %Format_Dashes(&Width)";
_Line = RESOLVE(CAT('&Err1 %Format_Line(Pre-Zip failed check failed for &File_Name.. SYSCC = ', STRIP(PUT(_RC, 4.)), '., &Width)'));
PUTLOG _Line;
PUTLOG "&Err2 %Format_Dashes(&Width)";
PUTLOG "&Err2 ";
CALL SYMPUTX('SYSCC', 8, 'G');
END;
ELSE
DO;
&Cmnt PUTLOG "&Nte2 Pre-Zip file check successful";
END;
RUN;
%&Cmnt.List_RC(Dashes=YES);
%IF &SYSCC = 0 %THEN
%DO;
%&Cmnt.PUT &Nte2 SYSCC is 0. Starting Zip Archive creation process;
%cd(&Zip_Path);
%**-----------------------------------------------------------------------------**;
%** ORIGINAL VERSION **;
%** The following file name works but only with files less than about 14 Gb. **;
%** For some reason, larger files "hang" and neither succeed nor fail. **;
%** Workaround #1 is to write to an intermediate STDOUT text file. **;
%**-----------------------------------------------------------------------------**;
%*FILENAME WinOpSys PIPE "&ZipPgmPath. -a ""&Zip_File."" ""&Full_File.""";
%**-----------------------------------------------------------------------------**;
%** WORKAROUND #1 **;
%** The following file name is for Workaround #1. The original file name is **;
%** split into 1) an independent (no PIPE) "X" command that writes to an **;
%** intermediate STDOUT text file and 2) a Filename that reads that STDOUT. **;
%**-----------------------------------------------------------------------------**;
%*X "del WinZip_STDOUT_Temp.txt & &ZipPgmPath. -a ""&Zip_File."" ""&Full_File."" > WinZip_STDOUT_Temp.txt";
%*FILENAME WinOpSys "WinZip_STDOUT_Temp.txt";
%**-----------------------------------------------------------------------------**;
%** WORKAROUND #2 **;
%** The following file name is for Workaround #2. STDOUT is piped directly **;
%** into the DATA step but STDERR ("2") is redirected to a STDERR text file. **;
%** Apparently, when both STDOUT and STDERR are piped directly into the DATA **;
%** step, some buffer gets full, and the entire process freezes. The downside **;
%** of redirecting STDERR to an external text file is that STDERR is then no **;
%** longer available inside the DATA step. If there is a problem, the external **;
%** text file must be examined manually or in a subsequent DATA step. **;
%**-----------------------------------------------------------------------------**;
FILENAME WinOpSys PIPE "&ZipPgmPath. -a ""&Zip_File."" ""&Full_File."" 2> WinZip_STDERR_Temp.txt";
DATA _NULL_;
LENGTH _Curr_DateTime $23;
LENGTH _Line $255;
LENGTH _RC 4.;
LENGTH _First_Time 3.;
LENGTH _Total_Bytes 3.;
RETAIN _First_Time 1;
RETAIN _Total_Bytes 0;
**------------------------------------------------------------------------------**;
** The "Start Zip at" log message is inaccurate when an intermediate text file **;
** is used and, in such a case (Workaround #1), should be commented out. **;
** For Workaround #2, the "Start Zip at" works fine and may be uncommented. **;
**------------------------------------------------------------------------------**;
IF _First_Time THEN
DO;
_First_Time = 0;
PUTLOG "&Nte2 %Format_Dashes(&Width)";
_Curr_DateTime = TRANWRD(PUT(DATETIME(), E8601DT23.2), 'T', ' ');
_Line = RESOLVE(CAT('&Nte1 %Format_Line(Start Zip at ', STRIP(_Curr_DateTime), '., &Width)'));
PUTLOG _Line;
END;
**------------------------------------------------------------------------------**;
** As with a FILENAME with a PIPE, the following "filenameless" INFILE works **;
** but only with files less than about 14 Gb. Using an intermediate text **;
** file is the Workaround #1 for this odd bug. Workaround #2 is to redirect **;
** STDERR to an external text file. See examples, above. **;
**------------------------------------------------------------------------------**;
* INFILE "&ZipPgmPath. -a ""&Zip_File."" ""&Full_File.""" PIPE
* TRUNCOVER
* END = _Zip_Process_Complete
* LENGTH = _SAS_Length
* ;
INFILE WinOpSys TRUNCOVER
END = _Zip_Process_Complete
LENGTH = _SAS_Length
;
INPUT _WinZip_Msg $VARYING32766. _SAS_Length;
_Line = RESOLVE(CAT('&Nte2 %Format_Line(%STR(', STRIP(_WinZip_Msg), '), &Width)'));
PUTLOG _Line;
IF INDEX(_WinZip_Msg, 'Total bytes=') THEN
DO;
&Cmnt PUTLOG "&Nte2 | 'Total bytes=' has been found";
_Total_Bytes = 1;
END;
IF _Zip_Process_Complete THEN
DO;
IF NOT _Total_Bytes THEN
DO;
PUTLOG "&Warn2 %Format_Dashes(&Width)";
_Line = RESOLVE(CAT('&Warn1 %Format_Line(&sQuote.Total bytes=&sQuote. not returned by WinZip, &Width)'));
PUTLOG _Line;
_Line = RESOLVE(CAT('&Warn2 %Format_Line(Results are suspect. Check zip archive., &Width)'));
PUTLOG _Line;
PUTLOG "&Warn2 %Format_Dashes(&Width)";
_RC = INPUT(SYMGET('SysRC'), 4.);
IF _RC < 4 THEN
DO;
&Cmnt PUTLOG "&Nte2 Setting SYSCC and SYSRC to 4";
CALL SYMPUTX('SYSCC', '4', 'G');
CALL SYMPUTX('SYSRC', '4', 'G');
END;
END;
_Curr_DateTime = TRANWRD(PUT(DATETIME(), E8601DT23.2), 'T', ' ');
_Line = RESOLVE(CAT('&Nte2 %Format_Line(End Zip at ', STRIP(_Curr_DateTime), '., &Width)'));
PUTLOG _Line;
_RC = INPUT(SYMGET('SysRC'), 4.);
IF _RC = 0 THEN
DO;
PUTLOG "&Nte2 %Format_Line(Return code from zipping &File_Name = 0., &Width)";
PUTLOG "&Nte2 %Format_Dashes(&Width)";
PUTLOG "&Nte2 ";
END;
ELSE
DO;
PUTLOG "&Err2 %Format_Dashes(&Width)";
_Line = RESOLVE(CAT('&Err1 %Format_Line(Return code from zipping &File_Name = ', STRIP(PUT(_RC, 4.)), '., &Width)'));
PUTLOG _Line;
PUTLOG "&Err2 %Format_Dashes(&Width)";
PUTLOG "&Err2 ";
END;
END;
RUN;
%END;
%ELSE
%DO;
%PUT &Warn2 ;
%PUT &Warn2 %Format_Dashes(&Width);
%PUT &Warn1 %Format_Line(SYSCC%STR(=)&SYSCC after Pre-Zip file check. Skipping Zip archive creation., &Width);
%PUT &Warn2 %Format_Line(Make sure to run %NRSTR(%Reset_RC) or %NRSTR(%Reset_All) before re-running., &Width);
%PUT &Warn2 %Format_Dashes(&Width);
%END;
%IF %QUPCASE(&Run_Mode) = TEST %THEN
%DO;
%List_RC(Dashes=YES);
%PUT _LOCAL_;
%END;
OPTION &Save_Xwait;
%&Cmnt.PUT &Nte2 Final Xwait option is %SYSFUNC(GETOPTION(XWAIT));
%LET MacroName = &SysMacroName; %End_Mac(&MacroName, Trace=&Trace)
%MEND Archive_Data;
%**-----------------------------------------------------------------------------**;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
FILENAME ZIP does not provide a password option, so the answer is no.