Проверьте, существует ли каталог или нет
Я пытаюсь проверить, что каталог существует с помощью Fortan90. На разных сайтах я нашел:
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
Тем не мение, inquire
возвращается False
существует ли каталог и если я выполню этот код дважды, я получу сообщение об ошибке
невозможно создать каталог, файл уже существует
Если я использую:
inquire(file='./docs/test', exist=dir_e)
с существующим файлом теста, inquire
возвращается true
,
Как я могу проверить наличие каталога? Я использую Ubuntu 11.04 и компилятор ifort.
7 ответов
Следующее должно работать:
INQUIRE (DIRECTORY=dir, EXIST=ex [, DIRSPEC=dirspec] [, ERR=label] [, IOSTAT=i-var] )
У меня нет ifort на этой машине, поэтому я не могу проверить это.
Приложение: Размещенный код изначально работает с gfortran. DIRECTORY
Оператор работает с ifort, но не с gfortran.
А в случае получения дополнительной информации проверьте: http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/fortran/win/compiler_f/lref_for/source_files/rfinquir.htm
Стандарты Fortran 95, 2003 и 2008 не указывают, как справки должны обращаться с каталогами. Из моего опыта работы с Linux gfortran рассматривает их как файлы, а ifort - нет. Оператор каталога является частной функцией ifort, и поэтому его следует избегать.
Самым безопасным будет проверить файл в указанном каталоге.
Большую часть времени проверяют, существует ли каталог, чтобы что-то в нем записать. Я просто создаю каталог. Если он уже существует, проблем нет.
CALL system("mkdir video")
CALL chdir("video")
CALL getcwd(path)
Вы можете использовать подпрограммы C для проверки файлов:
C сторона (хорошо с ifort и gfortran на Win32 и 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;
}
}
Фортран сторона:
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
Как использовать в рутине Фортрана:
..
use file
use iso_c_binding
...
integer(c_int) :: mode,exist,time
...
call file_info("./docs"//char(0),mode,exist,time)
Преимущество: он работает с любым типом файлов и предоставляет дополнительную информацию, такую как режим (разрешение на чтение / запись / выполнение) и время создания.
Вот подпрограмма, которую я часто использую - она использует условие, о котором вы спрашивали:
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
В зависимости от того, какой компилятор вы используете, вам придется решить, какой из этих условий вам подходит.
К сожалению, у меня нет доступа к nagfor
и не знаю, как это относится к каталогам.
Другое непереносимое решение - позволить оболочке (в данном случае Bash) сделать работу:
call system('[[ ! -e docs ]] && mkdir docs')
У меня такая же проблема. Если вам нужен независимый от компилятора способ сделать это, вы можете попробовать открыть небольшой файл в каталоге. Оператор open позволяет коду переходить к определенной строке (указанной в err=), если оператор open завершается неудачно:
! 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
Обратите внимание, что это не является защитой от дурака, так как предполагается, что "dir" имеет конечный "/" или "\" в зависимости от используемой ОС.