The OUTFIL control statement lets you create multiple output datasets or reports from a single DFSORT step. Each OUTFIL specifies a FNAMES= (the DD name where that output is written) and can have its own INCLUDE or OMIT to filter which records go to that file, its own BUILD= (or OUTREC-style reformatting) to change the record layout for that output only, and options like SPLITBY to split by record count or SAVE to capture records not selected by earlier OUTFILs. The primary output is still SORTOUT unless you use OUTFIL to redirect or add outputs. OUTFIL is the right tool when you need to split one sorted stream into several files (e.g. by department, by key range) or when you need different formats or filters per output. This page covers OUTFIL syntax, FNAMES=, INCLUDE/OMIT per output, BUILD=, SAVE, and SPLITBY.
OUTFIL (Output File) runs in the output phase. After records have been sorted or merged (and optionally processed by SUM), DFSORT writes them to SORTOUT and to any datasets named in OUTFIL statements. Each OUTFIL defines one (or more, via FNAMES=) output stream. You can have several OUTFIL statements: for example, one that writes only records where department is DEPT1, another for DEPT2, and another with SAVE that receives all records not already written by the previous OUTFILs. So one sort step can produce multiple filtered or reformatted files without running the sort again.
OUTFIL does not change the order of records—that was determined by SORT or MERGE. It only controls where each record is written and how it is formatted for that particular output. Each OUTFIL is independent: different INCLUDE/OMIT, different BUILD, different DD name.
FNAMES= specifies the DD name of the dataset(s) to which this OUTFIL will write. You must have a corresponding DD statement in your JCL. For example:
1OUTFIL FNAMES=OUT1,BUILD=(1,80)
This OUTFIL writes to the dataset allocated to DD name OUT1. Your JCL must include something like //OUT1 DD DSN=MY.OUTPUT.FILE1,DISP=(NEW,CATLG),.... You can give multiple names: FNAMES=OUT1,OUT2 writes the same record stream to both datasets. Typically each OUTFIL has its own FNAMES= so that different outputs go to different files (e.g. OUT1 for dept1, OUT2 for dept2).
Each OUTFIL can have INCLUDE=(condition) or OMIT=(condition). The condition uses the same syntax as the INCLUDE/OMIT control statements: (position,length,format,operator,value). Only records that satisfy the condition (for INCLUDE) or do not satisfy it (for OMIT) are written to that OUTFIL. So you can split one sorted stream into multiple files by value:
1234SORT FIELDS=(1,10,CH,A) OUTFIL FNAMES=DEPT1,INCLUDE=(30,5,CH,EQ,C'DEPT1'),BUILD=(1,50) OUTFIL FNAMES=DEPT2,INCLUDE=(30,5,CH,EQ,C'DEPT2'),BUILD=(1,50) OUTFIL FNAMES=OTHER,SAVE,BUILD=(1,50)
Records with bytes 30–34 equal to DEPT1 go to DEPT1; records with DEPT2 go to DEPT2; all other records go to OTHER because of SAVE. BUILD=(1,50) shortens each output to 50 bytes. The positions in INCLUDE= refer to the record at output time (after INREC if used, and after sort).
BUILD= on OUTFIL specifies how to reformat the record for this OUTFIL output only. The syntax is the same as OUTREC FIELDS= or BUILD=: (position,length) to copy from the record, constants C'...', nX, nZ. So one OUTFIL can write a 20-byte summary while another writes the full 80-byte record. The record length written to that OUTFIL's dataset is the length of the built record; the DD for that file must have the correct LRECL.
SAVE on an OUTFIL means: write to this OUTFIL any record that has not been written by a previous OUTFIL in the same step. So you use SAVE when you have several OUTFILs with INCLUDE (or OMIT) and you want a "catch-all" file for records that did not match any of the earlier conditions. The OUTFIL with SAVE is usually coded last. Without SAVE, records that do not match any OUTFIL's INCLUDE/OMIT are not written to any OUTFIL (they may still go to SORTOUT if you have a primary SORTOUT).
SPLITBY=n splits the output into multiple datasets by record count. You code multiple OUTFILs with the same or sequential FNAMES= and SPLITBY=n on the first. For example, the first 1000 records go to the first file, the next 1000 to the second, and so on. This is useful when you need to break a large output into fixed-size chunks (e.g. for transmission or for downstream limits). The exact syntax (e.g. one OUTFIL with SPLITBY=1000 and FNAMES=OUT1,OUT2,...) depends on your DFSORT version; see your product documentation.
SORTOUT is the single primary output. If you do not use OUTFIL, all records go to SORTOUT (after OUTREC if specified). When you add OUTFIL:
DFSORT evaluates each record against OUTFILs in the order they appear in SYSIN. The first OUTFIL whose INCLUDE/OMIT (if any) is satisfied can receive the record. If you use SAVE, the last OUTFIL with SAVE gets any record not yet written to a prior OUTFIL. So the order of OUTFIL statements matters when you have overlapping conditions or SAVE.
OUTFIL can generate reports with HEADER1, TRAILER1, SECTIONS, and related parameters—fixed header and trailer lines, control-break sections, and so on. Those are covered in the Report Generation and OUTFIL Advanced Output Control tutorials. For a first step, FNAMES=, INCLUDE/OMIT, BUILD=, and SAVE are enough to split and reformat output to multiple files.
Imagine you have one big sorted stack of cards and three boxes. OUTFIL is the rule for each box: "Box 1: only put cards that say DEPT1 here. Box 2: only put cards that say DEPT2 here. Box 3: put everything that's left here." So you go through the stack once and drop each card into the right box. You don't sort again—you just decide which box each card goes into. You can also say "when you put a card in box 1, only copy the first 50 characters onto a new slip"—that's BUILD= for that OUTFIL. So OUTFIL = multiple boxes (files) and rules (INCLUDE/OMIT/BUILD) for each box.
1. What does OUTFIL do in DFSORT?
2. What does FNAMES= on OUTFIL specify?
3. Can one OUTFIL write only records that match a condition?
4. What does SAVE do on an OUTFIL?
5. How does OUTFIL BUILD= relate to OUTREC?