Test whether a directory exists or not

2020-05-27 17:58发布

问题:

I'm trying to verify that a directory exists using Fortan90. On various sites I found:

logical :: dir_e
inquire(file='./docs/.', exist=dir_e)

if ( dir_e ) then
  write(*,*) "dir exists!"
else
  ! workaround: it calls an extern program...
  call system('mkdir docs')
end if

However, inquire returns False whether or not the directory exists and if I execute this code twice, I get an error message

cannot make dir, file already exists

If I use:

inquire(file='./docs/test', exist=dir_e)

with an existing file test, inquire returns true.

How can I check for the existence of a directory? I am using ubuntu 11.04 and the ifort compiler.

回答1:

The following should work:

INQUIRE (DIRECTORY=dir, EXIST=ex [, DIRSPEC=dirspec] [, ERR=label] [, IOSTAT=i-var] )

I don't have ifort on this machine so I can't test it.

Addendum: The code posted originally works with gfortran. The DIRECTORY statement works with ifort but not with gfortran.

And in case for more information check: http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/fortran/win/compiler_f/lref_for/source_files/rfinquir.htm#rfinquir



回答2:

The Fortran standard 95, 2003 and 2008 do not specify, how inquire should treat directories. From my experience under Linux, gfortran treats them as files, ifort does not. The directory statement is a proprietary feature of ifort and should therefore be avoided.

The safest would be to test for a file in the said directory.



回答3:

Most of the time, one checks if the directory exists so to write something in it. What I do is just create the directory. If it already exists there is no problem.

     CALL system("mkdir video")
     CALL chdir("video")
     CALL getcwd(path)


回答4:

You could use C routines to test the files :

C side (OK with ifort and gfortran on Win32 and Linux 32/64)

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#if defined(_WIN32) && defined(__INTEL_COMPILER)
#  include "dirent_windows.h"
#else
#  include <dirent.h>
#endif

void file_info(const char*filename,int*mode,int*exist,int*time){
  int k;
  struct stat buf;
  k=stat(filename,&buf);
  if(k != 0) {
    *mode=0;
    *exist=0;
    *time=0;
  }else{
    *mode=buf.st_mode;
    if(*mode == 0) *exist=0; else *exist=1;
    *time=buf.st_mtime;
  }
}

Fortran side :

MODULE file

  USE iso_c_binding

  INTERFACE
    SUBROUTINE file_info(filename,mode,exist,time) BIND(C,name="file_info")
      USE iso_c_binding
      CHARACTER(kind=C_CHAR),INTENT(in) :: filename(*)
      INTEGER(C_INT),INTENT(out) :: mode,exist,time
    END SUBROUTINE
  END INTERFACE

END MODULE

How to use in a Fortran routine :

..
use file
use iso_c_binding
...
integer(c_int) :: mode,exist,time
...
call file_info("./docs"//char(0),mode,exist,time)

Advantage : it works for any kind of file and provides additional pieces of information like the mode (read/write/execute permission) and the creation time.



回答5:

Here's a subroutine I use often -- it uses the conditional you asked about:

subroutine create_directory( newDirPath )
    ! Author:  Jess Vriesema
    ! Date:    Spring 2011
    ! Purpose: Creates a directory at ./newDirPath

    implicit none

    character(len=*), intent(in) :: newDirPath
    character(len=256)           :: mkdirCmd
    logical                      :: dirExists

    ! Check if the directory exists first
!   inquire( file=trim(newDirPath)//'/.', exist=dirExists )  ! Works with gfortran, but not ifort
    inquire( directory=newDirPath, exist=dirExists )         ! Works with ifort, but not gfortran


    if (dirExists) then
!      write (*,*) "Directory already exists: '"//trim(newDirPath)//"'"
    else
        mkdirCmd = 'mkdir -p '//trim(newDirPath)
        write(*,'(a)') "Creating new directory: '"//trim(mkdirCmd)//"'"
        call system( mkdirCmd )
    endif
end subroutine create_directory

Depending on which compiler you use, you'll have to decide which of those conditionals is right for you.

Unfortunately, I do not have access to nagfor and don't know how it treats directories.



回答6:

I had the same problem. If you want a compiler independent way of doing this, you can try to open a small file within the directory. The open statement allows for the code to jump to a particular line (specified by err=) if the open statement fails:

! Tests whether the directory exists
subroutine checkdir(dir)
       implicit none
       character(len=*), intent(in) :: dir
       integer :: unitno

       ! Test whether the directory exists
       open(newunit=unitno,file=trim(dir)//'deleteme.txt',status='replace',err=1234)
       close (unitno)
       return

       ! If doesn't exist, end gracefully
1234   write(*,*) 'Data directory, '//trim(dir)//' does not exist or could not write there!'
       STOP

end subroutine

Note that this is not foolproof, as it is assumed "dir" has the trailing "/" or "\" depending on the OS being used.



回答7:

Another non-portable solution is to let the shell (Bash, in this case) do the work:

call system('[[ ! -e docs ]] && mkdir docs')