Cara tercepat adalah program yang dibuat khusus, seperti ini:
#include <stdio.h>
#include <dirent.h>
int main(int argc, char *argv[]) {
DIR *dir;
struct dirent *ent;
long count = 0;
dir = opendir(argv[1]);
while((ent = readdir(dir)))
++count;
closedir(dir);
printf("%s contains %ld files\n", argv[1], count);
return 0;
}
Dari pengujian saya tanpa memperhatikan cache, saya menjalankan masing-masing sekitar 50 kali masing-masing terhadap direktori yang sama, berulang-ulang, untuk menghindari kemiringan data berbasis cache, dan saya mendapat kira-kira angka kinerja berikut (dalam waktu jam nyata):
ls -1 | wc - 0:01.67
ls -f1 | wc - 0:00.14
find | wc - 0:00.22
dircnt | wc - 0:00.04
Yang terakhir dircnt
,, adalah program yang disusun dari sumber di atas.
EDIT 2016-09-26
Karena banyaknya permintaan, saya menulis ulang program ini agar bersifat rekursif, sehingga akan masuk ke subdirektori dan terus menghitung file dan direktori secara terpisah.
Karena jelas beberapa orang ingin tahu bagaimana melakukan semua ini, saya punya banyak komentar dalam kode untuk mencoba memperjelas apa yang terjadi. Saya menulis ini dan mengujinya di Linux 64-bit, tetapi seharusnya bekerja pada sistem yang mendukung POSIX, termasuk Microsoft Windows. Laporan bug diterima; Saya senang memperbarui ini jika Anda tidak bisa membuatnya bekerja pada AIX atau OS / 400 Anda atau apa pun.
Seperti yang Anda lihat, ini jauh lebih rumit daripada yang asli dan tentu saja demikian: setidaknya satu fungsi harus ada untuk dipanggil secara rekursif kecuali jika Anda ingin kode menjadi sangat kompleks (misalnya mengelola tumpukan subdirektori dan memprosesnya dalam satu loop). Karena kita harus memeriksa jenis file, perbedaan antara OS yang berbeda, perpustakaan standar, dll ikut bermain, jadi saya telah menulis sebuah program yang mencoba untuk dapat digunakan pada sistem mana pun yang akan dikompilasi.
Ada sangat sedikit pengecekan kesalahan, dan count
fungsinya sendiri tidak benar-benar melaporkan kesalahan. Satu-satunya panggilan yang benar-benar dapat gagal adalah opendir
dan stat
(jika Anda tidak beruntung dan memiliki sistem di mana sudah dirent
berisi jenis file). Saya tidak paranoid tentang memeriksa panjang total nama path subdir, tetapi secara teoritis, sistem seharusnya tidak mengizinkan nama path yang lebih panjang dari pada PATH_MAX
. Jika ada masalah, saya dapat memperbaikinya, tetapi hanya kode yang perlu dijelaskan kepada seseorang yang sedang belajar menulis C. Program ini dimaksudkan untuk menjadi contoh tentang bagaimana menyelami subdirektori secara rekursif.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/stat.h>
#if defined(WIN32) || defined(_WIN32)
#define PATH_SEPARATOR '\\'
#else
#define PATH_SEPARATOR '/'
#endif
/* A custom structure to hold separate file and directory counts */
struct filecount {
long dirs;
long files;
};
/*
* counts the number of files and directories in the specified directory.
*
* path - relative pathname of a directory whose files should be counted
* counts - pointer to struct containing file/dir counts
*/
void count(char *path, struct filecount *counts) {
DIR *dir; /* dir structure we are reading */
struct dirent *ent; /* directory entry currently being processed */
char subpath[PATH_MAX]; /* buffer for building complete subdir and file names */
/* Some systems don't have dirent.d_type field; we'll have to use stat() instead */
#if !defined ( _DIRENT_HAVE_D_TYPE )
struct stat statbuf; /* buffer for stat() info */
#endif
/* fprintf(stderr, "Opening dir %s\n", path); */
dir = opendir(path);
/* opendir failed... file likely doesn't exist or isn't a directory */
if(NULL == dir) {
perror(path);
return;
}
while((ent = readdir(dir))) {
if (strlen(path) + 1 + strlen(ent->d_name) > PATH_MAX) {
fprintf(stdout, "path too long (%ld) %s%c%s", (strlen(path) + 1 + strlen(ent->d_name)), path, PATH_SEPARATOR, ent->d_name);
return;
}
/* Use dirent.d_type if present, otherwise use stat() */
#if defined ( _DIRENT_HAVE_D_TYPE )
/* fprintf(stderr, "Using dirent.d_type\n"); */
if(DT_DIR == ent->d_type) {
#else
/* fprintf(stderr, "Don't have dirent.d_type, falling back to using stat()\n"); */
sprintf(subpath, "%s%c%s", path, PATH_SEPARATOR, ent->d_name);
if(lstat(subpath, &statbuf)) {
perror(subpath);
return;
}
if(S_ISDIR(statbuf.st_mode)) {
#endif
/* Skip "." and ".." directory entries... they are not "real" directories */
if(0 == strcmp("..", ent->d_name) || 0 == strcmp(".", ent->d_name)) {
/* fprintf(stderr, "This is %s, skipping\n", ent->d_name); */
} else {
sprintf(subpath, "%s%c%s", path, PATH_SEPARATOR, ent->d_name);
counts->dirs++;
count(subpath, counts);
}
} else {
counts->files++;
}
}
/* fprintf(stderr, "Closing dir %s\n", path); */
closedir(dir);
}
int main(int argc, char *argv[]) {
struct filecount counts;
counts.files = 0;
counts.dirs = 0;
count(argv[1], &counts);
/* If we found nothing, this is probably an error which has already been printed */
if(0 < counts.files || 0 < counts.dirs) {
printf("%s contains %ld files and %ld directories\n", argv[1], counts.files, counts.dirs);
}
return 0;
}
EDIT 2017-01-17
Saya telah memasukkan dua perubahan yang disarankan oleh @FlyingCodeMonkey:
- Gunakan
lstat
sebagai ganti stat
. Ini akan mengubah perilaku program jika Anda memiliki direktori yang disinkronkan di direktori yang Anda pindai. Perilaku sebelumnya adalah bahwa subdirektori (ditautkan) akan memiliki jumlah file ditambahkan ke jumlah keseluruhan; perilaku baru adalah bahwa direktori yang ditautkan akan dihitung sebagai satu file, dan isinya tidak akan dihitung.
- Jika jalur file terlalu panjang, pesan kesalahan akan dipancarkan dan program akan berhenti.
EDIT 2017-06-29
Dengan sedikit keberuntungan, ini akan menjadi edit terakhir dari jawaban ini :)
Saya telah menyalin kode ini ke dalam repositori GitHub untuk membuatnya sedikit lebih mudah untuk mendapatkan kode (alih-alih menyalin / menempel, Anda dapat mengunduh sumbernya ), ditambah lagi membuatnya lebih mudah bagi siapa saja untuk menyarankan modifikasi dengan mengirimkan tarikan -meminta bantuan dari GitHub.
Sumber tersedia di bawah Apache License 2.0. Tambalan * selamat datang!
- "tambalan" adalah apa yang orang tua seperti saya sebut "permintaan tarik".