Degenerate Conic

Algorithms • Modern Fortran Programming • Orbital Mechanics

Oct 24, 2021

Fortran Filesystem Blues

files

One of my major pet peeves about Fortran is that it contains virtually no high-level access to the file system. The file system is one of those things that the Fortran standard pretends doesn't exist. It's one of those idiosyncratic things about the Fortran standard, like how it uses the word "processor" instead of "compiler", and doesn't acknowledge the existence of source code files so it doesn't bother to recommend a file extension for Fortran (gotta preserve that backward compatibility just in case punch cards come back).

There are various hacky workarounds to do various things that poor Fortran programmers have had to use for decades. Basically, all you have is OPEN, CLOSE, READ, WRITE, and INQUIRE. Here are a few examples:

Deleting a file

Here's a standard Fortran routine that can be used to delete a file:

function delete_file(name) result(istat)

  implicit none

  character(len=*),intent(in) :: name
  integer :: istat

  integer :: iunit

  open(newunit=iunit,status='OLD',iostat=istat)
  if (istat==0) close(iunit,status='DELETE',iostat=istat)

end function delete_file

As you can see, it's just a little trick, using a feature of CLOSE to delete a file after closing it (but first, we had to open it). Of course, note that the error codes are non-standard (the Fortran standard also doesn't consider this information important and lets the different compilers do whatever they want -- so of course, they all do something different). And of course, there is no exception handling in Fortran either (a post for another time).

Creating a directory

There is absolutely no standard ability in Fortran to create or delete a directory. Again, Fortran basically pretends that directories don't exist. Note that the Intel Fortran Compiler provides a super useful non-standard extension of the INQUIRE statement to allow it to be used to get information about directories. It's a pretty ridiculous state of affairs (Fortran added a bazillion IEEE routines in Fortran 2018 for some reason that nobody needed, but it still doesn't have something like this that everybody has needed for decades). Intel's IFPORT portability module provides many useful (non-standard) routines for accessing the file system (for example DELFILESQQ for deleting files and DELDIRQQ for deleting a directory). I use these all the time and the fact that they are non-standard and not present in other compilers is a major source of annoyance.

For some file or directory operations, you can always resort to using system calls, and thus have to provide different methods for different platforms (of course Fortran provides no standard way to get any information about the platform, so you have to resort to non-standard, possibly compiler-specific, preprocessor directives to do that). For example, to create a directory you could use:

subroutine make_directory(name)

  implicit none

  character(len=*),intent(in) :: name

  call execute_command_line ('mkdir '//name)

end subroutine make_directory

That one was easy because "mkdir" works on macOS, Window, and Linux. See previous post about getting command line calls into strings, which can also be useful for some things like this.

Getting a list of files

How about getting a list of all the files that match a specific pattern? Again, this can be done if you are using the Intel compiler using the IFPORT module GETFILEINFOQQ routine:

function get_filenames(pattern, maxlen) result(list)

  use ifport

  implicit none

  character(len=*),intent(in) :: pattern
  integer,intent(in) :: maxlen
  character(len=maxlen),dimension(:),allocatable :: list

  integer(kind=int_ptr_kind()) :: handle
  type(file$infoi8) :: info
  integer :: length

  allocate(list(0))
  handle = file$first
  do
    length = GETFILEINFOQQ(trim(pattern), info, handle)
    if ((handle==file$last) .or. (handle==file$error)) exit
    list = [list, info%name]
  end do

end function get_filenames

The file$infoi8 type is some super-weird non-standard Intel thing. Note that this example only returns the file names, not the full paths. To get the full path is left as an exercise to the reader. Also note that Fortran doesn't provide a good string class, so we just set a maximum string length as an argument to this function (but note that Intel is only returning a 255-character string anyway).

Final thoughts

There are various libraries out there that can do some of this. For example, M_system (a Fortran module interface for calling POSIX C system routines). Hopefully, a comprehensive set of filsystem routines will eventually make it into the Fortran Standard Library.

See also