数据通过 Fortran 逻辑单元在程序、设备或文件间进行传送。逻辑单元在 I/O 语句中用逻辑单元号来标识,逻辑单元号是从 0 到最大 4 字节整数值 (2,147,483,647) 的非负整数。
字符 * 可以作为逻辑单元标识符出现。当星号出现在 READ 语句中时,它代表标准输入文件;当它出现在 WRITE 或 PRINT 语句中时,则代表标准输出文件。
Fortran 逻辑单元可通过 OPEN 语句与特定的命名文件相关联。另外,在程序开始执行时,某些预连接单元会自动与特定文件相关联。
OPEN 语句的 FILE= 说明符在运行时建立逻辑单元到命名物理文件的关联。该文件可以是预先就有的,也可以由程序创建。
OPEN 语句中的 FILE= 说明符可以指定一个简单文件名 (FILE=’myfile.out’),也可以指定一个前面带有绝对或相对目录路径的文件名 (FILE=’../Amber/Qproj/myfile.out’)。另外,说明符还可以是字符常量、变量或字符表达式。
可以使用库例程将命令行参数和环境变量以字符变量形式送入程序,用作 OPEN 语句中的文件名。
以下示例 (GetFilNam.f) 展示了一种由键入的名称来构建绝对路径文件名的方法。程序使用库例程 GETENV、LNBLNK 和 GETCWD 返回 $HOME 环境变量的值,查找字符串中最后的非空格字符,确定当前工作目录:
CHARACTER F*128, FN*128, FULLNAME*128 PRINT*, ’ENTER FILE NAME:’ READ *, F FN = FULLNAME( F ) PRINT *, ’PATH IS: ’,FN END CHARACTER*128 FUNCTION FULLNAME( NAME ) CHARACTER NAME*(*), PREFIX*128 C This assumes C shell. C Leave absolute path names unchanged. C If name starts with ’~/’, replace tilde with home C directory; otherwise prefix relative path name with C path to current directory. IF ( NAME(1:1) .EQ. ’/’ ) THEN FULLNAME = NAME ELSE IF ( NAME(1:2) .EQ. ’~/’ ) THEN CALL GETENV( ’HOME’, PREFIX ) FULLNAME = PREFIX(:LNBLNK(PREFIX)) // 1 NAME(2:LNBLNK(NAME)) ELSE CALL GETCWD( PREFIX ) FULLNAME = PREFIX(:LNBLNK(PREFIX)) // 1 ’/’ // NAME(:LNBLNK(NAME)) ENDIF RETURN END |
编译并运行 GetFilNam.f,结果如下:
demo% pwd /home/users/auser/subdir demo% f95 -o getfil GetFilNam.f demo% getfil ENTER FILE NAME: getfil PATH IS: /home/users/auser/subdir/atest.f demo% |
2.1.4 向程序传递文件名中对这些例程进行了详细的介绍。有关详细信息,请参见 getarg(3F)、getcwd(3F) 和 getenv(3F) 的相应手册页条目;这些内容以及其他有用的库例程在《Fortran 库参考》中也有介绍。
OPEN 语句不需要指定名称;运行时系统会根据几个惯例提供文件名。
在 OPEN 语句中指定 STATUS=’SCRATCH’ 会打开一个名称形式为 tmp.FAAAxnnnnn 的文件,其中 nnnnn 用当前进程 ID 替换,AAA 是一个包含三个字符的字符串,x 是一个字母;AAA 和 x 可确保文件名唯一。该文件在程序终止或执行 CLOSE 语句时被删除。在 FORTRAN 77 兼容模式 (-f77) 下编译时,可以在 CLOSE 语句中指定 STATUS=’KEEP’ 来保留这个临时文件。(此为非标准扩展。)
如果文件已被程序打开,可以使用后续的 OPEN 语句更改文件的某些特性;例如 BLANK 和 FORM。此时,只需指定文件的逻辑单元号以及要更改的参数。
程序执行开始时,会自动将三个单元号与特定的标准 I/O 文件相关联。这些预连接单元是标准输入、标准输出和标准错误:
通常,标准输入是从工作站键盘接收输入;标准输出和标准错误是在工作站屏幕上显示输出。
在其他所有情况下,如果在 OPEN 语句中指定了逻辑单元号而未在 FILE= 后指定任何名称,文件将以 fort.n 形式的名称打开,其中 n 为逻辑单元号。
在假定使用缺省惯例的情况下,并非必须使用 OPEN 语句。如果逻辑单元上的第一个操作是 I/O 语句,而不是 OPEN 或 INQUIRE,则会引用文件 fort.n,其中 n 为逻辑单元号(0、5 和 6 除外,它们有特殊意义)。
这些文件无需在程序执行前就存在。如果对文件的第一个操作不是 OPEN 或 INQUIRE 语句,则会创建这些文件。
示例:以下代码中,如果 WRITE 是该单元上的第一个输入/输出操作,则会创建文件 fort.25:
demo% cat TestUnit.f IU=25 WRITE( IU, ’(I4)’ ) IU END demo% |
上述程序将打开文件 fort.25,并将一条格式化记录写入该文件:
demo% f95 -o testunit TestUnit.f demo% testunit demo% cat fort.25 25 demo% |
文件系统没有任何自动工具可将 Fortran 程序中的逻辑单元号与物理文件相关联。
但是,有几种令人满意的方式可将文件名传递给 Fortran 程序。
可以使用库例程 getarg(3F) 在运行时将命令行参数读入字符变量。参数会被解释为文件名并在 OPEN 语句的 FILE= 说明符中使用:
demo% cat testarg.f CHARACTER outfile*40 C Get first arg as output file name for unit 51 CALL getarg(1,outfile) OPEN(51,FILE=outfile) WRITE(51,*) ’Writing to file: ’, outfile END demo% f95 -o tstarg testarg.f demo% tstarg AnyFileName demo% cat AnyFileName Writing to file: AnyFileName demo% |
同样,可以使用库例程 getenv(3F) 在运行时将任何环境变量的值读入字符变量,该字符变量随后被解释为文件名:
demo% cat testenv.f CHARACTER outfile*40 C Get $OUTFILE as output file name for unit 51 CALL getenv(’OUTFILE’,outfile) OPEN(51,FILE=outfile) WRITE(51,*) ’Writing to file: ’, outfile END demo% f95 -o tstenv testenv.f demo% setenv OUTFILE EnvFileName demo% tstenv demo% cat EnvFileName Writing to file: EnvFileName demo% |
使用 getarg 或 getenv 时,应该注意前导或尾随的空格。(Fortran 95 程序可以使用内函数 TRIM 或更早的 FORTRAN 77 库例程 LNBLNK())在本章开头的示例中,可以随 FULLNAME 函数的代码行编写更加灵活的代码来接受相对路径名。
将物理文件与程序的逻辑单元号相关联的另一种方式是重定向或管道输送预连接的标准 I/O 文件。重定向或管道在运行时执行命令中使用。
采用这种方式,读取标准输入(单元 5)和写入标准输出(单元 6)或标准错误(单元 0)的程序可以通过重定向(在命令行中使用 <、>、>>、>&、|、|&、2>、2>&1),读取或写入其他任何命名文件。
参见下表:
表 2–1 csh/sh/ksh 命令行重定向和管道
操作 |
使用 C Shell |
使用 Bourne 或 Korn Shell |
---|---|---|
标准输入-从 mydata 读取 |
myprog < mydata |
myprog < mydata |
标准输出-写入(覆写)myoutput |
myprog > myoutput |
myprog > myoutput |
标准输出-写入/追加至 myoutput |
myprog >> myoutput |
myprog >> myoutput |
将标准错误重定向至文件 |
myprog >& errorfile |
myprog 2> errorfile |
将标准输出通过管道输送至另一程序的输入 |
myprog1 | myprog2 |
myprog1 | myprog2 |
将标准错误和输出通过管道输送至另一程序 |
myprog1 |& myprog2 |
myprog1 2>&1 | myprog2 |
有关命令行重定向和管道的详细信息,请参见 csh、ksh 和 sh 手册页。