Čtení tabulek a obrázků

Zajímavá aplikace modulů a polí je při práci s tabulkami a obrázky. Problém je podobně řešitelný v různých jazicích. Zde si ukážeme čtení datového souboru (databáze) ve fortranu. Cvičně si zvolíme soubor s následující strukturou:

Tabulka 8. Struktura databazové tabulky

Část souboruÚdajdélka
Hlavičkadélka v x10 znaků
Hlavičkadélka v y10 znaků
Hlavičkakometář40 znaků
Datazáznamy10 čísel na radek

každý záznam v tomhle souboru obsahuje 10 čísel na řádek. To znamená, že bez ohledu na délku v X nebo Y čteme pořád 10 číselné záznamy.


program pokus1

! mozne naivni reseni

integer :: nx,ny
character(len=40) :: com
real,allocatable :: data(:,:)

read(*,"(3I10,I40)") nx,ny,com
allocate(data(nx,ny))

do
  read(*,*,end=220) data(?????)
enddo
220 continue
end

Problem je s indexováním pole data. Jistě by šlo nejakým strašně složitým způsobem přetrasfomovávat indexy. Jiné řešení by bylo pomocí standardní funkce pack namapovat matici do vektoru a pak číst z něj. Ovšem existuje podstatně elegantnejší řešení.


Module databaze

character(len=40), private :: com = ' '
integer, private :: nx=0,ny=0
real, private, allocatable :: data(:,:)
logical :: databuf
private :: readdata

contains

subroutine opendb(unit,name)

integer :: unit
character(len=*) :: name

open(unit,file=name,status='old')
read(*,"(3I10,I40)") nx,ny,com
allocate(data(nx,ny))
databuf = .false.

end subroutine

subroutine getxy(nx1,nx2)

integer :: nx1,ny1

nx1 = nx
ny1 = ny
end subroutine

function readdb(unit,i,j)
integer :: unit,i,j
real :: readdb

if( .not. databuf ) then
  call readdata(unit,i,j)
  databuf = .true.
endif
readdb = data(i,j)
end function  

subroutine readdata(unit,x,y,data)

integer :: unit, i, x, y
real :: data(:)

i = 1 
do while ( i ≤ (nx*ny)/10 + 1)
  read(unit,*) data(i:i+80)
  i = i + 1
enddo

end subroutine

subroutine closedb(unit)

integer ::: unit

close(unit)
nx = 0
ny = 0
com = ' '
deallocate(data)
end subroutine

end module

Program pokus2

use database

! lepsi reseni nacitani

integer nx,ny

call opendb(1,"databaze.dat")
call getxy(nx,ny)
write(*,*) "posledni prvek =",readdb(1,nx,ny)
if( status /= 0 ) stop 'Error while data read.'
closedb(1)
end program

Vypadá to uměle a složitě, ale v případě použití složitho souboru to velmi usnadní práci a čtení. Kromě toho je přesně s tímhle stylem definován astronomický FITS formát a programováno čtení a psaní do souboru v Unixu. Je totiž méně HW náročné načíst najednou 1kB z disku a pak z něj postupně číst, když je potřeba než provádět operace po bytech.