不在本次讨论范围,上面的几种方法思路在linux均需要变换才能使用)。目前我还没有测试在MPF4.0等其他的编译器中使用API函数的情况,感兴趣的测试后不要忘了来分享啊^v^。
该方法主要使用了一下三个系统函数:FindFirstFile,FindNextFile和
FindClose,这三个函数存在于系统的Kernel32.dll函数中,因此调用之前需要先引用这个函数库。简单给出这三个函数的介绍: HRESULT FindFirstFile(
[in,string] LPCWSTR wsSearchFile [out] LPWIN32_FIND_DATAW pFindFileData [out] LPHANDLE pSearchHandle );
wsSearchFile:字符串类型的变量,也就是上面说的筛选值, pFindFileData,表示所找到的文件的信息,类似上面方法中的那个FILE$INFO类型,也是在函数调用过程中生成信息,他的类型就是WIN32_FIND_DATA(一个结构体,在fortran中使用TYPE定义)。
pSearchHandle:这是一个表示文件地址的变量,类似于我们用OPEN命令打开一个文件时,前面给一个unit的意思,他可以用在后面的FindNextFile和FindClose函数中。
该函数的返回值为0表示文件未找到。
HRESULT FindNextFile(
[in] HANDLE hSearchHandle [out] LPWIN32_FIND_DATAW pFindFileData );
该函数可以用上面所获得HANDLE句柄来查找下一个符合条件的文件,函数运行过程中同样给pFindFileData生成了相关信息,文件名就从其中获取。返回值同FindFirstFile。
HRESULT FindClose(
[in] HANDLE hSearchHandle );
根据上面的文件句柄关闭文件,返回值同上。
有了对这三个函数的了解,接下来的事情就是如何使用这三个函数了,给出关键的子程序并作说明:
subroutine FindName(FileExt,outFile,iFile)
Usekernel32 !载入函数库
integer,parameter::maxlen=80 ! 设置一个文件名长度的阈值
CHARACTER*(*) FileExt,OutFile !筛选值和目标路径
Integer(4) hFind,res !文件句柄和返回值
integer(4),intent(inout)::iFile !已找到的文件个数(不含dir.txt)
Type(t_WIN32_FIND_DATA) FindFileData !系统定义的一个结构体信息,具体的可以自行查阅WIN32API手册
character*maxlen cname ! 这个变量用来存放获得的文件名,长度为上面所设定的,不宜太长
res=1 iFile=0
hFind = FindFirstFile(FileExt,FindFileData) !找第一个文件 If(hFind == INVALID_HANDLE_VALUE)then
Return ! 没有找到匹配文件,返回结果=-1
else
!继续循环寻找下一个 do while(res) iFile=iFile+1
!先把已有的写入文件
cname=FindFileData.cFileName
!这一段代码很特殊,主要是因为调用API之后,默认的文件名长度非常之长,用常用的trim()函数无法缩短,因为文件名后面并不是空格,而是一个值为0的ASCII字符,因此用循环将这个字符替换为空格,以便于后面的处理,这也是上面说阈值不宜过大的愿意,否则浪费时间 do i=1,maxlen
if(ichar(cname(i:i))==0) cname(i:i)=' ' enddo
callWriteFileName(trim(cname),outFile,iFile) !调用子函数写出文件名
res=FindNextFile(hFind,FindFileData) 继续查找下一个,用res的值来控制循环是否退出 enddo
res=FindClose(hFind) !退出循环后关闭文件 endif endsubroutine
肿么样,API函数看下来是否有点晕晕的,能看到这里相信你对fortran的理解又加深了一些吧。
该方法和上一种方法如出一辙,优缺点也近乎相同,同样没有包含子目录(你有兴趣的话可以试试能否使用FindFileData里面的信息让这个子程序包含子目录,如果有了结果,同样不要忘了来分享哦)。
总结一下上面的几种方法,手工输入适用于文件比较少,而且路径比较复杂的时候;使用dir命令几乎可以通吃,但是无法直接给出文件数目;PI函数功能较为一般,但是可以直接获得找到的文件个数,而且通过writefile子函数的处理,可以让dir.txt直接存在于当前目录下但不包含在本身的文件列表中。选哪一种,完全看你的需要和喜好啦!
一个小小的例子(使用SYSTEMQQ实现):在当前目录下有 1.txt…4.txt这样4个文本文件(注意路径以及文件名中不要有空格,否则fortran中就得按字符读取了),分别存放一个数字:1,2,3,4,要求循环读取这些文件中的数字,并且相加,给出最终的和,程序如下: program listfile
character*100 fPath character*200 path character*7 outPut integer a,b b=0
fPath=\ outPut=\
call ListToFile(fPath,outPut) !先生成文件列表
open(1,file='dir.txt',status='old') !打开生成的列表文件 10continue !由于不知道有多少行,所以下面使用END标签来控制文件是否结束
read(1,*,end=20)path
if(index(Path,\我生成的是绝对路径,所以,用该函数检查读取的这一行是否为文件列表本身,如果不是再往下操作 open(2,file=''//trim(Path)//'',status='old') read(2,*)a close(2) b=b+a endif goto 10
20 close(1) !文件读取结束 print*,b !输出和 end program listfile
二、运行时动态生成文件名
这个是针对具有特殊需求,或者是文件名有着非常好的规律性才这样做,比如我开始的时候说的调用MIcpasd的文件进行处理,由于需要每天都运行程序,而且每天不同时候都会有新的文件生成,显然,使用第一部分中说的方法是不合理的,工作量太大(当然,如果你愿意写一个批处理定时生成文件名也未尝不可),重要的是Micaps数据文件具有相当好的文件名格式(不是数据格式,嘿嘿),基本是按照 年月日时.时效 样的格式来生成的,因此,就可以设置某种规则来自动生成需要处理的文件名。
具体的例子就不举例了,也许以后有空会把我那个程序翻出来共享一下,主要的思路就是获取系统时间,根据时间生成这时候应该处理的文件的文件名(年月日时,时效都有,文件名就不愁啦),你可以在这次程序运行结束后,就把下次需要处理的文件名事先生成好(我就是这样做的),然后下次直接处理那些文件就行,如果遇到文件不存在等信息,最好也记录下来。
=========================================
下载附件请去:http://bbs.06climate.com/forum.php?mod=viewthread&tid=30