《-- Pro*CからPythonへの移行で学んだこと②:固定長ファイル・fgets・feof編 --》
Introduction / はじめに
Batch programs often read fixed-width text files line by line and extract values from specific character positions.
バッチ処理では、固定長のテキストファイルを1行ずつ読み込み、決められた位置から各項目を切り出す処理があります。
In Pro*C or C, functions such as fgets and feof are commonly used for this kind of file processing.
Pro*CやC言語では、このようなファイル処理にfgetsやfeofがよく使用されます。
When migrating this logic to Python, the code becomes simpler, but there are still some important differences to understand.
Pythonへ移行するとコードはシンプルになりますが、理解しておきたい違いがいくつかあります。
Reading a File in ProC(ProCでファイルを読み込む)
A typical Pro*C pattern may look like this:
Pro*Cでは、例えば次のような処理があります。
while (!feof(fp)) {
fgets(line, sizeof(line), fp);
if (feof(fp) != 0) {
break;
}
/* process record */
}
The program reads one line using fgets() and checks whether the end of the file has been reached.
fgets()で1行を読み込み、ファイルの終端に到達したかを確認しながら処理しています。
Reading a File in Python(Pythonでファイルを読み込む)
A similar structure in Python can be written like this:
Pythonで似た流れにすると、次のように書けます。
while True:
line = fp.readline()
if line == "":
break
# process record
readline() returns an empty string when it reaches the end of the file.
readline()は、ファイルの終端に到達すると空文字を返します。
Therefore, the following condition can be used as an EOF check.
そのため、次の処理をEOFの判定として使用できます。
if line == "":
break
break vs continue
break stops the entire loop.
breakはループそのものを終了します。
continue, on the other hand, skips the current iteration and moves to the next one.
一方、continueは現在の処理だけをスキップし、次のループへ進みます。
For example, if blank lines should be ignored:
例えば、空行を読み飛ばしたい場合は次のように書けます。
while True:
line = fp.readline()
if line == "":
break
if not line.strip():
continue
# process normal record
If the input file contains:
入力ファイルが次のようになっていた場合、
record 1
record 2
the flow becomes:
処理の流れは次のようになります。
record 1 → process
blank line → skip
record 2 → process
EOF → break
Key Point / ポイント
breakends the loop, whilecontinueskips only the current iteration.
breakはループ自体を終了し、continueは現在の1回だけをスキップします。
Reading Fixed-Width Data(固定長データを切り出す)
Suppose the following fixed-width record is provided:
例えば、次のような固定長データがあるとします。
202608ABC00100000100
Assume that the first six characters represent the year and month, and the next six characters represent the item code.
先頭6文字が年月、その次の6文字が商品コードだとします。
In Python, we can use string slicing.
Pythonでは文字列のスライスを使って切り出せます。
year_month = line[0:6]
item_code = line[6:12]
Python slicing follows the start:end format, and the end position itself is not included.
Pythonのスライスはstart:endという形式で、endの位置そのものは含まれません。
Defining Positions as Constants(切り出し位置を定数化する)
Writing values such as line[0:6] directly throughout the program can make maintenance difficult.
プログラム内のさまざまな場所にline[0:6]のような値を直接書くと、後から修正しづらくなります。
One option is to define the positions as constants.
そこで、切り出し位置を定数として定義する方法があります。
POS_YEAR_MONTH: tuple[int, int] = (0, 6)
POS_ITEM_CODE: tuple[int, int] = (6, 12)
start, end = POS_YEAR_MONTH
year_month = line[start:end]
This makes it easier to understand where each field is located.
各項目がどの位置から切り出されているのか分かりやすくなります。
Be Careful with Short Lines(レコード長不足に注意する)
Suppose we convert part of the input record to an integer.
例えば、入力データの一部を整数へ変換するとします。
quantity = int(line[20:25])
If the line is shorter than expected, line[20:25] may return an empty string.
レコードが想定より短い場合、line[20:25]が空文字になることがあります。
This can result in:
その結果、
ValueError: invalid literal for int() with base 10: ''
may be raised.
というエラーが発生する可能性があります。
Key Point / ポイント
Successfully reading a line does not necessarily mean that the record itself is valid.
「1行読み込めた」ことと「正しい形式のレコードである」ことは別です。
What I Learned / 学んだこと
In Pro*C, file processing may use fgets, feof, and fixed-size char arrays.
Pro*Cでは、fgets、feof、固定長のchar配列などを使用してファイルを処理します。
In Python, similar logic can be expressed with readline, break, continue, and string slicing.
Pythonでは、readline、break、continue、文字列スライスなどで同様の処理を表現できます。
The syntax is simpler, but understanding the input file layout is still essential.
書き方はシンプルになりますが、入力ファイルのレイアウトを正しく理解することは変わらず重要です。