Как получить доступ к одной записи с неформатированным прямым доступом Fortran, если соответствующий RECL неизвестен?

Если не используется новый потоковый доступ, доступный в F2003, Fortran классически рассматривает файлы как последовательность записей. Если файл подключен для прямого доступа, можно получить доступ к любой записи в любом порядке, указав номер записи. Например:

open(newunit=funit, file=filename, form='unformatted', access='direct', &
     recl=64, status='old')
read(funit, rec=2) data
close(funit)

Так что это звучит великолепно... однако я не уверен, что понимаю параметр RECL и как можно эффективно использовать прямой доступ, если правильная длина записи еще не известна. Из документов (различные версии Intel Fortran):

Все записи имеют длину, указанную параметром RECL в операторе OPEN.

Другими словами, прямой доступ разрешает доступ к данным в объеме, равном или меньше RECL, при перемещении по файлу с шагом RECL. То есть вы можете указать любое значение, которое вам нравится (равное или меньше размера файла, я полагаю). Я думаю, это очевидно задним числом... но я надеялся, что соответствующий RECL каким-то образом можно обнаружить.1 Возможно, я делаю это неправильно, но я хотел бы получить данные из указанного только запись - не больше, не меньше.

Помимо кодирования соответствующего значения RECL в разделе «заголовок» файла, есть ли способ получить доступ к одной записи за раз с файлом, подключенным для неформатированного (или даже отформатированного) прямого доступа, если правильная длина записи не известно заранее? Какие хитрости для этого используются?

1 Я надеялся, что inquire(funit, recl=rl) предоставит соответствующий RECL, но если файл был подключен для прямого доступа, он возвращает значение RECL, указанное при открытии файла. При подключении для последовательного доступа кажется, что он возвращает максимально допустимую длину записи (?), 2040 в моем случае.


person Matt P    schedule 10.05.2017    source источник
comment
К вашей сноске: если файл подключен для последовательного доступа, то возвращаемое значение rl действительно соответствует максимальной длине записи.   -  person francescalus    schedule 10.05.2017
comment
@francescalus Поскольку это ifort, означает ли это 4 * 2040 байт?   -  person Matt P    schedule 10.05.2017
comment
Возможно, но это может варьироваться в зависимости от параметров, используемых при компиляции. Чтобы быть явным: максимальная длина записи файла с последовательным доступом не связана с соответствующей длиной записи для прямого доступа.   -  person francescalus    schedule 10.05.2017
comment
если вы не знаете, RECL как вы узнаете, что файл вообще был записан с фиксированной длиной записи? Кажется, это тот случай, когда вы должны лучше объяснить, что вы на самом деле пытаетесь сделать.   -  person agentp    schedule 10.05.2017
comment
@agentp Это резонный вопрос. Файлы создаются отдельной и независимой программой. Известно, что в каждом файле записи имеют одинаковую длину, но не обязательно, что это за длина. Я думаю, что мне, возможно, придется модифицировать программу записи файлов, чтобы я мог предположить максимальную длину записи в программе чтения файлов, а не пытаться определить, какова подходящая длина для каждого файла, который должен быть обработан.   -  person Matt P    schedule 10.05.2017
comment
Если у вас есть контроль над пишущей стороной, просто используйте потоки.   -  person agentp    schedule 10.05.2017
comment
@agentp Я не очень хорошо знаком с потоковым доступом. Хотя возможность произвольного доступа (с использованием позиции) и записей переменной длины являются преимуществами, кажется, что вам нужно будет знать длину/положение всех записей, прежде чем вы сможете получить к ним доступ и использовать их эффективно. Может быть, я что-то упускаю... Если хотите, я могу задать новый вопрос: чтобы использовать потоки, вам пришлось бы читать весь файл и сохранять длину/положение каждой записи? В моем случае, я полагаю, я мог бы прочитать первую запись и вычислить положение всех последующих записей?   -  person Matt P    schedule 10.05.2017


Ответы (1)


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

Если вы знаете, какие данные хранятся в записи прямого доступа, вы можете запросить компилятор, спросив не о файле, а о данных.

Например, если запись состоит из переменных a, b, c, какими бы они ни были,

 !just an example
 real :: a(10)
 type(my_type) :: b
 character(5) :: c(3)

вы спрашиваете, насколько велика такая запись

 inquire(iolength=rl) a, b, c

а затем вы соединяете свой файл с recl=rl

open(newunit=funit, file=filename, form='unformatted', access='direct', &
     recl=rl, status='old')

См., например, Почему работает ввод-вывод с прямым доступом. неправильно с Intel Visual Fortran

Будьте осторожны, значение RECL не является переносимым и будет различаться между компиляторами. Некоторые измеряют его в байтах, а некоторые в 4-байтовых словах. Я просто помню, что gfortran и ifort различаются, а не какой из них какой. И мне все равно, кто из них кто.

Если вы обнаружите, что указываете RECL с магической константой, как в recl=64, вы делаете что-то не так, потому что это не будет работать в другом компиляторе. У вас всегда должна быть переменная, а не фиксированное число.

person Vladimir F    schedule 10.05.2017
comment
Тогда его не следует открывать таким образом. - person Vladimir F; 10.05.2017
comment
Использование inquire для данных имеет смысл. Я пытался использовать это ранее, но неправильно и был в тупике. Теперь я думаю, что он у меня есть... - person Matt P; 10.05.2017
comment
А, теперь я вспомнил свою проблему с inquire(iolength=rl) a. Предположим, что a — массив целых чисел. Можно предположить, что все записи (массивы) в файле имеют одинаковую длину, но эта длина неизвестна априори. Можете подсказать, как это может работать? Если нет, я думаю, мне нужно будет изменить программу, которая записывает файл, чтобы все массивы создавались с известной максимальной длиной, при необходимости дополняемые нулями. Имеет ли это смысл? - person Matt P; 10.05.2017
comment
Стандарт Fortran требует измерения recl в байтах. Ifort переходит в этот режим при -standard-semantics, что подразумевает byterecl - person tim18; 10.05.2017
comment
@ tim18 В своем ответе я не ссылался на стандарт, я написал о том, что делают обычные компиляторы. Я также не уверен, что стандарт требует этого, у вас есть цитата? Стандарт IIRC даже позволяет использовать маркеры записи. - person Vladimir F; 10.05.2017
comment
@ tim18 Я также читал, что стандарт предлагает byterecl, но это не обязательно. Однако я не читал стандарт. Я прочитал документы Intel; с параметром компилятора по умолчанию: assume nobyterecl ... Units for OPEN statement RECL values with unformatted files are in four-byte (longword) units. - person Matt P; 10.05.2017
comment
Для неформатированного ввода-вывода требуется, чтобы длина записи была указана в виде единиц хранения файла, которые могут не быть байтами, хотя там, где это целесообразно, рекомендуется использовать 8-битный октет. Для форматированного ввода-вывода даже это не годится. [@Тим] - person francescalus; 10.05.2017
comment
Процитируем стандарт: количество битов в единице хранения файла задается константой FILE_STORAGE_SIZE (13.8.2.9), определенной во встроенном модуле ISO_FORTRAN_ENV. Рекомендуется, чтобы единицей хранения файлов был 8-битный октет, если этот выбор целесообразен. Эта рекомендация отсутствовала в стандарте до Fortran 2003, и некоторые компиляторы, такие как DEC, выбрали числовую единицу хранения в качестве единицы хранения файлов. Intel, разумеется, унаследовала это как часть приобретения команды DEC Fortran. - person Steve Lionel; 10.05.2017