Using IBM i? Need to create Excel, CSV, HTML, JSON, PDF, SPOOL reports? Learn more about the fastest and least expensive tool for the job: SQL iQuery.
For several years I've been using the QSH (QShell) JAR (Java Archive) tool on IBM i to zip up IFS file and system objects. Anything from an HTML webpage on the IFS to a *SAVF in QGPL has been stuffed into a ZIP file.
In early 2012, IBM ported the ZLIB ZIP utilities to IBM i in the form of the QZIPUTIL *SRVPGM. The two exported subprocedure APIs are QzipZip and QzipUnzip. The names are case-sensitive.
While these APIs are highly limited compared to other operating system implementations, they do provide a primative ZIP capability for both IFS files and regular objects.
Rather that go over the API parameters, I've built a CL wrapper that runs the QzipZIP tool. I will produce one for Unzip shortly and update this article. Be sure to FOLLOW this article to be notified of updates.
Below is the CTZIP (Cozzi Tools ZIP Utility) command source. It allows you to create a ZIP file that contains a sysetm object (such as a program, file, user space, just about anything) or a file or folder on the IFS. The nature of these APIs is such that you may only add one item at a time to the ZIP file. To add multiple items, you need to run the command once for eah item you wish you add. Note: All Zip files are created on the IFS.
There are couple of parameters that I should highlight.
VERBOSE: This parameter is used when you want the API to report progress message to the joblog. The API itself calls for a *VERBOSE or *NONE option, but I simplified it on the command, to VERBOSE( *YES or *NO ).
SUBDIR: This parameter is when an IFS folder is being zipped up. If you want the subdirectories and their contents to be included in the resulting ZIP file, then specify SUBDIR(*YES). Again, the API uses an usual set of options *ALL and *NONE, which I've simplified via the command to SUBDIR(*YES or *NO).
Unfortunately, IBM is now outsourcing its IBM i development to all over the world. While the developers do seem to be very talented, I have noticed that the 35 years of IBM i knowledge from Rochester, MN USA is NOT being well transferred to this new generation of developers. Lots of omissions and implementation errors are appearing in almost everything new feature coming onto this system. QZIPUTIL is no exception.
In order to compile an RPG program that leverages the APIs in this service program, it must first be added to either a user-supplised Binding Directory or to the IBM system API binding directory. It should have been included in the IBM System API binding directory but it is not. So as a one-time thing, run the following CL command, so that you can compile programs that call QzipZip and QzipUnzip APIs:
ADDBNDDIRE BNDDIR(QUSAPIBD) OBJ((QZIPUTIL))
Hopefully IBM will see this article and add it in a tech refresh or CUMPTF package.
Once compiled, type in CTZIP and press F4 to prompt it. If you want to ZIP up something from the IFS, specify OBJ(*STMF) and the STMF parameter shall appear in the prompter (when you press Enter). Otherwise, type in the name of an IBM i object.
CTZIP can archive any IFS file or IBM i user objects such as Files, User Spaces, Save Files (a form of *FILE) and maybe a few others--nothing is documented so it is trial-and-error for this API.
CTZIP OBJ(COZTOOLSRT) OBJTYPE(*SAVF)
Then look in your HOME directory on the IFS for the zip file you just created. To add to it, just run the command again with another object. If you have trouble, specify VERBOSE(*YES) when running it to see if it gives you any feedback.
Cut/paste the folloiwng code into a source member named CTZIP. The name CTZIP means "COZZI TOOLS Zip Utility"
CTZIP: CMD PROMPT('COZZI - ZIP Utility') PARM KWD(OBJ) TYPE(QUAL1) SNGVAL((*STMF)) MIN(1) + PROMPT('Object to add to ZIP file') QUAL1: QUAL TYPE(*NAME) LEN(10) EXPR(*YES) QUAL TYPE(*NAME) LEN(10) DFT(*CURLIB) + SPCVAL((*CURLIB)) EXPR(*YES) + PROMPT('Object library') PARM KWD(OBJTYPE) TYPE(*CHAR) LEN(10) DFT(*FILE) + SPCVAL((*FILE) (*SAVF *FILE) (*USRSPC)) + PROMPT('Object type') STMF: PARM KWD(STMF) TYPE(*PNAME) LEN(640) DFT(*NONE) + SPCVAL((*NONE '')) MIN(0) EXPR(*YES) + VARY(*YES) PMTCTL(USESTMF) PROMPT('IFS File') PARM KWD(SUBDIR) TYPE(*CHAR) RSTD(*YES) DFT(*YES) + SPCVAL((*YES *ALL) (*NO *NONE)) + EXPR(*YES) PROMPT('Include subdirectories') PARM KWD(ZIPLOC) TYPE(*PNAME) LEN(5000) DFT(*HOME) + SPCVAL((*HOME)) EXPR(*YES) VARY(*YES) + INLPMTLEN(32) PROMPT('Zip file location') PARM KWD(ZIP) TYPE(*PNAME) LEN(5000) DFT(*OBJ) + SPCVAL((*OBJ) (*OBJLIB)) EXPR(*YES) + VARY(*YES) INLPMTLEN(32) PROMPT('Zip file + name') PARM KWD(VERBOSE) TYPE(*CHAR) RSTD(*YES) DFT(*NO) + SPCVAL((*YES *VERBOSE) (*NO *NONE)) + EXPR(*YES) PROMPT('Verbose messages') PARM KWD(COMMENTS) TYPE(*CHAR) LEN(512) + DFT(*NONE) SPCVAL((*NONE '')) EXPR(*YES) + VARY(*YES) PROMPT('Embedded Comments') USESTMF: PMTCTL CTL(OBJ) COND((*EQ *STMF) (*EQ *NONE)) + NBRTRUE(*GE 1)
I managed to avoid using any of my improved COZZI TOOLS /COPY members to build this utility. So it is a stand-alone module. Just compile it and it'll work. If you do NOT have the proper PTFs on your IBM i V7R1 build, then you won't have QZIPUTIL in QSYSINC and this program will not compile. Assuming you ran the ADDBNDDIRE command above, then it should compile just fine.
Cut/paste the following RPG IV code into a source member on your system and compile it.
H DFTACTGRP(*NO) ACTGRP(*NEW) OPTION(*NODEBUGIO:*SRCSTMT) /copy qsysinc/qrpglesrc,qziputil /copy qsysinc/qrpglesrc,qusrobjd /copy qsysinc/qrpglesrc,qusec D PSDS SDS Qualified D runlib 10A overlay(PSDS:081) D JobName 10A Overlay(PSDS:244) D usrprf 10A Overlay(PSDS:254) D JobNbr 6A Overlay(PSDS:264) D QusROBJD2 PR extPgm('QUSROBJD') D rtnData 65535A OPTIONS(*VARSIZE) D nRtnDataLen 10I 0 Const D Format 8A Const D QualObj 20A Const D ObjType 10A Const D api_error LikeDS(QUSEC) D OPTIONS(*VARSIZE:*NOPASS) D qualObj_T DS Qualified D name 10A D lib 10A D qualObjType_T DS Qualified D name 10A D lib 10A D type 10A D entryPList PR extPgm('CTZIP') D obj Const LikeDS(qualObj_T) D objtype 10A Const D ifsFile 5000A Const Varying D subdir 10A Const D zipDir 5000A Const Varying D zipFile 5000A Const Varying D verbose 10A Const D comments 512A Const Varying D zipPath DS LikeDS(qlg_Path_Name_T) Inz D objPath DS LikeDS(qlg_Path_Name_T) Inz D ifsPath S 5000A Varying D suffix S 4A D objDesc DS LikeDS(QUSD0100) Inz D zipOptions DS LikeDS( QZIP_zip_options_ZIP00100_T ) D Inz D apiError DS LikeDS(QUSEC) Inz(*LIKEDS) D object DS LikeDS(qualObjType_T) D entryPList PI D obj Const LikeDS(qualObj_T) D objtype 10A Const D ifsFile 5000A Const Varying D subdir 10A Const D zipDir 5000A Const Varying D zipFile 5000A Const Varying D verbose 10A Const D comments 512A Const Varying C MOVE *ON *INLR /free if (zipDir = '*HOME'); ifsPath = '/home/' + %trimR(psds.usrprf); else; ifsPath = %TrimR(zipDir); endif; if (zipFile = '*OBJ'); ifsPath += '/' + %trimR(obj.name) + '.ZIP'; elseif (zipFile = '*OBJLIB'); ifsPath += '/' + %trimR(obj.Lib) + '/' + %trimR(obj.Name) + '.ZIP'; else; ifsPath += '/' + %trimR(zipFile); endif; EVALR suffix = %TrimR(ifsPath); if (suffix <> '.ZIP' and suffix <> '.zip'); ifsPath += '.ZIP'; endif; zipPath.CCSID = 0; zipPath.Country_ID = *ALLX'00'; zipPath.Language_ID = *ALLX'00'; zipPath.reserved = *ALLX'00'; zipPath.reserved2 = *ALLX'00'; zipPath.path_Type = 0; zipPath.path_Name_Delimiter = '/'; zipPath.path_Length = %len(ifsPath); zipPath.path_Name = ifsPath; apiError = *ALLX'00'; if ((obj.name = '*STMF') or (obj.name = '*NONE') or (obj.name = '')); ifsPath = %trimR(ifsFile); else; QusROBJD2(objDesc : %size(objDesc) :'OBJD0100': obj : objType : apiError ); if (objDesc.qusbrtn06 > 0); // Got something? object.name = objDesc.qusobjn00; object.lib = objDesc.qusrl01; object.type = %subst(objDesc.QUSOBJT00 : 2); endif; ifsPath = '/qsys.lib/' + %trimR(object.lib) + '.lib' + '/' + %trimR(object.name) + '.' + %trimR(object.Type); endif; objPath.CCSID = 0; objPath.Country_ID = *ALLX'00'; objPath.Language_ID = *ALLX'00'; objPath.reserved = *ALLX'00'; objPath.reserved2 = *ALLX'00'; objPath.path_Type = 0; objPath.path_Name_Delimiter = '/'; objPath.path_Length = %len(ifsPath); objPath.path_Name = ifsPath; zipOptions.verbose_Option = verbose; zipOptions.subtree_Option = subdir; if (%Len(comments) > 0 and comments <> ''); zipOptions.comment = comments; zipOptions.comment_Length = %len(comments); endif; apiError = *ALLX'00'; qzipzip( objPath : zipPath : 'ZIP00100' : zipOptions : apiError ); return; /end-free