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.master
parent
f246d382bf
commit
21e85704aa
2 changed files with 100 additions and 0 deletions
@ -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 |
@ -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 |
||||
|
Loading…
Reference in new issue