Правильное использование потока Фортран для записи и чтения массива целых чисел - PullRequest
2 голосов
/ 02 августа 2011

Это в некоторой степени связано с моим недавним сообщением о потоке Фортрана и тому подобном: Преобразование данных, хранящихся в двоичных файлах Фортрана 90, в читаемый человеком формат .

Я пытаюсь написать простой массивцелых чисел в файл, а затем использовать функцию Fortran READ, чтобы затем прочитать в двоичном файле, который я создал.Я использую поток, включая ACCESS="STREAM" в мою директиву OPEN.У меня есть следующий код:

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

Однако, когда я компилирую это с помощью gfortran и запускаю его, я получаю следующий вывод:

 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

Почему вывод таксложный?Неужели READ читает файл ustream.demo как строку, а не как целое число?Однако, когда я меняю тип test1, test2 и test3 на string, мой вывод - это просто серия из трех пустых строк.

Я неправильно использую директиву POS в READ?Я думаю, что POS указывает номер символа в выводе (хотя я не уверен, что элементы массива каким-либо образом разделены);это правильно?

Большое спасибо за потраченное время!

Ответы [ 2 ]

5 голосов
/ 03 августа 2011

Для целей, которые вы описали в предыдущем вопросе, я думаю, что вы программируете это сложнее, чем необходимо. Предполагая, что вы хотите двоичный файл без дополнительной структуры записи, вы хотите неформатированный и потоковый. Вы можете прочитать файл так же, как вы его написали - вам не нужно использовать POS - если цель не состоит в том, чтобы научиться использовать POS.

Мой протестированный пример основан на программе на Фортране, в которой я читаю двоичный файл, написанный другим человеком, почти наверняка с помощью программы на Си. Файл состоит из заголовков, за которыми следуют массивы переменной длины. Я открываю файл:

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

Я прочитал заголовок (переменная, которая является определяемым пользователем типом со многими под-переменными):

read (75) header

Я распределяю массив по длине, которая была прочитана в одно поле заголовка, затем я читаю массив:

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

Затем я обрабатываю данные в массиве. Затем я повторяю до конца файла (не показано в примерах кода).

Очень просто ... не нужно вычислять позицию в файле и использовать ключевое слово POS READ.

3 голосов
/ 03 августа 2011

Проблема в ваших операторах чтения, POS - это смещение в байтах от начала файла и не связано напрямую с индексом массива исходного массива a, который был записан в файл.

Таким образом, в вашем коде, если test1 - это 4-байтовое целое число, читаемое Фортраном, построит его путем чтения байтов с 1 по 4 файла. Аналогично, test2 будет составлено из байтов 2–5, тогда как значение фактически сохраняется в байтах 5–8.

Когда я изменяю строки чтения на

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

Вывод становится,

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

что, я думаю, больше того, что вы хотели. Обратите внимание, что если значения были записаны в файл первоначально как, скажем, 2-байтовые или 8-байтовые целые числа, вам придется учитывать эти размеры в смещениях POS при чтении файла.

Кроме того, стоит изучить инструмент командной строки od для быстрого опроса двоичных файлов. Например, первым делом я проверил, что запись работает нормально, используя

$ 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
...