From 21e85704aa69f08690beb0963b4f1a9b06443d38 Mon Sep 17 00:00:00 2001 From: wirawan Date: Mon, 8 Feb 2010 21:49:54 +0000 Subject: [PATCH] * Initial version of Fortran binary file reader. Later a writing facility can be added as well. * Note that this module is intended only for reading/writing Fortran-generated files. It is not recommended for any other purpose because of its terrible feature: no metadata, no description whatsoever. --- iofmt/__init__.py | 11 ++++++ iofmt/fortbin.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 iofmt/__init__.py create mode 100644 iofmt/fortbin.py diff --git a/iofmt/__init__.py b/iofmt/__init__.py new file mode 100644 index 0000000..d55e5af --- /dev/null +++ b/iofmt/__init__.py @@ -0,0 +1,11 @@ +# $Id: __init__.py,v 1.1 2010-02-08 21:49:54 wirawan Exp $ +# +# wpylib.iofmt module +# Created: 20100208 +# Wirawan Purwanto +# +# I/O format-related stuff. + +"""I/O format-related stuff.""" + +pass diff --git a/iofmt/fortbin.py b/iofmt/fortbin.py new file mode 100644 index 0000000..6e25e03 --- /dev/null +++ b/iofmt/fortbin.py @@ -0,0 +1,89 @@ +# $Id: fortbin.py,v 1.1 2010-02-08 21:49:54 wirawan Exp $ +# +# wpylib.iofmt.fortbin module +# Created: 20100208 +# Wirawan Purwanto +# +""" +Fortran binary format. + +""" + +import numpy +import sys + +from wpylib.sugar import ifelse + +class fortran_bin_file(object): + """A tool for reading Fortran binary files.""" + def __init__(self, filename=None): + self.record_marker_type = numpy.uint32 + self.debug = 100 + if filename: + self.open(filename) + + def open(self, filename): + self.F = open(filename, "rb") + + def read(self, *fields, **opts): + """Reads a Fortran record. + The description of the fields are given as + (name, dtype, length) tuples.""" + from numpy import fromfile as rd + if self.debug: + dbg = lambda msg : sys.stderr.write(msg) + else: + dbg = lambda msg : None + def fld_count(f): + if len(f) > 2: + return f[2] + else: + return 1 + + reclen = numpy.fromfile(self.F, self.record_marker_type, 1) + dbg("Record length = %d\n" % reclen) + expected_len = sum([ fld_count(f) * numpy.dtype(f[1]).itemsize + for f in fields ]) + dbg("Expected length = %d\n" % expected_len) + if expected_len > reclen: + raise IOError, \ + "Attempting to read %d bytes from a record of length %d bytes" \ + % (expected_len, reclen) + + if "out" in opts: + rslt = opts["out"] + else: + rslt = {} + + if (issubclass(rslt.__class__, dict) and issubclass(dict, rslt.__class__)) \ + or "__setitem__" in dir(rslt): + def setval(d, k, v): + d[k] = v + else: + # Assume we can use setattr method: + setval = setattr + + for f in fields: + if len(f) > 2: + (name,Dtyp,Len) = f + dtyp = numpy.dtype(Dtyp) + setval(rslt, name, numpy.fromfile(self.F, dtyp, Len)) + else: + # Special handling for scalars + name = f[0] + dtyp = numpy.dtype(f[1]) + setval(rslt, name, numpy.fromfile(self.F, dtyp, 1)[0]) + + if expected_len < reclen: + self.F.seek(reclen - expected_len, 1) + + reclen2 = numpy.fromfile(self.F, self.record_marker_type, 1) + dbg("Record length tail = %d\n" % reclen2) + + if reclen2 != reclen: + raise IOError, \ + "Inconsistency in record: end-marker length = %d; was expecting %d" \ + % (reclen2, reclen) + + return rslt +