Direktori

Menelusuri isi direktori dengan opendir dan readdir, menyaring entri, serta menggunakan glob untuk pola nama berkas.

Daftar isi

Topik ini membahas penelusuran isi direktori, yaitu memperoleh daftar berkas di dalam sebuah direktori dengan opendir dan readdir, menyaring entri yang tidak diinginkan, mengurutkan hasilnya, dan mencari berkas berdasarkan pola nama dengan glob. Setelah seluruh contoh diikuti, skrip dapat menginventarisasi isi direktori arsip secara deterministik, yaitu menghasilkan urutan yang sama pada setiap penjalanan.

Menelusuri isi direktori dengan opendir#

Membaca isi direktori mengikuti pola yang sama dengan membaca berkas, yaitu membuka, membaca, kemudian menutup. Fungsi opendir menghubungkan sebuah handle direktori dengan jalur direktori, dan mengembalikan nilai salah bila jalurnya tidak ada atau bukan direktori, sehingga disiplin or die tetap digunakan pada pembukaannya. Fungsi readdir mengembalikan isi direktori, dan bila dipanggil dalam konteks daftar, satu pemanggilan mengembalikan seluruh entri sekaligus dalam bentuk array nama. Fungsi closedir melepaskan handle direktorinya setelah selesai.

Dua entri khusus selalu ikut dalam hasil readdir, yaitu . yang menunjuk direktori itu sendiri dan .. yang menunjuk direktori induknya. Kedua entri ini bukan berkas dan tidak berguna bagi daftar inventaris, sehingga keduanya lazim disaring sebelum hasilnya diproses. Nama entri yang dikembalikan hanya nama dasar tanpa jalur induk, sehingga pemanggilan berikutnya pada berkas tersebut perlu menyambung jalur direktorinya kembali.

Selain dalam konteks daftar, readdir dapat dipanggil di dalam perulangan untuk mengembalikan satu entri pada setiap putaran. Bentuk perulangan ini hemat memori pada direktori yang sangat besar, karena seluruh daftarnya tidak perlu ditampung sekaligus, dan menjadi tempat yang tepat untuk memasang penjaga penyaringan entri khusus. Untuk daftar inventaris biasa, konteks daftar lebih ringkas, karena pemisahan, penyaringan, dan pengurutan dikerjakan pada satu array.

Menyaring dan mengurutkan entri#

Urutan keluaran readdir ditentukan oleh sistem berkas dan tidak dapat diandalkan, sehingga hasilnya dapat berbeda antar sistem, antar media penyimpanan, bahkan antar penjalanan pada kasus tertentu. Daftar entri karenanya selalu diurutkan dengan sort sebelum ditampilkan, dan penyaringan entri . serta .. dikerjakan dengan grep pada satu ekspresi yang sama.

Skrip berikut menyiapkan direktori contoh berisi tiga berkas, menelusuri isinya, menyaring entri khusus, mengurutkan sisanya, lalu menampilkannya:

perl daftar-direktori.pl
#!/usr/bin/perl
use strict;
use warnings;

my $dir = 'arsip-catatan';

# menyiapkan direktori contoh beserta isinya
if (not -d $dir) {
    mkdir $dir, 0755 or die "Tidak dapat membuat direktori $dir: $!";
}

for my $nama ('catatan-01.txt', 'catatan-02.txt', 'cadangan.zip') {
    open(my $fh, '>', "$dir/$nama")
        or die "Tidak dapat membuat $dir/$nama: $!";
    print $fh "isi $nama\n";
    close($fh);
}

# menelusuri isi direktori dengan opendir dan readdir
opendir(my $dh, $dir) or die "Tidak dapat membuka direktori $dir: $!";
my @entri = readdir($dh);
closedir($dh);

# menyaring entri khusus, lalu mengurutkan sisanya
my @berkas = sort(grep { $_ ne '.' and $_ ne '..' } @entri);

print "Jumlah entri berkas: ", scalar(@berkas), "\n";
print "- $_\n" for @berkas;
text Keluaran
Jumlah entri berkas: 3
- cadangan.zip
- catatan-01.txt
- catatan-02.txt

Ekspresi grep { $_ ne '.' and $_ ne '..' } @entri menyisakan hanya entri yang bukan . dan bukan .., kemudian sort menyusun sisanya menurut abjad. Keluaran memuat tiga entri sesuai jumlah berkas yang disiapkan, dan urutannya tetap sama pada setiap penjalanan. Pola saring lalu urutkan ini adalah bentuk baku penelusuran direktori di Perl.

Pengurutan tanpa blok perbandingan mengikuti urutan karakter pada string, sehingga penomoran dengan lebar tetap, seperti catatan-01 dan catatan-02, menghasilkan urutan angka yang benar pada saat diurutkan secara abjad. Kebiasaan menomori arsip dengan lebar yang tetap karenanya mempermudah penelusuran, sedangkan bila urutan lain diinginkan, sort dapat menerima blok perbandingan tersendiri.

Mencari berkas dengan pola menggunakan glob#

Fungsi glob mengembalikan daftar jalur yang cocok dengan pola nama berkas, dengan aturan pola yang akrab bagi pengguna shell, yaitu * untuk sebaran karakter apa pun dan ? untuk satu karakter. Berbeda dari readdir yang mengembalikan nama dasar saja, glob mengembalikan jalur lengkap mengikuti pola yang diberikan, sehingga hasilnya langsung dapat dibuka dengan open. Fungsi ini cocok bila yang dicari adalah sebagian berkas dengan ciri nama yang sama, misalnya hanya berkas log berakhiran .txt.

Skrip berikut menyiapkan direktori contoh berisi tiga berkas log dan satu berkas CSV, kemudian mengambil hanya berkas yang berakhiran .txt dan mengurutkan hasilnya:

perl cari-dengan-glob.pl
#!/usr/bin/perl
use strict;
use warnings;

my $dir = 'log-sensor';

# menyiapkan direktori contoh beserta isinya
if (not -d $dir) {
    mkdir $dir, 0755 or die "Tidak dapat membuat direktori $dir: $!";
}

for my $nama ('log-05-06.txt', 'log-05-07.txt', 'log-05-08.txt', 'ringkasan.csv') {
    open(my $fh, '>', "$dir/$nama")
        or die "Tidak dapat membuat $dir/$nama: $!";
    print $fh "data $nama\n";
    close($fh);
}

# hanya berkas dengan akhiran .txt yang diambil, lalu diurutkan
my @berkas_txt = sort(glob("$dir/*.txt"));

print "Berkas yang cocok dengan pola *.txt:\n";
print "- $_\n" for @berkas_txt;
text Keluaran
Berkas yang cocok dengan pola *.txt:
- log-sensor/log-05-06.txt
- log-sensor/log-05-07.txt
- log-sensor/log-05-08.txt

Berkas ringkasan.csv tidak muncul karena tidak cocok dengan pola *.txt, dan setiap hasilnya membawa awalan direktorinya. Pengurutan tetap dipasang meskipun glob pada banyak sistem sudah mengembalikan hasil terurut, karena perilaku itu bukan jaminan dan sort menghilangkan keraguan tersebut dengan biaya yang kecil.

Pola lain mengikuti aturan yang sama, yaitu log-05-0?.txt mencakup log-05-06.txt sampai log-05-09.txt dengan satu tanda ?, sedangkan beberapa pola dalam satu pemanggilan dipisah spasi dan hasil gabungannya tetap diurutkan dengan sort. Pemilihan antara keduanya mengikuti kebutuhan, yaitu readdir untuk seluruh isi direktori dan glob untuk sebagian berkas yang dicocokkan menurut pola.

Kesalahan umum#

Kesalahan pertama adalah membiarkan entri . dan .. lolos ke dalam pemrosesan. Selain memuat entri tak berguna pada daftar, kedua entri ini membuat penelusuran rekursif menunjuk direktori itu sendiri dan induknya terus-menerus, sehingga perulangannya tidak pernah berhenti. Penjaga sederhananya diletakkan di awal blok perulangan:

perl Penjaga terhadap entri khusus di dalam perulangan
# tidak-dijalankan
while (my $entri = readdir($dh)) {
    next if $entri eq '.' or $entri eq '..';
    # memproses $entri setelah entri khusus terlewati
}

Kesalahan kedua adalah mengandalkan urutan asli readdir tanpa sort. Program yang tampak benar pada satu komputer dapat menghasilkan urutan berbeda pada komputer lain, dan perbandingan antar penjalanan menjadi sulit dilakukan. Panggil sort sebelum daftarnya digunakan.

Kesalahan ketiga adalah menyusun pola glob dari jalur yang mungkin mengandung spasi. Spasi di dalam pola dianggap pemisah antarpola, sehingga glob("$dir/*.txt") dengan $dir berisi data arsip mencari di dua tempat yang salah sekaligus. Gunakan opendir dan readdir bila jalur direktorinya tidak dapat dipastikan bebas spasi.

Ringkasan#

  • opendir, readdir, dan closedir menelusuri isi direktori dengan pola buka, baca, tutup yang sama seperti pada berkas.
  • Entri . dan .. selalu muncul dalam hasil readdir dan disaring dengan grep, sedangkan sort membuat urutan keluaran deterministik.
  • glob("$dir/*.txt") mengembalikan jalur berkas yang cocok dengan pola, lengkap dengan awalan direktorinya, dan tetap diurutkan sebelum digunakan.
  • Nama direktori yang mengandung spasi lebih aman ditelusuri dengan opendir dan readdir daripada dengan pola glob.

Referensi#