Fortran进行批处理的方法_第1页
Fortran进行批处理的方法_第2页
Fortran进行批处理的方法_第3页
Fortran进行批处理的方法_第4页
Fortran进行批处理的方法_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Fortran中批量处理文件的方法总结循环读取目录下的所有符合条件的文件=一、简单的介绍     在一年之前,我写过一个程序,主要是对Micaps资料进行批量处理,将逐日资料处理为旬、月的数据,在那个程序中,始终有一个问题困扰我,就是如何自动生成该读取的下一个文件名,这使我真正开始关注fortran中的批处理,时隔一年,决定写下这些文字,将我用到的一些fortran批处理的方法和大家共享,交流。     对于那些只要会用程序,不求其中原理的朋友,请马上跳过这些文字,直接去下载附件吧!程序里有使用说明,但是,如果你不懂原理,估计现成的程

2、序你使用起来也会碰壁哦!     这里所说的批处理是指对某一个目录下的指定后缀的文件的批量读取和处理。     我总结的批处理方法大概可以用下面这个示意图来说明: | | |将文件目录写入一个文本文件,供fortran循环读取 |手动输入文件名 |运行程序之前命令行工具导出文件名 |程序运行后,未开始计算之前,生成文件名 |         调用CMD命令生成 |   

3、0;     GETFILEINFOQQ方法生成 |         调用WIN32API生成 | |在程序运行时动态生成文件名 | |        对于第一种方法,我将主要介绍如何将目录写入文件,然后举出一个小的示例来验证。第二种方法主要是说明其思路。 二、方法的介绍 1、  将文件目录写入一个文本文件,供fortran循环读取 1.1、

4、60;    手动输入文件名这是最基本的方法啦,如果文件个数不多,而且文件名中包含了空格等特殊字符的话,建议使用这种方法,在这里就不多说啦,至于在fortran中的处理,等几个小方法介绍完之后会有一个例子来说明。 1.2、     运行程序之前命令行工具导出文件名    这是一个既高效又保险的方法,主要思路就是通过强大的CMD命令列出目录下的文件到一个指定的文件中,然后由fortran去循环读取该文件中的文件名信息,从而批量处理。     a、 从运行工具

5、打开你的CMD窗口;     b、转到要处理的当前目录(可省略):CD /d 路径,如:     CD /d  e:test      这样可以快速到达e:test目录     c、 使用DIR命令列出文件目录信息到指定的文件,通常使用的     Dir  *.*>新文件名  这个命令在这里已经不能满足要求,因为会列出一堆对于我们处理而言无用的信息,现

6、在要使用的命令是:     DIR  /b  filter>newfile     注意,其中的filter为文件筛选,必须自己修改为所需的,比如你可以把它改成*.txt,这样,就会列出当前目录下的所有txt结尾的文件了。 Newfile就是你需要存放文件名的那个文件,比如可以是 dir.txt,这样就成了  dir /b*.txt>dir.txt,就会把当前目录下的所有文件都列出到dir.txt文件中,当然,由于dir.txt也在当前目录,所以也会被算

7、进去,这在处理的时候是需要注意的,下面几种方法中同样考虑了这个问题。你可以选择手动删掉,或者把dir.txt这个文件存到其他地方去,或者,不要和你需要的文件具有相同的后缀也行,比如:dir /b *.txt>e:dir.txt  (假设当前目录是e:test)    如果省略了第二步中的转到当前目录的话,就需要在dir命令后输入完整的路径了,而且新生成的文件也要选择有权限建立新文件的地方存放,比如你在c:users目录下输入:dir /b e:test*.txt>e:dir.txt,这个命令和上面先转到e:test目录下的效果是一样的。

8、60;    现在你是不是比较好奇,/b 是干嘛的,其实就是只列出文件名,不要其他的附件信息,比如创建时间,文件大小等等这些对于我们批处理无关的信息。     如果你想包含某个目录下的子目录,那么,就可以这样写: Dir /b/s filter>newfile    /s就表示包含子目录,但是,这样会有一个问题,那就是,批处理的时候必须获得正确的路径才能操作,这样得到的子目录里面的文件不会有任何标志说他是来自子目录的,因此fortran处理的时候就无法判断了,所以,如果包含了子目录,那么请用下面的命

9、令: Dir /a-d/b/s filter>newfile    现在去看看新生成的文件吧,怎么样,很惊喜吧!     懂了这个方法,下面一部分的第一个方法对你来说就是小菜一碟啦。     如果你使用的win7(或vista)系统,而且无法正常使用CVF编译器的话,那么第一部分到这里就算结束啦,除非,你会在其他fortran编译器中调用WIN32API。 1.3、程序运行后,未开始计算之前生成文件名 1.3.1、在程序中调用CMD命令    

10、60;   这个方法其实就是上一个方法的进化版,只不过变成了在程序运行的时候调用命令自动生成,这样整个过程显得少一点,只需要在程序里设置好相关的参数即可。        这个方法的关键在于SYSTEMQQ函数的使用,这是CVF编译器封装的调用CMD命令的一个函数,存在于DFLIB库中,其语法命令为:     result = SYSTEMQQ(commandline)      commandline:表示需要进行的CMD操作,字符串形式,函数中

11、的实际长度由传入的参数决定,input类型(表示输入为参数);     Results:一个逻辑型变量(logical(4)),如果成功为true,失败为false(不解的是程序中要实现的东西都是正常的,比如仅仅传入dir命令,返回的结果仍然为F,请高手赐教) 给出一个简单的例子: USE DFLIB LOGICAL(4)resultresult = SYSTEMQQ('copy e:dir.txt e:testdir.txt')    这个命令将第一个路径中的文件复制到为第二个路径中的文件。通过这

12、个例子再结合上面一个方法,就可以很方法便的构造出我们需要用来批处理的子函数,关键语句如下所示:subroutine ListToFile(fPath,outPut)character*(*),InTent(In): fPath,outPut  character*100CMD  LOGICAL(4) res  CMD="dir/a-d/b/s "/trim(fPath)/" >"/trim(outPut)res=SYSTEMQQ(CMD)endsubroutine  

13、     其中传入的是文件筛选值和输出的路径,这个方法也是我在第一部分中最为推荐的一个方法了,代码简洁高效,能够输出完整的路径,可以包含子文件夹,唯一的缺点就是输出的文件个数不能直接在程序中调用(方便循环),需要在批处理的时候使用其他方法来判断文件是否读取结束。 1.3.2、使用GETFILEINFOQQ方法生成文件目录       该方法是下面一个方法的进化版,是由CVF对WIN32的API进行了封装,这样,我们就可以通过简单的调用函数来实现一些面向对象的功能。简单的翻译了一下官方给出的GET

14、FILEINFOQQ函数信息:Module: USE DFLIB (存在于DFLIB库中)语法简介:Syntax result = GETFILEINFOQQ (files, buffer, handle) files :输入类型的字符型变量,表示你需要查找的路径(也就是我们上面方法中的筛选值),同样可以使用*或者?这样的通配符。 buffer :在函数运行中会获得一个值,可供输出使用,这个值就是所找到的文件的相关信息,属于FILE$INFO类型的变量(该类型定义于:fortran安装路径DF98INCLUDE路径下),其结构如下:T

15、YPE FILE$INFO  INTEGER(4)CREATION    INTEGER(4)LASTWRITE    INTEGER(4)LASTACCESS    INTEGER(4)LENGTH    INTEGER(4)PERMIT    CHARACTER(255)NAMEEND TYPE FILE$INFO handle :接受输入和输出整型变量

16、,表示文件控制信息(同样在DFLIB中定义),包含以下内容:FILE$FIRST - First matching file found.FILE$LAST - Previous file was the last valid file.FILE$ERROR - No matching file found.Results: 返回值是一个整型变量(integer(4)),表示的不含空格的文件名长度,如果文件未找到,则返回0。     了解了以上信息,我们就可以通过编程进行循环调用这个函数,每找到一个符合条件的文件,就把他输入到指定路径的文件中去,注意,凡

17、是input类型的变量都必须传入数值,否则会出错。 如果你比较有探索精神,就试着用这个介绍和思路来编程一下吧,子程序如下所示(完整的请下载附件)Subroutine GetFileList(cFileName,outPut,iFile)    UseDFLib,only:GetFileInfoQQ,GetLastErrorQQ,FILE$INFO,FILE$LAST,FILE$ERROR,FILE$FIRST,ERR$NOMEM,ERR$NOENT,FILE$DIR    !引入库函数Implicit None!根据上面的语

18、法介绍来定义变量Character*(*),Intent(In):cFileName !筛选值character*(*),intent(In):output  !输出路径Integer,Intent(InOut):iFile   !记录已经找到几个文件TYPE (FILE$INFO) info  !找到的文件的信息INTEGER(4):Wildhandle,length  !文件控制信息,文件大小,Wildhandle = FILE$FIRSTiFile = 0  DOWHILE (.TRUE.

19、)  !循环找文件     length = GetFileInfoQQ(cFileName,info,Wildhandle)  !调用函数找文件!如果遇到错误或者不能再找到不同的文件,则进入选择,准备退出     IF (Wildhandle .EQ. FILE$LAST) .OR.(Wildhandle .EQ. FILE$ERROR) THEN        SELECT CASE (GetLastErrorQ

20、Q()                   CASE (ERR$NOMEM)  !/内存不足         iFile = - 1         Return       CASE (ERR$NOENT)  !/碰到通配符序列尾,正常退出    

21、     Return       CASE DEFAULT         iFile = 0         Return        END SELECT     END IF              

22、;iFile= iFile + 1       Call WriteFileName( Trim(info.Name) ,outPut, iFile)  !调用子函数输出文件名  ENDDOEnd Subroutine GetFileList     注意,在调用子函数输出文件名时,要做一些处理,主要是判断文件是否存在(不存在则新建,如果是第一次找到,而且文件存在,则覆盖,否则追加),以及找到的是否为我们自己建立的这个dir.txt文件(如果是,则忽略,找到的文件数量-1) 

23、   这个方法也不错,如果不需要子目录的信息,其优越性不亚于上一种方法,因为该子函数能够直接返回找到的文件数量。 1.3.3调用WIN32API生成目录下的文件信息       有了上面的几种方法,其实这个方法可以不需要介绍,但是也许有和我一样喜欢刨根问底的朋友,还是贴出来,也算是分享一下CVF平台下对于API的调用方法。fortran的最大强项是数值计算,他本身对于各种系统信息的处理功能实在不敢说好,如果要实现一些交互的功能目前来说还是比较复杂的。    该方法直接调用系统的API函数来实现功能,理论上

24、只要是fortran编译器支持API调用,就可以使用该方法,也就是说可以用于win7和vista(linux的不在本次讨论范围,上面的几种方法思路在linux均需要变换才能使用)。目前我还没有测试在MPF4.0等其他的编译器中使用API函数的情况,感兴趣的测试后不要忘了来分享啊v。     该方法主要使用了一下三个系统函数:FindFirstFile,FindNextFile和FindClose,这三个函数存在于系统的Kernel32.dll函数中,因此调用之前需要先引用这个函数库。简单给出这三个函数的介绍:HRESULT FindFirstFile( 

25、      in,string   LPCWSTR                    wsSearchFile       out           LPWIN32_FIND_DATAW   pFindFileData     

26、60; out           LPHANDLE           pSearchHandle       );wsSearchFile:字符串类型的变量,也就是上面说的筛选值,       pFindFileData,表示所找到的文件的信息,类似上面方法中的那个FILE$INFO类型,也是在函数调用过程中生成信息,他的类型就是WIN32_FIND_D

27、ATA(一个结构体,在fortran中使用TYPE定义)。pSearchHandle:这是一个表示文件地址的变量,类似于我们用OPEN命令打开一个文件时,前面给一个unit的意思,他可以用在后面的FindNextFile和FindClose函数中。该函数的返回值为0表示文件未找到。 HRESULT FindNextFile(       in       HANDLE               hSear

28、chHandle       out    LPWIN32_FIND_DATAW    pFindFileData       );    该函数可以用上面所获得HANDLE句柄来查找下一个符合条件的文件,函数运行过程中同样给pFindFileData生成了相关信息,文件名就从其中获取。返回值同FindFirstFile。 HRESULT FindClose(       in   &#

29、160;   HANDLE       hSearchHandle       );    根据上面的文件句柄关闭文件,返回值同上。 有了对这三个函数的了解,接下来的事情就是如何使用这三个函数了,给出关键的子程序并作说明:subroutine FindName(FileExt,outFile,iFile)  Usekernel32  !载入函数库integer,parameter:maxlen=80  ! 设置一个文

30、件名长度的阈值CHARACTER*(*)    FileExt,OutFile  !筛选值和目标路径Integer(4)    hFind,res  !文件句柄和返回值integer(4),intent(inout):iFile  !已找到的文件个数(不含dir.txt)Type(t_WIN32_FIND_DATA) FindFileData !系统定义的一个结构体信息,具体的可以自行查阅WIN32API手册character*maxlen cname ! 这个变量用来存放获得的文件名,长度为上

31、面所设定的,不宜太长 res=1iFile=0   hFind = FindFirstFile(FileExt,FindFileData)  !找第一个文件   If(hFind = INVALID_HANDLE_VALUE)then         Return ! 没有找到匹配文件,返回结果=-1       else          

32、60;      !继续循环寻找下一个         do while(res)           iFile=iFile+1           !先把已有的写入文件                 cname=F

33、indFileData.cFileName                     !这一段代码很特殊,主要是因为调用API之后,默认的文件名长度非常之长,用常用的trim()函数无法缩短,因为文件名后面并不是空格,而是一个值为0的ASCII字符,因此用循环将这个字符替换为空格,以便于后面的处理,这也是上面说阈值不宜过大的愿意,否则浪费时间             

34、  do i=1,maxlen                  if(ichar(cname(i:i)=0) cname(i:i)=' '                enddo              callWriteFileName(trim

35、(cname),outFile,iFile) !调用子函数写出文件名              res=FindNextFile(hFind,FindFileData)        继续查找下一个,用res的值来控制循环是否退出         enddo         res=FindClose(hFind)&#

36、160;     !退出循环后关闭文件       endifendsubroutine     肿么样,API函数看下来是否有点晕晕的,能看到这里相信你对fortran的理解又加深了一些吧。该方法和上一种方法如出一辙,优缺点也近乎相同,同样没有包含子目录(你有兴趣的话可以试试能否使用FindFileData里面的信息让这个子程序包含子目录,如果有了结果,同样不要忘了来分享哦)。     总结一下上面的几种方法,手工输入适用于文件比较少,而且路径比较复杂的时候;使用

37、dir命令几乎可以通吃,但是无法直接给出文件数目;PI函数功能较为一般,但是可以直接获得找到的文件个数,而且通过writefile子函数的处理,可以让dir.txt直接存在于当前目录下但不包含在本身的文件列表中。选哪一种,完全看你的需要和喜好啦!     一个小小的例子(使用SYSTEMQQ实现):在当前目录下有 1.txt4.txt这样4个文本文件(注意路径以及文件名中不要有空格,否则fortran中就得按字符读取了),分别存放一个数字:1,2,3,4,要求循环读取这些文件中的数字,并且相加,给出最终的和,程序如下:program listfilecharacter*100 fPathcharacter*200 pathcharacter*7 outPutinteger a,bb=0fPath="*.txt"outPut="dir.txt"call ListToFile(fPath,outPut)  !先生

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论