如何让IFORT程序实现文件名通配符(*)展开功能?
解决Intel IFORT编译程序在Windows下不支持命令行通配符展开的问题
首先纠正你代码里的一个语法错误:open语句缺少闭合括号,正确写法是:
open(newunit=ifile, file=trim(filename))
回到通配符展开的问题,根源在于Windows默认的CMD shell不会自动展开命令行通配符,Gfortran编译的程序内部实现了通配符解析逻辑,而Intel IFORT编译的程序依赖shell处理通配符,因此可通过以下方式解决:
方法1:使用支持通配符展开的Shell运行程序
Windows下的PowerShell、Git Bash等Shell会自动解析通配符并展开为匹配的文件名列表,直接用这些Shell运行程序即可:
- PowerShell中执行:
.\readoneline.exe data*.dat - Git Bash中执行:
./readoneline.exe data*.dat
方法2:修改Fortran程序,自行实现通配符展开
如果必须在CMD下运行,可以在程序中添加通配符解析逻辑,调用Windows API来匹配文件。以下是一个简化的实现示例(支持*和?通配符):
program readoneline character(1024) :: line, filename, pattern integer :: i, nfile, ifile, status ! Windows API相关常量与类型 integer, parameter :: MAX_PATH = 260 integer, parameter :: INVALID_HANDLE_VALUE = -1 type, bind(C) :: WIN32_FIND_DATA integer(2) :: dwFileAttributes integer(8) :: ftCreationTime integer(8) :: ftLastAccessTime integer(8) :: ftLastWriteTime integer(4) :: nFileSizeHigh integer(4) :: nFileSizeLow integer(4) :: dwReserved0 integer(4) :: dwReserved1 character(MAX_PATH) :: cFileName character(14) :: cAlternateFileName end type WIN32_FIND_DATA type(WIN32_FIND_DATA) :: find_data ! 声明Windows API函数 interface function FindFirstFileA(lpFileName, lpFindFileData) bind(C, name='FindFirstFileA') import :: WIN32_FIND_DATA integer(c_intptr_t) :: FindFirstFileA character(C_CHAR), intent(in) :: lpFileName(*) type(WIN32_FIND_DATA), intent(out) :: lpFindFileData end function FindFirstFileA function FindNextFileA(hFindFile, lpFindFileData) bind(C, name='FindNextFileA') import :: WIN32_FIND_DATA integer(c_int) :: FindNextFileA integer(c_intptr_t), intent(in) :: hFindFile type(WIN32_FIND_DATA), intent(out) :: lpFindFileData end function FindNextFileA function FindClose(hFindFile) bind(C, name='FindClose') integer(c_int) :: FindClose integer(c_intptr_t), intent(in) :: hFindFile end function FindClose end interface nfile = command_argument_count() do i = 1, nfile call get_command_argument(i, pattern) pattern = trim(pattern) ! 检查参数是否包含通配符 if (index(pattern, '*') /= 0 .or. index(pattern, '?') /= 0) then ! 调用Windows API查找匹配文件 hFind = FindFirstFileA(trim(pattern)//C_NULL_CHAR, find_data) if (hFind == INVALID_HANDLE_VALUE) then print*, 'No files match pattern: ', trim(pattern) cycle end if ! 处理第一个找到的文件 call process_file(trim(find_data%cFileName)) ! 处理后续匹配文件 do win32_status = FindNextFileA(hFind, find_data) if (win32_status == 0) exit call process_file(trim(find_data%cFileName)) end do call FindClose(hFind) else ! 无通配符,直接处理文件 call process_file(pattern) end if end do contains subroutine process_file(fname) character(*), intent(in) :: fname integer :: ifile character(1024) :: line open(newunit=ifile, file=fname, status='old', iostat=status) if (status /= 0) then print*, 'Failed to open file: ', trim(fname) return end if read(ifile, '(A)') line print*, 'First line of '//trim(fname)//' is '//trim(line) close(ifile) end subroutine process_file end program readoneline
这个程序会自动识别命令行参数中的通配符,调用Windows系统接口遍历匹配文件并逐个处理;无通配符时则直接处理目标文件。
方法3:编写批处理脚本辅助展开通配符
可以写一个简单的批处理脚本(比如run.bat),利用CMD的for命令遍历匹配文件并传递给程序:
@echo off for %%f in (data*.dat) do ( readoneline.exe "%%f" )
运行这个批处理文件,CMD会自动展开data*.dat为所有匹配的文件名,并逐个传递给你的程序。
内容的提问来源于stack exchange,提问作者Michael Ou
相关产品推荐
相关产品推荐

