2

フォーマットされたASCIIファイルを読んでいます。このファイルは基本的にASCIIでエンコードされており、次のようになります。

fieldname 1
header info 1
header info 2
header info 3
aruieopaurjjk&*(^0uio3789$
#$adsfhoueraeiknvaer93-8(&897klfaicvnjai9ea890 34
*(()kla3j90ajkl4a8 ...

fieldname 2
header info 1
header info 2
header info 3
8&80973jknaua890a3a()Ujkl;fjaoi0()8&*(&jla;f)*(
jkl;aje()()78907jkoja0988093jn890&*(4fakoa343a
...

したがって、ファイルはASCIIですが、人間が読める形式ではありません。レコード長に一貫性がありません。ファイルポインタがの直前にあると仮定して、データを読み取るルーチンがありますfieldname。フィールド名が必要なものであることを確認し、データを返すそのフィールドを読み取り/デコードします。フィールドが必要なものでない場合は、次のようになるまで行を読み取ります。fieldnameライン。ご想像のとおり、これはひどく非効率的です。最後のフィールドを読み取るには、基本的に1つおきのフィールドを順番に読み取る必要があります。また、順不同で読んだ場合は、ファイル全体を巻き戻してやり直す必要があります。私がやりたいのは、フィールド名をファイルの先頭からのバイトオフセットにマップできるようにインデックスを作成することです。そうすれば、ファイル内の適切な場所を「シーク」して、フォーマットされたシーケンシャルファイルとして読み続けることができます...

次の方法でファイルを読み取ることができるソリューションに満足しています。

read(iu,'(A)',end=190) mystring  !get from current position to end of line
read(iu,*,end=190) myint1,myint2 !read two integers
read(iu,'(a,i8,3e14.7,i8,a)',end=190, err=900) !read a string, 8 character wide integer ...

おそらく、ある種の最適化されたgetline機能とストリームアクセスを備えたソリューションを使用することもできます。次に、上記をgetlineの呼び出しに置き換えてから、返される文字列を読み取ることができます...

私はこの投稿を見てきましたが、私の質問はもう少し一般的です(その投稿には行番号が必要でした。バイトオフセットが必要です)。これは、ストリームアクセスとpos指定子を使用した魔法で実現できるようですが、リーダーを完全に書き直す必要があるかどうかはわかりません(リーダーがどのように作成されるかわからないため、ほぼ不可能です。一見ランダムに見える文字列を実際にfloatに変換します)。

4

1 に答える 1

4

フォーマットされたストリームアクセス(Fortran 2003標準で導入)を使用すると、以前に読み取られたファイル内の位置を探すことができます。フォーマットされたストリームにはまだレコードベースのアプローチ(正式にはレコード区切り文字として改行を使用)があるため、フォーマットされたシーケンシャルアクセスに使用されたものと同じコードを再利用できることがよくあります。

INQUIREステートメントを使用して現在のファイル位置を取得します。

INTEGER :: file_pos
INQUIRE(UNIT=iu, POS=file_pos)

各行を含むレコードを読み取る前に、この方法でINQUIREを呼び出し、fieldnameそのレコードを読み取り、そのレコードのフィールド名を判別し、後で検索できるようにフィールド名とファイル位置を配列などに格納できます。

前進しないREADを使用して、以前に保存された位置に再配置できます。

READ (iu,"()", ADVANCE='NO', POS=file_pos)

後続のREADステートメントは、再配置されたレコードに初めて遭遇する順次フォーマットされたファイルの場合と同じように続行されます。

于 2012-08-02T21:07:59.720 に答える