• Tidak ada hasil yang ditemukan

BAB 20 LIBRARY STRING

21.2 Model I/O Lengkap

Agar I/O lebih terkendali, kami dapat menggunakan model yang lengkap. Suatu konsep pusat dalam model ini adalah file handle, yang setara dengan stream ( FILE*) di (dalam) C, dimana menghadirkan suatu file terbuka dengan suatu posisi sekarang.

Untuk membuka suatu file, kami menggunakan fungsi io.open, yang menyerupai fungsi fopen di dalam C. Ia menerima sebagai argumentasi nama dari file untuk membuka ditambah suatu mode string. Mode string tersebut boleh berisi ` r´ untuk membaca, a ` w´ untuk menulis ( juga untuk menghapus isi file yang sebelumnya), atau ` a´ untuk menambahkan catatan, dan sebuah opsional ` b´ untuk membuka file biner. Fungsi Yang terbuka mengembalikan suatu hendle baru untuk file tersebut. Dalam hal kesalahan, open mengembalikan nol, dan suatu pemberitahu kesalahan dan suatu bilangan kesalahan:

print(io.open("non-existent file", "r"))

--> nil No such file or directory 2 print(io.open("/etc/passwd", "w"))

--> nil Permission denied 13

Penafsiran dari angka-angka kesalahan adalah bergantung sistem. Suatu idiom khas untuk melihat kemungkinan kesalahan adalah

local f = assert(io.open(filename, mode))

Jika gagal, pemberitahu kesalahan akan menyatakan argumentasi yang kedua, dan kemudian menunjukkan pesan itu.

Setelah kami membuka suatu file, kami dapat membaca atau menulis dengan metoda read/write yang serupa dengan fungsi read/write , tetapi kami memanggilnya sebagai metoda pada handle file, menggunakan tanda titik dua sintaksis. Sebagai contoh,untuk membuka suatu file dan membaca nya semua, kami dapat menggunakan suatu perintah seperti ini:

local f = assert(io.open(filename, "r")) local t = f:read("*all")

f:close()

I/O library juga menawarkan penggunaan untuk io.stdin, io.stdout, dan io.stderr yang ketiganya sudah dikenal pada C stream. Maka, kami dapat mengirimkan suatu pesan secara langsung kepada berkas kesalahan dengan suatu kode seperti ini:

io.stderr:write(message)

Kami dapat mencampur model yang lengkap dengan model yang sederhana. Kami mendapat file masukan yang sekarang digunakan dengan pemanggilan io.input(), tanpa argumentasi. Kami menata file masukan sekarang menggunakan panggilan io.input(handle). ( Panggilan yang sama juga berlaku untuk io.output.) Sebagai contoh, jika kami ingin merubah file masukan yang sekarang untuk sementara, maka kami dapat menulis seperti ini:

local temp = io.input() -- save current file io.input("newinput") -- open a new current file ... -- do something with new input

io.input():close() -- close current file

io.input(temp) -- restore previous current file

21.2.1 Suatu trik performa sederhana

Umumnya, pada Lua, lebih cepat jika membaca suatu file secara keseluruhan dibanding membacanya garis per garis. Bagaimanapun, kadang-kadang kami harus menghadapi beberapa file besar ( katakan, puluhan atau ratusan megabytes) tidak masuk akal untuk membacanya secara keseluruhan. Jika kami ingin menangani file besar dengan capaian maksimum, cara yang paling cepat adalah membacanya dalam kumpulan besar ( e.g., 8 KB utuk masing-masing kumpulan). Untuk menghindari permasalahan dalam pemotongan garis di pertengahan, kami meminta untuk membaca suatu kumpulan ditambah satu baris:

local lines, rest = f:read(BUFSIZE, "*line")

Rest variabel akan mendapatkan sisa garis yang patah oleh kumpulan itu. Kami kemudian menggabungkan kumpulan dan sisa garis ini. Dengan begitu, hasil kumpulan akan selalu pecah pada batasan-batasan garis.

Suatu contoh khas dari teknik itu adalah implementasi dari wc, suatu program untuk menghitung banyaknya karakter, kata-kata, dan garis dalam suatu file:

local BUFSIZE = 2^13 -- 8K

local f = io.input(arg[1]) -- open input file

local cc, lc, wc = 0, 0, 0 -- char, line, and word counts while true do

local lines, rest = f:read(BUFSIZE, "*line") if not lines then break end

if rest then lines = lines .. rest .. '\n' end cc = cc + string.len(lines)

-- count words in the chunk

local _,t = string.gsub(lines, "%S+", "") wc = wc + t -- count newlines in the chunk _,t = string.gsub(lines, "\n", "\n")

lc = lc + t end

print(lc, wc, cc)

21.2.2 File Binary

Model sederhana fungsi io.input dan io.output selalu membuka suatu file dalam gaya teks ( default). Pada Unix, tidak ada perbedaan antara teks dan file biner. Tetapi dalam beberapa sistem, khususnya Windows, file biner harus dibuka dengan suatu printah khusus. Untuk menangani file biner seperti itu , kami harus menggunakan io.open, dengan huruf ` b´ dalam mode string.

Data biner pada Lua ditangani dengan cara yang sama untuk teks. Suatu string pada Lua boleh berisi banyak bytes dan hampir semua fungsi pada library mampu menangani bytes yang berubah-ubah. ( kami dapat mempertemukan pola untuk data biner, sepanjang pola tidak berisi suatu byte nol. Jika kami ingin menyesuaikan byte nol, kami dapat menggunakan kelas % z sebagai gantinya.)

Secara khas, kami membaca semua data biner dengan pola *all, yang membaca keseluruhan file, atau dengan pola teladan n, yang membaca n bytes. Sebagai contoh sederhana, program berikut mengkonversi suatu file teks dari format DOS ke format Unix ( menterjemahkan urutan dari pembawaan return-newlines utnuk newlines). Disini tidak menggunakan File I/O standar ( stdin/stdout), sebab file tersebut bersikap terbuka pada gaya teks. Sebagai gantinya, mengasumsikan bahwa nama dari file masukan dan file keluaran yang diberi sebagai argumentasi program:

local inp = assert(io.open(arg[1], "rb")) local out = assert(io.open(arg[2], "wb")) local data = inp:read("*all")

data = string.gsub(data, "\r\n", "\n") out:write(data) assert(out:close())

Kami dapat memanggil program ini dengan garis perintah berikut :

> lua prog.lua file.dos file.unix

Seperti contoh yang lain , program berikut mencetak semua string temuan dalam suatu file biner. Program mengasumsikan bahwa suatu string adalah urutan zero-terminated dari enam atau lebih karakter valid, di mana suatu karakter valid adalah karakter yang diterima oleh pola validchars. Dalam contoh, ia menjadi anggota alphanumeric, pemberian tanda baca, dan karakter ruang/spasi. Kami menggunakan penggabungan dan string.rep untuk menciptakan suatu pola yang menangkap semua urutan enam atau lebih validchars. % Z pada ujung pola memenuhi byte nol pada ujung suatu string.

local f = assert(io.open(arg[1], "rb")) local data = f:read("*all")

local validchars = "[%w%p%s]"

local pattern = string.rep(validchars, 6) .. "+%z" for w in string.gfind(data, pattern) do

print(w) end

Sebagai contoh terakhir, program berikut membuat suatu tempat pembuangan dari suatu file biner. Dan argumentasi program yang pertama merupakan input nama file, keluaran menuju standar output. Program membaca file dalam kumpulan dari 10 bytes. Masing-masing kumpulan, ditulis dalam hexadecimal dari tiap byte, dan kemudian menulis kumpulan tersebut sebagai teks, mengubah karakter kendali menjadi titik.

local f = assert(io.open(arg[1], "rb")) local block = 10

while true do

local bytes = f:read(block) if not bytes then break end

for b in string.gfind(bytes, ".") do

io.write(string.format("%02X ", string.byte(b))) end

io.write(string.rep(" ", block - string.len(bytes) + 1)) io.write(string.gsub(bytes, "%c", "."), "\n")

end

Mungkin kami menyimpan program itu di dalam suatu nama file penting, jika kami menerapkan program ke dirinya sendiri, dengan panggilan :

prompt> lua vip vip

akan menghasilkan keluaran seperti(dalam unix) :

6C 6F 63 61 6C 20 66 20 3D 20 local f = 61 73 73 65 72 74 28 69 6F 2E assert(io. 6F 70 65 6E 28 61 72 67 5B 31 open(arg[1 5D 2C 20 22 72 62 22 29 29 0A ], "rb")). ... 22 25 63 22 2C 20 22 2E 22 29 "%c", ".") 2C 20 22 5C 6E 22 29 0A 65 6E , "\n").en 64 0A d.