Rekaman terformat versus tak terformat

Perbedaan rekaman terformat yang mudah dibaca dan rekaman tak terformat yang ringkas untuk data numerik.

Daftar isi

Setiap pernyataan write ke berkas menghasilkan satu rekaman (record), dan bentuk rekaman itu ditentukan oleh penanda form= pada pernyataan open. Rekaman terformat (formatted) menyimpan setiap nilai sebagai teks yang mengikuti spesifikasi format, sedangkan rekaman tak terformat (unformatted) menyalin representasi memori nilai apa adanya. Topik ini membandingkan keduanya pada data numerik yang sama, mencakup ukuran berkas hasilnya, kecepatan dan ketepatan pembacaan kembali, serta penanda rekaman yang mengapit data pada berkas tak terformat. Satu program menulis seribu nilai real ke kedua bentuk berkas, membacanya kembali, dan membandingkan ukurannya, dengan seluruh keluaran diambil dari eksekusi nyata gfortran.

Rekaman terformat: setiap nilai menjadi teks#

Pada berkas terformat, setiap nilai diubah menjadi rangkaian karakter sesuai deskriptor format sebagaimana dibahas pada topik deskriptor edit format. Program berikut menulis seribu nilai 0.1 * i satu per satu dengan deskriptor E24.14, sehingga setiap rekaman berisi satu nilai dalam notasi eksponensial berlebar 24 karakter. Hasilnya adalah berkas teks yang dapat dibuka dengan editor mana pun, dapat diperiksa isinya secara langsung, dan tetap dapat dibaca program lain tanpa mengetahui bahasa pemrograman yang menulisnya.

Sifat portabel tersebut menjadi kekuatan utama rekaman terformat. Isinya tidak bergantung pada representasi internal komputer karena setiap nilai sudah menjadi teks, sehingga berkas yang ditulis di satu mesin dapat dibaca di mesin lain dengan kompiler berbeda. Harga yang dibayar adalah ukuran berkas dan waktu proses, karena setiap nilai real presisi tunggal memerlukan sekitar dua puluh karakter padahal di memori nilainya hanya membutuhkan empat byte, dan konversi teks harus dilakukan dua arah saat menulis dan saat membaca.

Rekaman tak terformat: representasi memori apa adanya#

Pada berkas tak terformat, penanda form="unformatted" menyatakan bahwa write menyalin byte internal nilai tanpa konversi ke teks. Seribu nilai real presisi tunggal ditulis dengan satu pernyataan write (unit) data_uji tanpa perulangan elemen satu per satu, dan hasilnya berukuran jauh lebih kecil karena setiap nilai hanya membutuhkan empat byte. Penulisan dan pembacaannya juga lebih cepat karena tidak ada pengubahan format sama sekali, sehingga bentuk ini menjadi pilihan lazim untuk berkas antara (intermediate file) dan data numerik berukuran besar pada perhitungan ilmiah.

Konsekuensinya ada pada keterbacaan dan portabilitas. Isi berkasnya tidak dapat dibaca manusia, dan representasi internalnya bergantung pada arsitektur, termasuk urutan byte (endianness) dan panjang penanda rekaman yang mengapit datanya. Program contoh pada bagian berikutnya menulis dan membaca kedua bentuk berkas pada mesin yang sama, sehingga perbandingan ukuran dan ketepatan keduanya dapat diamati langsung dari keluarannya.

Program perbandingan dan keluarannya#

fortran terformat.f90
program terformat_biner
  implicit none
  integer, parameter :: n = 1000
  real :: data_uji(n)
  real :: baca_terformat(n)
  real :: baca_biner(n)
  integer :: unit
  integer :: i
  integer :: ukuran_teks
  integer :: ukuran_biner

  do i = 1, n
     data_uji(i) = 0.1 * real(i)
  end do

  ! rekaman terformat: setiap nilai diubah menjadi teks
  open (newunit=unit, file="data-terformat.txt", status="replace", action="write")
  do i = 1, n
     write (unit, "(E24.14)") data_uji(i)
  end do
  close (unit)

  ! rekaman tak terformat: representasi memori ditulis apa adanya
  open (newunit=unit, file="data-biner.bin", form="unformatted", status="replace", &
        action="write")
  write (unit) data_uji
  close (unit)

  ! membaca kembali kedua berkas dan memverifikasi isinya
  open (newunit=unit, file="data-terformat.txt", status="old", action="read")
  do i = 1, n
     read (unit, "(E24.14)") baca_terformat(i)
  end do
  close (unit)

  open (newunit=unit, file="data-biner.bin", form="unformatted", status="old", &
        action="read")
  read (unit) baca_biner
  close (unit)

  print *, "Elemen      1 :", data_uji(1), baca_terformat(1), baca_biner(1)
  print *, "Elemen   1000 :", data_uji(n), baca_terformat(n), baca_biner(n)
  print *, "Selisih maksimum terformat :", maxval(abs(data_uji - baca_terformat))
  print *, "Selisih maksimum biner     :", maxval(abs(data_uji - baca_biner))

  ! membandingkan ukuran kedua berkas hasil penulisan
  inquire (file="data-terformat.txt", size=ukuran_teks)
  inquire (file="data-biner.bin", size=ukuran_biner)
  print *, "Ukuran berkas terformat (byte) :", ukuran_teks
  print *, "Ukuran berkas biner (byte)     :", ukuran_biner
end program terformat_biner
bash
# mengompilasi program dari direktori topik
gfortran terformat.f90 -o terformat
# menjalankan program
./terformat
text Keluaran
 Elemen      1 :  0.100000001      0.100000001      0.100000001    
 Elemen   1000 :   100.000000       100.000000       100.000000    
 Selisih maksimum terformat :   0.00000000    
 Selisih maksimum biner     :   0.00000000    
 Ukuran berkas terformat (byte) :       25000
 Ukuran berkas biner (byte)     :        4008

Keluaran memperlihatkan bahwa kedua jalur pembacaan kembali menghasilkan nilai yang identik dengan nilai asalnya, ditandai selisih maksimum nol pada keduanya. Ketepatan jalur terformat bukan kebetulan, karena deskriptor E24.14 mencetak empat belas angka di belakang titik, sedangkan real presisi tunggal hanya menyimpan sekitar sembilan angka signifikan, sehingga tidak ada informasi yang hilang ketika nilai ditulis dan dibaca kembali. Bila deskriptornya disempit, misalnya E12.4, jalur terformat justru kehilangan ketepatan, sedangkan jalur tak terformat tetap utuh karena nilainya tidak pernah dikonversi ke teks.

Perbedaan ukurannya mencolok, yaitu 25000 byte berbanding 4008 byte untuk data yang sama. Berkas terformat membutuhkan 25 byte per rekaman, yakni 24 karakter medan E24.14 ditambah satu penanda akhir baris, sedangkan berkas tak terformat menyimpan seribu nilai menjadi 4000 byte data. Sisa 8 byte pada berkas biner berasal dari penanda pembuka dan penutup rekaman yang dijelaskan pada bagian berikutnya.

Penanda rekaman dan perhitungan ukuran#

Berkas tak terformat akses berurutan menyisipkan penanda rekaman (record marker) di awal dan akhir setiap rekaman, yaitu bilangan bulat yang menyatakan panjang rekamannya. Perintah berikut menampilkan dua baris pertama berkas terformat dan 16 byte pertama berkas biner hasil program di atas untuk membuktikan strukturnya.

bash
# menampilkan dua baris pertama berkas terformat
head -2 data-terformat.txt
# menampilkan 16 byte pertama berkas tak terformat
od -A d -t x1 -N 16 data-biner.bin
text Keluaran
    0.10000000149012E+00
    0.20000000298023E+00
0000000 a0 0f 00 00 cd cc cc 3d cd cc 4c 3e 9a 99 99 3e
0000016

Empat byte pertama berkas biner terbaca a0 0f 00 00, yang dalam urutan byte kecil (little-endian) bernilai 4000, tepat sebesar 1000 elemen dikali 4 byte. Nilai inilah yang ditulis oleh penanda pembuka rekaman gfortran, dan penanda penutup yang senilai dengannya menyusul di akhir rekaman sehingga total berkas menjadi 4008 byte. Empat byte berikutnya, cd cc cc 3d, adalah representasi memori 0.1 dalam real presisi tunggal, diikuti cd cc 4c 3e untuk 0.2. Sementara itu, dua baris pertama berkas terformat menunjukkan nilai yang sama dalam bentuk teks 0.10000000149012E+00 berlebar 24 karakter. Perbandingan ini memperlihatkan perbedaan ukuran per nilai, yaitu 4 byte memori berbanding 25 byte teks per rekaman.

Struktur penanda ini sekaligus menjelaskan mengapa berkas tak terformat tidak portabel lintas kompiler. Panjang penandanya ditentukan implementasi, dan penanda tersebut membuat read tanpa format dapat memverifikasi panjang rekaman yang dibaca. Berkasnya hanya dijamin terbaca kembali oleh kompiler yang sama pada arsitektur yang sama, sedangkan pertukaran berkas antar mesin memerlukan konversi eksplisit.

Kapan memilih rekaman tak terformat#

Tabel berikut merangkum pertimbangan pemilihan bentuk rekaman untuk data numerik.

AspekTerformatTak terformat
Keterbacaan manusiaDapat dibaca dan disunting editor teksTidak dapat dibaca manusia
Ukuran berkasBesar, sekitar 25 byte per real presisi tunggal pada contoh iniKecil, 4 byte per real presisi tunggal
KecepatanLebih lambat karena konversi teks dua arahLebih cepat karena penyalinan memori
KetepatanBergantung pada jumlah digit deskriptorIdentik dengan nilai di memori
PortabilitasAman lintas mesin dan kompilerTerikat kompiler dan arsitektur yang sama

Pilihan yang lazim adalah rekaman terformat untuk hasil akhir yang dibaca manusia atau dibagikan ke program lain, sedangkan rekaman tak terformat untuk berkas antara (intermediate file) antartahap perhitungan dan arsip data berukuran besar yang hanya dibaca kembali oleh program yang sama. Program ilmiah berukuran besar umumnya menggunakan keduanya sekaligus, yaitu data mentah ditulis tak terformat demi kecepatan, lalu ringkasannya ditulis terformat demi keterbacaan.

Kesalahan umum#

Kesalahan pertama adalah membaca berkas tak terformat dengan pernyataan terformat atau sebaliknya. Struktur rekamannya berbeda sehingga pembacaan berakhir dengan error atau menghasilkan nilai yang tidak bermakna, dan penyebabnya sering kali berupa kelalaian menuliskan form="unformatted" pada open saat membaca berkas tak terformat. Pastikan nilai form= pada pernyataan open pembaca sama dengan pernyataan penulisnya.

Kesalahan kedua adalah menganggap berkas tak terformat portabel. Urutan byte berbeda antar arsitektur, dan panjang penanda rekaman berbeda antar kompiler, sehingga berkas yang dipindahkan antar mesin perlu dikonversi terlebih dahulu. Kesalahan ketiga adalah mempercayai deskriptor terformat yang sempit. Bila deskriptor E12.4 digunakan pada data serupa, sebagian angka signifikan hilang karena pembulatan sehingga selisih maksimum pada keluaran program tidak lagi nol. Aturan praktisnya adalah memeriksa ketepatan tulis-baca ulang dengan membandingkan nilai asal dan nilai bacaan, persis seperti yang dilakukan program contoh pada topik ini.

Ringkasan#

  • Rekaman terformat menyimpan nilai sebagai teks sesuai deskriptor sehingga portabel, sedangkan rekaman tak terformat menyalin representasi memori sehingga ringkas dan cepat.
  • Pada contoh seribu real presisi tunggal, berkas terformat berukuran 25000 byte dan berkas tak terformat 4008 byte, dengan selisih pembacaan nol pada keduanya karena E24.14 memuat lebih banyak digit daripada yang disimpan real presisi tunggal.
  • Berkas tak terformat akses berurutan diapit penanda rekaman berisi panjang rekaman, pada gfortran berukuran 4 byte, sehingga 4000 byte data menjadi 4008 byte berkas.
  • Rekaman tak terformat hanya portabel pada kompiler dan arsitektur yang sama, sedangkan rekaman terformat aman dipindahkan antar mesin.

Referensi#