, 5 min read
Decompressing ZIP Files on Mainframe
Original post is here eklausmeier.goip.de/blog/2022/06-15-decompressing-zip-files-on-mainframe.
Unfortunately classical mainframe has no builtin decompressing software for ZIP files. What you could do: Transfer ZIP file to USS, decompress and unpack there, then copy back to MVS. To do it directly on MVS you need to purchase a separate utility to do this. One utility is FLAM, Frankenstein Limes Access Method. FLAM is a product of limes datentechnik.
Given a ZIP file which contains 10 files.
$ unzip -l fulwola.zip
Archive: fulwola.zip
Length Date Time Name
--------- ---------- ----- ----
709692 2022-06-08 22:09 20220609_WOLA_EXP_WOLA_ADRESSE_CZSWADTB.csv
179 2022-06-08 22:09 20220609_WOLA_EXP_WOLA_ADRESSE_CZSWADTB.info
674 2022-06-08 22:09 20220609_WOLA_EXP_WOLA_GESCHAEFTS_VM_CZSWGVTB.csv
177 2022-06-08 22:09 20220609_WOLA_EXP_WOLA_GESCHAEFTS_VM_CZSWGVTB.info
1754956 2022-06-08 22:09 20220609_WOLA_EXP_WOLA_PARTYINFOS_CZSWPTTB.csv
179 2022-06-08 22:09 20220609_WOLA_EXP_WOLA_PARTYINFOS_CZSWPTTB.info
1004 2022-06-08 22:09 20220609_WOLA_EXP_WOLA_PARTY_BEZ_CZSWPBTB.csv
177 2022-06-08 22:09 20220609_WOLA_EXP_WOLA_PARTY_BEZ_CZSWPBTB.info
15254 2022-06-08 22:09 20220609_WOLA_EXP_WOLA_VERFUEGUNGEN_CZSWVFTB.csv
178 2022-06-08 22:09 20220609_WOLA_EXP_WOLA_VERFUEGUNGEN_CZSWVFTB.info
--------- -------
2482470 10 files
They can be decompressed to below PO files on mainframe:
EH2KLRQ.ZIPWOLA.CZSWADTC
EH2KLRQ.ZIPWOLA.CZSWADTI
EH2KLRQ.ZIPWOLA.CZSWGVTC
EH2KLRQ.ZIPWOLA.CZSWGVTI
EH2KLRQ.ZIPWOLA.CZSWPBTC
EH2KLRQ.ZIPWOLA.CZSWPBTI
EH2KLRQ.ZIPWOLA.CZSWPTTC
EH2KLRQ.ZIPWOLA.CZSWPTTI
EH2KLRQ.ZIPWOLA.CZSWVFTC
EH2KLRQ.ZIPWOLA.CZSWVFTI
Relevant part in JCL is:
//FLCLCONV EXEC PGM=FLCL,REGION=0M,PARM='CONV'
//STEPLIB DD DISP=SHR,DSN=SYS3.FLAM.LOAD
//SYSOUT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//STDENV DD *
LANG=de_DE.IBM1141
FLM_SAF_LOG=OFF
//ARCHIN DD DISP=SHR,DSN=EH2KLRQ.FULWOLA.ZIP
//FLAMPAR DD *
read.text(file=DD:ARCHIN/?*)
write.record(
file='EH2KLRQ.ZIPWOLA.[_-1-.1|cut7][ext|cut1]'
ccsid=1141
falloc(recformat=FB,space(primary=200,secondary=300))
ccsid=1141
)
//
See 1027: Need example to unzip ZIP file with multiple files in it.
Three things are noteworthy:
- All members of ZIP archive are processed via
/?*
- Output files are dynamically created using
[AX-BY]
, then using first 7 characters, adding first character from extension - Target CCSID is specified
From FLCLBOOK.txt:
This is the list of supported processing rules:
- [path] - Extracts the string before the last slash or backslash, i.e. the path without trailing (back)slash
- [name] - Extracts the part after the last (back)slash, i.e. the filename
- [base] - Extracts the part between the last (back)slash and the last dot, i.e. the filename without extension
- [ext] - Extracts the part after the last dot, i.e. the file extension
- [member] - Extracts a string enclosed in round brackets from the filename part of the string, e.g. a PDS member name on z/OS
- [copy] - Simply copies the input string (useful if you only want to add an extension)
- [upper] - Converts all characters to upper case
- [lower] - Converts all characters to lower case
- [title] - Converts the first character to upper case, all others to lower case
- [cutX] - Cuts off the string after the X-th character, where X is a positive or negative number indicating how many characters to keep, counting from the front (positive) or back (negative)
- [indN] - Inserts the current index as decimal number of at least length N (padded with preceding zeros) N is any number between 0 and 9, where 0 results in variable length numbers with their shortest possible representation (no preceding zeros)
- [rndN] - Inserts random numbers of length N (with preceding zeros) N is any number between 0 and 9, where 0 results in variable length numbers (no preceding zeros)
- [AX] - A is a place holder for a single-byte character, X is a positive or negative number; Extracts the string part between the X-th occurrence of the specified character and the next occurrence of that same character. If X is negative, search starts at the back and in reverse. If X is 0, the part before the first occurrence of A is extracted.
- [AX-] - A is a placeholder for a single-byte character, X is a positive or negative number; Extracts the string part after the X-th occurrence of the specified character. If X is negative, search starts at the back and in reverse. If X is 0, the input string is copied.
- [AX-BY] - A and B are placeholders for a single-byte character, X and Y are positive or negative numbers; Extracts the string part between the X-th occurrence of A and (relative to that occurrence) the Y-th occurrence of B. Like above, negative numbers mean counting from the back.
- [search=replace] - Replaces the first occurrence of the string 'search' with the string 'replace'
- [search=*replace] - Replaces all occurrences of the string 'search' with the string 'replace'
- [table] - Evaluates to the current table name if end of table handling is activated (only when reading tables)
Examples:
------------------------------------------------------------------------
infile='/path/to/file.ext' pattern='text_without_tokens' outfile='text_without_tokens'
infile='/path/to/file.ext' pattern='text^[path^]' outfile='text[path]'
infile='/path/to/file.ext' pattern='[PATH]' outfile='/path/to'
infile='/path/to/file.ext' pattern='[Name]' outfile='file.ext'
infile='/path/to/file.ext' pattern='[ext]' outfile='ext'
infile='/path/to/file.ext' pattern='[UPPER]' outfile='/PATH/TO/FILE.EXT'
infile='/path/to/file.ext' pattern='[cut5]' outfile='/path'
infile='/path/to/file.ext', pattern='FILE[ind04]' outfile='FILE0001'
infile='/path/to/file.ext', pattern='FILE[rnd04]' outfile='FILE0815'
infile='/path/to/file.ext' pattern='[/2]' outfile='to'
infile='/path/to/file.ext' pattern='[/-1]' outfile='file.ext'
infile='/path/to/file.ext' pattern='[/2-]' outfile='to/file.ext'
infile='/path/to/file.ext' pattern='[/3-.1]' outfile='file'
infile='/path/to/file.ext' pattern='[path=directory]' outfile='/directory/to/file.ext'
infile='USER.DATA.PDS(MYMEMBER)' pattern='[member]' outfile='MYMEMBER'
infile='USER.DATA.PDS(MYMEMBER)' pattern='[.0|lower]/[.1|lower]/[member|lower].[ext|(0|lower]' outfile='user/data/mymember.pds'
infile='/verylongpath/to/longfilename.ext' pattern='[path|verylong=|/=*.|.1-|upper].[base|cut-8|upper]' outfile='PATH.TO.FILENAME'
infile='/path/to/*.txt' pattern='<SYSUID>.GDG(+[ind0])' outfile='USER.GDG(+n)' whereby n starts with 1 and is incremented for each file
------------------------------------------------------------------------