IO list-directed dan namelist

Masukan dan keluaran list-directed dengan format asterisk serta kelompok data bernama melalui namelist.

Daftar isi

Pernyataan masukan dan keluaran dengan format asterisk, yang disebut list-directed I/O, adalah bentuk paling ringkas untuk membaca dan menulis data dalam Fortran. Sifat ringkas itu berasal dari cara kerjanya, yaitu kompiler menentukan lebar medan dan bentuk setiap nilai berdasarkan tipe datanya tanpa deskripsi format dari penulis program. Topik ini membahas cara kerja keluaran list-directed pada pernyataan print dan write, aturan repeat count pada daftar masukan beserta jebakannya pada daftar keluaran, pembacaan data dari berkas internal (internal file), serta kelompok data bernama melalui pernyataan namelist. Setiap mekanisme didemonstrasikan dengan program utuh yang dikompilasi dan dijalankan dengan gfortran, sehingga setiap blok keluaran pada topik ini merupakan hasil eksekusi nyata dan dapat diuji ulang dari direktori topik masing-masing.

Keluaran list-directed dengan format asterisk#

Pada keluaran list-directed, penanda format pada pernyataan write atau print diganti tanda asterisk. Kompiler memeriksa tipe setiap item pada daftar keluaran, memilih lebar medan yang sesuai, dan menyisipkan spasi pemisah antarnilai tanpa perlu campur tangan penulis program. Program berikut menampilkan larik suhu dan beberapa konstanta bertipe berbeda, membuat berkas sensor.txt yang berisi satu rekaman data, membaca kembali berkas itu, lalu menguji pembacaan dari berkas internal.

fortran list-directed.f90
program list_directed
  implicit none
  integer :: unit
  real :: suhu(3)
  integer :: kode_sensor
  real :: tekanan
  integer :: nomor
  real :: kadar
  character(len=32) :: baris

  suhu = [24.5, 25.0, 23.75]

  print *, "Suhu tercatat:", suhu
  print *, 42, 3.14, .true.

  ! JEBAKAN: pada daftar output, 3*24.5 hanyalah perkalian biasa
  print *, "3*24.5 pada daftar output :", 3*24.5

  ! program membuat berkas datanya sendiri sebelum membacanya
  ! nilai array ditulis dengan menyebut nama array-nya saja
  open (newunit=unit, file="sensor.txt", status="replace", action="write")
  write (unit, *) 101, suhu, 1013.25
  close (unit)

  open (newunit=unit, file="sensor.txt", status="old", action="read")
  read (unit, *) kode_sensor, suhu, tekanan
  close (unit)

  print *, "Kode sensor:", kode_sensor
  print *, "Suhu       :", suhu
  print *, "Tekanan    :", tekanan

  ! repeat-count 3*24.5 HANYA sah pada daftar INPUT list-directed
  baris = "102 3*24.5 1013.25"
  read (baris, *) kode_sensor, suhu, tekanan
  print *, "Repeat-count pada input :", kode_sensor, suhu, tekanan

  baris = "7 9.5"
  read (baris, *) nomor, kadar
  print *, "Internal file:", nomor, kadar
end program list_directed
bash
# mengompilasi program dari direktori topik
gfortran list-directed.f90 -o list-directed
# menjalankan program
./list-directed
text Keluaran
 Suhu tercatat:   24.5000000       25.0000000       23.7500000    
          42   3.14000010     T
 3*24.5 pada daftar output :   73.5000000    
 Kode sensor:         101
 Suhu       :   24.5000000       25.0000000       23.7500000    
 Tekanan    :   1013.25000    
 Repeat-count pada input :         102   24.5000000       24.5000000       24.5000000       1013.25000    
 Internal file:           7   9.50000000    

Keluaran tersebut memperlihatkan konvensi yang berlaku pada keluaran list-directed gfortran. String dicetak tanpa tanda kutip, bilangan bulat dicetak rata kanan pada medan yang lebarnya ditentukan kompiler, dan setiap bilangan real presisi tunggal dicetak dengan sekitar sembilan angka signifikan, misalnya 24.5000000. Nilai 3.14000010 pada baris kedua perlu penjelasan tersendiri, karena bilangan 3.14 tidak dapat diwakili dengan tepat dalam biner presisi tunggal sehingga sisa pembulatan representasinya ikut tercetak. Nilai logis .true. dicetak sebagai satu huruf T, dan tiga elemen larik suhu ditulis berurutan hanya dengan menyebut nama lariknya.

Repeat count pada masukan dan jebakannya pada keluaran#

Bentuk r*nilai pada daftar masukan list-directed disebut repeat count, yakni pengulangan satu nilai sebanyak r kali. Baris data 102 3*24.5 1013.25 mengandung lima nilai meskipun penulisannya hanya terdiri atas tiga bagian, karena 3*24.5 mengisi tiga item berurutan dengan nilai 24.5. Pada baris keluaran Repeat-count pada input, kelima item masukan, yaitu kode_sensor, ketiga elemen suhu, dan tekanan, terisi penuh dari pembacaan baris itu. Bentuk ini berguna untuk data yang banyak elemennya bernilai sama, misalnya baris pengukuran yang elemen-elemen kosongnya diisi nilai pengganti yang sama.

Bentuk yang sama tidak memiliki makna pengulangan pada daftar keluaran. Baris keluaran 3*24.5 pada daftar output : 73.5000000 menunjukkan akibatnya, yaitu kompiler mengevaluasi 3*24.5 sebagai perkalian biasa dan mencetak satu nilai 73.5. Karena bentuknya sah secara sintaks, tidak ada pesan error yang muncul, dan kesalahan jenis ini baru terlihat ketika data yang ditulis tidak sesuai harapan. Cara yang benar untuk menulis tiga nilai yang sama adalah menyebut item satu per satu atau menulis nama lariknya, sebagaimana pernyataan write pada program di atas yang menulis 101, suhu, 1013.25 menjadi lima nilai dalam satu rekaman.

Berkas internal untuk membaca dari string#

Berkas internal (internal file) adalah variabel karakter yang berperan sebagai rekaman bagi pernyataan read, sehingga teks yang sudah berada di memori dapat diurai dengan aturan masukan list-directed yang sama seperti saat membaca berkas biasa. Program di atas memuat baris 102 3*24.5 1013.25 ke dalam variabel baris, kemudian pernyataan read (baris, *) menguraikannya menjadi lima item sekaligus. Mekanisme yang sama mengisi nomor dan kadar dari string 7 9.5, dan keluaran Internal file: 7 9.50000000 membuktikan pengisiannya.

Berkas internal praktis ketika sebuah baris perlu dibaca sebagai teks terlebih dahulu, misalnya untuk memeriksa tanda khusus pada awal baris sebelum barisnya diurai sebagai data. Pola kerjanya terdiri atas dua langkah, yaitu membaca satu rekaman berkas dengan format "(A)" ke variabel karakter, lalu mengurai variabel karakter itu dengan read list-directed. Dengan pemisahan dua langkah ini, baris yang tidak sesuai pola dapat diperiksa dan dilewati tanpa mengganggu posisi pembacaan pada berkas utamanya, karena setiap langkah tetap membaca tepat satu rekaman.

Kelompok data bernama dengan namelist#

Kelompok namelist adalah deklarasi yang memberi nama pada sekumpulan variabel agar semuanya dapat ditulis dan dibaca sekaligus dengan menyebut nama kelompoknya. Deklarasi namelist /konfigurasi/ lokasi, jumlah_sensor, ambang pada program berikut membentuk kelompok bernama konfigurasi, yang kemudian ditulis ke berkas dengan penanda nml=konfigurasi dan dibaca kembali dengan penanda yang sama. Program ini menulis berkas konfigurasi.nml, menampilkan isinya baris demi baris, mengosongkan ketiga variabel anggotanya, lalu mengisi ulang semuanya dari berkas yang sama.

fortran namelist.f90
program demo_namelist
  implicit none
  character(len=24) :: lokasi
  integer :: jumlah_sensor
  real :: ambang(4)
  integer :: unit
  integer :: status
  character(len=80) :: baris
  namelist /konfigurasi/ lokasi, jumlah_sensor, ambang

  lokasi = "Stasiun Bandung"
  jumlah_sensor = 3
  ambang = [25.0, 30.0, 27.5, 40.0]

  open (newunit=unit, file="konfigurasi.nml", status="replace", action="write")
  write (unit, nml=konfigurasi)
  close (unit)

  ! menampilkan isi berkas namelist persis seperti yang tertulis
  open (newunit=unit, file="konfigurasi.nml", status="old", action="read")
  do
     read (unit, "(A)", iostat=status) baris
     if (status /= 0) exit
     print "(A)", trim(baris)
  end do
  close (unit)

  ! mengosongkan nilai, lalu membaca kelompok namelist kembali
  lokasi = ""
  jumlah_sensor = 0
  ambang = 0.0
  open (newunit=unit, file="konfigurasi.nml", status="old", action="read")
  read (unit, nml=konfigurasi)
  close (unit)

  print *, "Dibaca kembali:", trim(lokasi), jumlah_sensor, ambang
end program demo_namelist
bash
# mengompilasi program dari direktori topik
gfortran namelist.f90 -o namelist
# menjalankan program
./namelist
text Keluaran
&KONFIGURASI
 LOKASI="Stasiun Bandung         ",
 JUMLAH_SENSOR=3          ,
 AMBANG=  25.0000000    ,  30.0000000    ,  27.5000000    ,  40.0000000    ,
 /
 Dibaca kembali:Stasiun Bandung           3   25.0000000       30.0000000       27.5000000       40.0000000    

Berkas konfigurasi.nml berformat teks dan dapat disunting dengan editor biasa. Header &KONFIGURASI membuka kelompok, setiap variabel ditulis dengan namanya beserta nilainya, dan tanda garis miring menutup kelompok. Berbeda dengan keluaran list-directed pada bagian sebelumnya, string pada keluaran namelist ditulis dalam tanda kutip dan diberi spasi pengisi sampai panjang deklarasi variabelnya, yaitu 24 karakter untuk lokasi. Pembacaan kembali mengisi variabel berdasarkan nama, bukan berdasarkan posisi, sehingga urutan penulisan variabel di dalam berkas boleh berbeda dari urutan deklarasinya dan variabel anggota yang tidak disebut di dalam berkas tetap mempertahankan nilainya. Sifat ini menjadikan namelist pilihan yang lazim untuk berkas konfigurasi program ilmiah.

Kesalahan umum#

Kesalahan pertama adalah memasang repeat count pada daftar keluaran dengan harapan nilai terulang. Perbaikannya sama dengan yang dijelaskan pada bagian repeat count di atas, yaitu menyebut item satu per satu atau menulis nama lariknya pada pernyataan write. Kesalahan ini tidak memunculkan pesan error, sehingga hasil cetaknya perlu dibandingkan dengan data yang dimaksud, bukan cukup diverifikasi berhasilnya kompilasi.

Kesalahan kedua adalah mencantumkan item masukan yang tipenya tidak cocok dengan datanya, misalnya membaca teks abc ke dalam variabel bertipe integer. Pernyataan read tanpa penanda iostat menghentikan program saat berjalan, sedangkan dengan iostat=status kegagalan tersebut dapat ditangani oleh program sendiri dan baris data yang bermasalah dapat dilaporkan. Pola penanganan dengan iostat dan iomsg dibahas lebih lanjut pada topik berkas dan unit di modul ini.

Kesalahan ketiga pada namelist adalah membaca kelompok yang namanya atau variabelnya tidak terdapat dalam deklarasi. Pembacaan berakhir dengan error karena sistem waktu berjalan (runtime) kompiler mencocokkan header berkas dengan nama kelompok yang diminta pada pernyataan read. Pastikan header berkas, misalnya &KONFIGURASI, sama dengan nama kelompok pada deklarasi, dan setiap variabel yang ditulis di dalam berkas sudah menjadi anggota kelompok tersebut.

Ringkasan#

  • Format asterisk membuat kompiler menentukan lebar medan dari tipe setiap item, sehingga print *, suhu menulis seluruh elemen larik tanpa deskripsi format.
  • Repeat count r*nilai mengisi r item berurutan dan hanya sah pada daftar masukan, sedangkan pada daftar keluaran 3*24.5 dievaluasi sebagai perkalian.
  • Berkas internal memungkinkan string karakter diurai dengan aturan masukan list-directed melalui read (baris, *).
  • Kelompok namelist menulis dan membaca sekumpulan variabel berdasarkan nama, sehingga cocok untuk berkas konfigurasi yang disunting manusia.

Referensi#