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.