Skip to content

5. Files and paths ​

The table is in a file, data/cars.csv, whose name report now takes from the command line:

year, make, model, price, notes
1997, Ford, E350, 3000.00, ac abs moon
1999, Chevy, Venture, 4900.50, extended edition
2001, Fiat, Punto, 2500, a small city car with a low fuel consumption and a surprisingly large boot

The pieces of a path ​

f90
print '(A)', 'directory: '//input%basedir()
print '(A)', 'file:      '//input%basename()
print '(A)', 'extension: '//input%extension()
output = input%basename(strip_last_extension=.true.)//'.md'
print '(A,L2)', 'a CSV file:', input%match('*.csv')  ! a wildcard pattern

basedir, basename and extension take a path apart. basename can also drop the last extension: this is how report names its output after its input. match compares the whole string with a wildcard pattern, * any sequence of characters, ? one character, [...] a character of a set; glob uses the same patterns to list the files that match.

Reading ​

f90
call read_file(file=input%chars(), lines=rows)    ! one string for each line
print '(I0,A)', size(rows), ' rows read from '//input

read_file reads the whole file and allocates one string for each line, each of its own length. It takes the name of the file as a character: input%chars().

Writing ​

f90
allocate(table(size(rows) + 1))
do r = 1, size(rows)
  call rows(r)%split(tokens=cells, sep=',')
  cells = cells%strip()
  table(merge(1, r + 1, r == 1)) = '| '//glue%join(array=cells(1:4), sep=' | ')//' |'
enddo
table(2) = '|---|---|---|---|'
call write_file(file=output%chars(), lines=table)
print '(A)', 'table written to '//output

Each row is split, cleaned and joined again as a row of a Markdown table; write_file writes an array of strings, one for each line.

Running it ​

$ report data/cars.csv
directory: data
file:      cars.csv
extension: .csv
a CSV file: T
4 rows read from data/cars.csv
table written to cars.md
$ cat cars.md
| year | make | model | price |
|---|---|---|---|
| 1997 | Ford | E350 | 3000.00 |
| 1999 | Chevy | Venture | 4900.50 |
| 2001 | Fiat | Punto | 2500 |

The whole program:

f90
program report
!< Tutorial, chapter 5: files and paths.
use stringifor
implicit none
type(string)              :: input, output, glue
type(string), allocatable :: rows(:), cells(:), table(:)
character(256)            :: argument
integer                   :: r

call get_command_argument(1, argument)
input = trim(argument)

print '(A)', 'directory: '//input%basedir()
print '(A)', 'file:      '//input%basename()
print '(A)', 'extension: '//input%extension()
output = input%basename(strip_last_extension=.true.)//'.md'
print '(A,L2)', 'a CSV file:', input%match('*.csv')  ! a wildcard pattern

call read_file(file=input%chars(), lines=rows)    ! one string for each line
print '(I0,A)', size(rows), ' rows read from '//input

allocate(table(size(rows) + 1))
do r = 1, size(rows)
  call rows(r)%split(tokens=cells, sep=',')
  cells = cells%strip()
  table(merge(1, r + 1, r == 1)) = '| '//glue%join(array=cells(1:4), sep=' | ')//' |'
enddo
table(2) = '|---|---|---|---|'
call write_file(file=output%chars(), lines=table)
print '(A)', 'table written to '//output
endprogram report

What you learned

read_file and write_file for whole files; basedir, basename, extension for the paths; match for wildcard patterns. Reference: Files and Paths.

Next: 6. A polished report.