- Tác giả

- Name
- Nguyễn Đức Xinh
- Ngày xuất bản
- Ngày xuất bản
FILE-CONTROL và FILE SECTION trong COBOL – Đọc file text tuần tự như batch program thực tế
Vì sao phải hiểu FILE-CONTROL và FILE SECTION trong COBOL?
Trong các bài trước, bạn đã quen với:
- Bài 002: DATA DIVISION, level number, PIC
- Bài 004: Toán tử & biểu thức
- Bài 005: IF, EVALUATE
- Bài 006: Vòng lặp & PERFORM
Nhưng một batch program thực tế (như RZZBSQLN1.PCO) luôn có thêm một mảnh ghép quan trọng:
Đọc/ghi file – thường là file text tuần tự, dùng để nhận input hoặc ghi log/output.
Trong COBOL, phần này được mô tả bởi hai khu vực chính:
- ENVIRONMENT DIVISION → INPUT-OUTPUT SECTION → FILE-CONTROL – định nghĩa file logic, liên kết với file vật lý, tổ chức file, FILE STATUS
- DATA DIVISION → FILE SECTION – mô tả cấu trúc record (layout từng dòng trong file)
Bài này sẽ giúp bạn:
- Đọc được các đoạn như:
SELECT INP1FILE ASSIGN TO "INP1-MSD" ... FILE STATUS IS F_STS. - Hiểu vai trò của
FD,01 INP1_REC,READ ... AT END ... NOT AT END ... - Mapping sang mental model Java/Python (FileReader, BufferedReader)
- Viết được một skeleton batch để đọc file tuần tự từ đầu đến cuối
Tổng quan: ENVIRONMENT DIVISION, FILE-CONTROL và FILE SECTION
Trong một chương trình COBOL xử lý file, bạn thường thấy cấu trúc như:
IDENTIFICATION DIVISION.
PROGRAM-ID. SAMPLE-FILE.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT INFILE ASSIGN TO "input.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-FILE-STS.
DATA DIVISION.
FILE SECTION.
FD INFILE.
01 IN-REC.
05 IN-FIELD1 PIC X(10).
05 IN-FIELD2 PIC 9(5).
WORKING-STORAGE SECTION.
01 WS-FILE-STS PIC X(2) VALUE "00".
01 WS-END-FLAG PIC 9 VALUE 0.
PROCEDURE DIVISION.
OPEN INPUT INFILE
PERFORM UNTIL WS-END-FLAG = 1
READ INFILE
AT END
MOVE 1 TO WS-END-FLAG
NOT AT END
DISPLAY IN-FIELD1 IN-FIELD2
END-READ
END-PERFORM
CLOSE INFILE
STOP RUN.
Tách component:
FILE-CONTROL:- Khai báo tên file logic (
INFILE) - Liên kết với file vật lý (
ASSIGN TO "input.txt") - Định nghĩa cách tổ chức file (
ORGANIZATION IS LINE SEQUENTIAL) - Chỉ định biến chứa status (
FILE STATUS IS WS-FILE-STS)
- Khai báo tên file logic (
FILE SECTION:FD INFILE.– mô tả file01 IN-REC.– mô tả một record (mỗi dòng trong file)
PROCEDURE DIVISION:OPEN INPUT INFILEREAD INFILE AT END ... NOT AT END ...CLOSE INFILE
Trong RZZBSQLN1.PCO, pattern này xuất hiện với:
SELECT INP1FILE ASSIGN TO "INP1-MSD"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS F_STS.
FD INP1FILE
LABEL RECORDS ARE STANDARD.
01 INP1_REC.
02 INP1_SQL PIC X(80).
Đây là file chứa các câu lệnh SQL text, mỗi dòng một SQL.
FILE-CONTROL – SELECT, ASSIGN, ORGANIZATION, FILE STATUS
1. SELECT và ASSIGN – đặt tên logic cho file
FILE-CONTROL.
SELECT INP1FILE ASSIGN TO "INP1-MSD".
INP1FILElà tên file logic trong chương trình COBOLASSIGN TO "INP1-MSD"là tên file vật lý (tùy platform):- Trên mainframe: có thể là DDNAME, dataset name
- Trên GnuCOBOL: có thể là đường dẫn
"/path/input.txt"
Mapping sang Java pseudo-code:
BufferedReader inp1file = new BufferedReader(
new FileReader("INP1-MSD")
);
Bạn làm việc với INP1FILE (logic name), còn runtime sẽ hiểu file vật lý tương ứng.
2. ORGANIZATION IS LINE SEQUENTIAL – file text từng dòng
ORGANIZATION IS LINE SEQUENTIAL
Ý nghĩa:
- File được xem như danh sách các dòng text, mỗi lần
READđọc một dòng - Mỗi record trong
FILE SECTIONtương ứng với một line
Các giá trị khác của ORGANIZATION (nâng cao hơn, dùng cho VSAM, indexed file):
SEQUENTIALRELATIVEINDEXED
Trong context batch đọc file text đơn giản, bạn hầu như sẽ dùng LINE SEQUENTIAL.
3. FILE STATUS IS – lưu mã lỗi I/O
FILE STATUS IS F_STS.
-
F_STSlà biến PIC X(2) trong WORKING-STORAGE, ví dụ:77 F_STS PIC X(2) VALUE SPACE. -
Mỗi lần
OPEN,READ,CLOSEfile, COBOL sẽ setF_STS:- "00" – OK
- Các giá trị khác – lỗi hoặc trạng thái đặc biệt (EOF, permission, không tìm thấy file, ...)
Trong RZZBSQLN1, bạn thấy pattern:
IF F_STS NOT = "00"
... xử lý lỗi file ...
END-IF.
Về tư duy, có thể coi như:
int status = openFile();
if (status != 0) {
// handle error
}
FILE SECTION – FD và record layout
Sau FILE-CONTROL, tới DATA DIVISION → FILE SECTION:
FILE SECTION.
FD INP1FILE.
01 INP1_REC.
02 INP1_SQL PIC X(80).
Ý nghĩa:
FD INP1FILE.– khai báo file description cho logic nameINP1FILE01 INP1_REC.– mô tả một dòng (record) trong file- Bên trong
INP1_REClà các field con (level 02, 05,...)
Ví dụ khác, file chứa thông tin khách hàng:
FD CUSTFILE.
01 CUST-REC.
05 CUST-ID PIC 9(5).
05 CUST-NAME PIC X(30).
05 CUST-AGE PIC 9(3).
Nếu ORGANIZATION IS LINE SEQUENTIAL, mỗi dòng trong file text sẽ map vào CUST-REC theo layout này:
- Từ cột 1–5 :
CUST-ID - Từ cột 6–35 :
CUST-NAME - Từ cột 36–38:
CUST-AGE
File thực tế có thể trông như:
00001Nguyen Van A 025
00002Tran Thi B 031
Khi READ CUSTFILE, COBOL sẽ:
- Lấy 5 ký tự đầu →
CUST-ID - Lấy 30 ký tự tiếp →
CUST-NAME - Lấy 3 ký tự cuối →
CUST-AGE
01 CUST-REC chính là record cấp 01 mà bạn đã học ở bài 006 (level number).
OPEN, READ, CLOSE – vòng đời làm việc với file
1. OPEN – mở file với mode thích hợp
OPEN INPUT INFILE.
OPEN OUTPUT OUTFILE.
OPEN I-O UPDFILE.
Các mode cơ bản:
INPUT– chỉ đọcOUTPUT– chỉ ghi (ghi mới)I-O– đọc/ghi (update)EXTEND– ghi nối thêm cuối file
Sau OPEN, bạn phải check FILE STATUS nếu được khai báo.
2. READ – đọc từng record
Form điển hình với AT END:
READ INFILE
AT END
... xử lý khi hết file ...
NOT AT END
... xử lý record đọc được ...
END-READ.
Kết hợp với loop (như đã thấy ở bài 006 – PERFORM):
PERFORM UNTIL WS-END-FLAG = 1
READ INFILE
AT END
MOVE 1 TO WS-END-FLAG
NOT AT END
... xử lý record ...
END-READ
END-PERFORM.
Đây là pattern main loop chuẩn để đọc file từ đầu tới EOF.
3. CLOSE – đóng file
CLOSE INFILE.
Thông thường, bạn nên đóng file trong paragraph riêng (ví dụ INP1-CLOSE-RTN trong RZZBSQLN1) và chỉ gọi một lần ở cuối chương trình hoặc khi có error cần stop.
Mapping mental model sang Java/Python
Giả sử bạn có đoạn COBOL đọc file khách hàng:
FILE-CONTROL.
SELECT CUSTFILE ASSIGN TO "customer.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS F_STS.
FILE SECTION.
FD CUSTFILE.
01 CUST-REC.
05 CUST-ID PIC 9(5).
05 CUST-NAME PIC X(30).
WORKING-STORAGE SECTION.
77 F_STS PIC X(2) VALUE SPACE.
77 END-FLAG PIC 9 VALUE 0.
PROCEDURE DIVISION.
OPEN INPUT CUSTFILE
IF F_STS NOT = "00"
DISPLAY "FILE OPEN ERROR: " F_STS
STOP RUN
END-IF
PERFORM UNTIL END-FLAG = 1
READ CUSTFILE
AT END
MOVE 1 TO END-FLAG
NOT AT END
DISPLAY "ID=" CUST-ID " NAME=" CUST-NAME
END-READ
END-PERFORM
CLOSE CUSTFILE
STOP RUN.
Java-style pseudo-code tương đương:
try (BufferedReader reader = new BufferedReader(new FileReader("customer.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
String custId = line.substring(0, 5);
String custName = line.substring(5, 35);
System.out.println("ID=" + custId + " NAME=" + custName);
}
} catch (IOException e) {
System.out.println("FILE OPEN/READ ERROR" + e.getMessage());
}
Điểm khác biệt:
- COBOL mô tả layout ngay trong code (FILE SECTION)
- Java/Python thường phải tự
substring/splitđể parse
Pattern trong RZZBSQLN1: INP1FILE và record SQL
Trích đoạn (rút gọn) từ RZZBSQLN1.PCO:
FILE-CONTROL.
SELECT INP1FILE ASSIGN TO "INP1-MSD"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS F_STS.
FILE SECTION.
FD INP1FILE
LABEL RECORDS ARE STANDARD.
01 INP1_REC.
02 INP1_SQL PIC X(80).
Và đoạn đọc file (giản lược):
INP1-OPEN-RTN.
OPEN INPUT INP1FILE
IF F_STS NOT = "00"
... log lỗi ...
GO TO STOP-PGM
END-IF.
INP1-INPUT-RTN.
READ INP1FILE
AT END
MOVE 1 TO INP1_END
NOT AT END
ADD 1 TO INP1_INPCNT
END-READ.
Tư duy backend dev khi đọc:
INP1FILE~ file chứa danh sách SQL textINP1_REC~ một dòng trong file, chứaINP1_SQLINP1-OPEN-RTN~ mở file, check statusINP1-INPUT-RTN~ đọc từng dòng, tăng counter, set flag EOF
Trong các bài sau về embedded SQL, bạn sẽ thấy các dòng này được đưa vào table WK_SQL_TBL và thực thi bằng EXECUTE IMMEDIATE.
Ví dụ tổng hợp: chương trình đọc file text đơn giản
Dưới đây là ví dụ full một chương trình COBOL đọc file text và in từng dòng cùng số thứ tự record.
File input (data/customer.txt)
00001Nguyen Van A 025
00002Tran Thi B 031
00003Le Van C 040
Chương trình COBOL
IDENTIFICATION DIVISION.
PROGRAM-ID. READ-CUSTOMER.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CUSTFILE ASSIGN TO "customer.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS F-ST.
DATA DIVISION.
FILE SECTION.
FD CUSTFILE.
01 CUST-REC.
05 CUST-ID PIC 9(5).
05 CUST-NAME PIC X(30).
05 CUST-AGE PIC 9(3).
WORKING-STORAGE SECTION.
77 F-ST PIC X(2) VALUE SPACE.
77 END-FLAG PIC 9 VALUE 0.
77 REC-COUNT PIC 9(5) VALUE 0.
PROCEDURE DIVISION.
MAIN-RTN.
PERFORM OPEN-RTN THRU OPEN-EXT
PERFORM READ-RTN THRU READ-EXT
UNTIL END-FLAG = 1
PERFORM CLOSE-RTN THRU CLOSE-EXT
STOP RUN.
OPEN-RTN.
OPEN INPUT CUSTFILE
IF F-ST NOT = "00"
DISPLAY "FILE OPEN ERROR: " F-ST
MOVE 1 TO END-FLAG
END-IF.
OPEN-EXT.
EXIT.
READ-RTN.
READ CUSTFILE
AT END
MOVE 1 TO END-FLAG
NOT AT END
ADD 1 TO REC-COUNT
DISPLAY "REC#" REC-COUNT
DISPLAY " ID : " CUST-ID
DISPLAY " NAME: " CUST-NAME
DISPLAY " AGE : " CUST-AGE
END-READ.
READ-EXT.
EXIT.
CLOSE-RTN.
CLOSE CUSTFILE
DISPLAY "TOTAL RECORD = " REC-COUNT.
CLOSE-EXT.
EXIT.
Ví dụ này kết hợp:
FILE-CONTROL+FILE SECTIONOPEN/READ/CLOSEFILE STATUSPERFORM ... THRU ...+PERFORM ... UNTIL ...
Tức là gắn kết những gì bạn đã học ở bài 004–006 với file I/O thực tế.
Bài tập thực hành
Bài 1 – Skeleton đọc file sản phẩm
Thiết kế chương trình đọc file sản phẩm với layout:
PROD-ID– 10 ký tự (X(10))PROD-NAME– 30 ký tự (X(30))PROD-PRICE– 9 ký tự numeric (9(9))
Yêu cầu:
- Khai báo
FILE-CONTROLvớiSELECT,ASSIGN TO "product.txt",ORGANIZATION IS LINE SEQUENTIAL,FILE STATUS IS WS-FS. - Khai báo
FILE SECTIONvớiFD PROD-FILEvà01 PROD-RECtương ứng. - Viết
PROCEDURE DIVISIONtối thiểu có:OPEN INPUT PROD-FILE- Loop
READđến EOF - Mỗi record:
DISPLAYID + NAME + PRICE CLOSE PROD-FILE
Không cần chạy được ngay, chỉ cần đúng cấu trúc.
Bài 2 – Đếm số record và xử lý lỗi FILE STATUS
Mở rộng bài 1:
- Thêm
WS-REC-COUNT(9(5)) vàWS-ERR-FLAG(9) - Logic:
- Sau
OPEN, nếuWS-FS NOT = "00"→ setWS-ERR-FLAG = 1,STOP RUN - Khi
READmàFILE STATUS!= "00" và != EOF (tùy platform) → tăngERR-COUNT, hiển thị message - Cuối chương trình, hiển thị tổng record đọc được và tổng số lỗi I/O
- Sau
Bài 3 – Mapping FILE SECTION sang Java parser
Lấy lại layout CUST-REC ở ví dụ trên. Hãy viết pseudo-code Java hoặc Python để:
- Mở file text
- Đọc từng dòng
- Parse
custId,custName,custAgeđúng theo vị trí
Mục tiêu: luyện thói quen luôn mapping COBOL layout sang tư duy parsing hiện đại.
Bài 4 – Áp dụng pattern của RZZBSQLN1
Từ các trích đoạn về INP1FILE trong RZZBSQLN1.PCO, hãy:
- Viết lại
FILE-CONTROL+FILE SECTIONdưới dạng rút gọn (chỉ giữ phần liên quan đếnINP1_SQL) - Viết pseudo-code mô tả
INP1-OPEN-RTNvàINP1-INPUT-RTNbằng Java hoặc Python - Chỉ ra:
- Biến nào là FILE STATUS
- Biến nào là flag EOF
- Biến nào là counter số record đọc được
Kết luận
Sau bài 007, bạn đã nắm được:
- Cách COBOL định nghĩa file logic và vật lý qua FILE-CONTROL
- Cách mô tả layout từng dòng file bằng FILE SECTION / FD / 01 record
- Pattern chuẩn để đọc file tuần tự:
OPEN→READ ... AT END ...trong loop →CLOSE - Liên hệ trực tiếp với code enterprise như
RZZBSQLN1.PCO
Kết hợp với kiến thức trước đó (DATA DIVISION, level number, PERFORM loop, IF/EVALUATE), bạn đã có thể tự tin đọc, hiểu và viết các chương trình COBOL đơn giản để xử lý file text – nền tảng của rất nhiều batch job ngoài đời.
Ở các bài tiếp theo, chúng ta sẽ:
- Đi sâu vào WORKING-STORAGE nâng cao với OCCURS và REDEFINES – cách khai báo table và struct phức tạp (bài 008)
- Phân tích cách
RZZBSQLN1dùngWK_SQL_TBLvàWK_PARM_TBLđể lưu danh sách SQL/parameter
Từ đó, bạn dần tiến tới việc đọc trọn vẹn logic của một chương trình COBOL lớn và có thể tự thiết kế batch program cho hệ thống của riêng mình.
