开发者

Using Fortran stream correctly to write and read an array of integers

开发者 https://www.devze.com 2023-03-25 15:02 出处:网络
This 开发者_开发技巧is somewhat related to my recent post about Fortran stream and the like: Converting data stored in Fortran 90 binaries to human readable format.

This 开发者_开发技巧is somewhat related to my recent post about Fortran stream and the like: Converting data stored in Fortran 90 binaries to human readable format.

I am attempting to write a simple array of integers to a file, and then use Fortran's READ function to then read in the binary that I have created. I am using stream by including ACCESS="STREAM" in my OPEN directive. I have the following code:

MODULE streamtest2subs

  IMPLICIT NONE

CONTAINS

SUBROUTINE writeUstream(myarray)
  IMPLICIT NONE
  INTEGER, INTENT(IN), DIMENSION(4,10) :: myarray
  INTEGER :: myvalue = 12345, mypos
  OPEN(UNIT=11, FILE="ustream.demo", STATUS="REPLACE", ACCESS="STREAM")
  WRITE(11) myarray
  CLOSE(UNIT=11)
END SUBROUTINE writeUstream

SUBROUTINE readUstream
  IMPLICIT NONE
  INTEGER :: test1, test2, test3
  INTEGER :: n
  OPEN(UNIT=42, FILE="ustream.demo", STATUS="OLD", ACCESS="STREAM")
  READ(42, POS=1) test1
  READ(42, POS=2) test2
  READ(42, POS=3) test3

  WRITE(*,*) "This is the output:"
  WRITE(*,*) test1
  WRITE(*,*) test2
  WRITE(*,*) test3
END SUBROUTINE readUstream

END MODULE streamtest2subs

PROGRAM streamtest2
  USE streamtest2subs
  IMPLICIT NONE
  INTEGER :: i, j, k
  INTEGER, DIMENSION(4,10) :: a

  WRITE(*,*) "This is my input array:"
  k=1
  DO i=1,4
    DO j=1,10
      a(i,j)=k
      WRITE(*, "(i3)", ADVANCE="NO") a(i,j)
      k=k+1
    END DO
    WRITE(*,*)
  END DO
  WRITE(*,*)

  CALL writeUstream(a)
  CALL readUstream
END PROGRAM streamtest2

However, when I compile this using gfortran and run it, I get the following output:

 This is my input array:
  1  2  3  4  5  6  7  8  9 10
 11 12 13 14 15 16 17 18 19 20
 21 22 23 24 25 26 27 28 29 30
 31 32 33 34 35 36 37 38 39 40

 This is the output:
           1
   184549376
      720896

Why is it that the output is so complex? Is it that READ is reading the ustream.demo file as a string instead of as an integer? However, when I change the type of test1, test2, and test3 to string, my output is simply a series of three blank lines.

Am I using the POS directive in READ incorrectly? I think that POS specifies the character number in the output (although I am not sure if the elements of the array are delimited in any way); is this correct?

Thank you very much for your time!


For the purposes that you have described in your previous question, I think that you are programming this more complicated than is necessary. Assuming that you want a binary file without extra record structure, you want unformatted and stream. You can read the file in the same way that you wrote it -- you don't need to use POS -- unless the purpose is to learn how to use POS.

My tested example is based on a Fortran program in which I read a binary file that was written by someone else, almost certainly with a C program. The file consists of headers, followed by arrays of variable lengths. I open the file:

open ( unit=75, file=FileName, status='old', access='stream', form='unformatted', action='read' )

I read a header (a variable that is a user-define type with many sub-variables):

read (75) header

I allocate the array to the length that was read into one field of the header, then I read the array:

allocate ( array (1:header % ArrayLen) )
read (75) array

Then I process the data in the array. Then I repeat until end of file (not shown in the code samples).

Very easy ... no need to calculating position in the file and use the POS keyword of READ.


The problem is your read statements, the POS is the byte offset from the start of the file and is not related directly to the array index of the original a array that was written to the file.

So, in your code if test1 is a 4 byte integer the Fortran read will construct it by reading bytes 1 to 4 of the file. Similarly, test2 would be constructed from bytes 2 to 5, whereas the value is actually stored in bytes 5 to 8.

When I change the read lines to,

READ(42, POS=1) test1
READ(42, POS=5) test2
READ(42, POS=9) test3

The output becomes,

This is my input array:
1  2  3  4  5  6  7  8  9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40

This is the output:
       1
      11
      21

which I think is more what you were after. Note that if the values were written to file originally as, say, 2-byte or 8-byte integers then you would have to account for those sizes in the POS offsets when you read the file.

As an aside, it's worth learning the command line tool od for quick interrogations of binary files. For example, the first thing I did was check the write worked okay using,

$ od -t d4 ustream.demo 
0000000                 1              11              21              31
0000020                 2              12              22              32
0000040                 3              13              23              33
0000060                 4              14              24              34
0000100                 5              15              25              35
0000120                 6              16              26              36
0000140                 7              17              27              37
0000160                 8              18              28              38
0000200                 9              19              29              39
0000220                10              20              30              40
0000240
0

精彩评论

暂无评论...
验证码 换一张
取 消