Skip to content

Instantly share code, notes, and snippets.

@tkanmae
Last active December 18, 2015 02:28
Show Gist options
  • Save tkanmae/5710730 to your computer and use it in GitHub Desktop.
Save tkanmae/5710730 to your computer and use it in GitHub Desktop.
Scan records in a Fortran unformatted file.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division
import itertools
import struct
def scan_fortran_unformatted(fname, marker_size=4):
"""Scan records of a Fortran unformatted file.
In unformatted IO, Fortran typically writes the length of a record at the
beginning and at the end of the record. They are often called as markers.
Most but not all Fortran runtimes use 4 bytes for the markers.
Parameters
----------
fname: str
File name.
marker_size: int, optional
Marker size in bytes. Default is 4.
Returns
-------
record_struct: list of 4-tuple of ints
Record structure. Each tuple contains information about a record block:
the record number, the position of the beginning of the record, the
number of bytes in the record.
"""
unpack = struct.unpack
if not marker_size in (4, 8):
raise ValueError('marker_size must be either 4 or 8.')
fmt = 'i' if marker_size == 4 else 'q'
with open(fname, 'rb') as fh:
record_struct = []
for rec_num in itertools.count(1):
buf = fh.read(marker_size)
if len(buf) < marker_size:
break
# Marker at the beginning of the block.
marker_beg, = unpack(fmt, buf)
# Position of the beginning of the record.
pos_beg = fh.tell()
# Seek the end of the block.
fh.seek(marker_beg, 1)
# Marker at the end of the block.
marker_end, = unpack(fmt, fh.read(marker_size))
# Both lengths must be the same.
assert marker_beg == marker_end
record_struct.append((rec_num, pos_beg, marker_beg))
return record_struct
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment