सबसे तेज़ तरीका एक उद्देश्य-निर्मित कार्यक्रम है, जैसे:
#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;
}
कैश की परवाह किए बिना अपने परीक्षण से, मैंने इनमें से प्रत्येक के बारे में 50 बार एक ही डायरेक्टरी के खिलाफ, ओवर-ओवर, कैश-आधारित डेटा तिरछा से बचने के लिए दौड़ाया, और मुझे निम्नलिखित प्रदर्शन संख्याएँ (वास्तविक घड़ी समय में) मिलीं:
ls -1 | wc - 0:01.67
ls -f1 | wc - 0:00.14
find | wc - 0:00.22
dircnt | wc - 0:00.04
यह आखिरी है, dircnt
उपरोक्त स्रोत से संकलित कार्यक्रम है।
EDIT 2016-09-26
लोकप्रिय मांग के कारण, मैंने इस कार्यक्रम को पुनरावर्ती होने के लिए फिर से लिखा है, इसलिए यह उपनिर्देशिकाओं में छोड़ देगा और फ़ाइलों और निर्देशिकाओं को अलग-अलग गिनना जारी रखेगा।
चूंकि यह स्पष्ट है कि कुछ लोग यह जानना चाहते हैं कि यह सब कैसे करना है, इसलिए मुझे यह स्पष्ट करने के लिए कोड में बहुत सारी टिप्पणियाँ हैं कि यह क्या हो रहा है। मैंने इसे लिखा और 64-बिट लिनक्स पर इसका परीक्षण किया, लेकिन इसे माइक्रोसॉफ्ट विंडोज सहित किसी भी POSIX-compliant सिस्टम पर काम करना चाहिए । बग रिपोर्ट का स्वागत है; यदि आप इसे अपने AIX या OS / 400 या जो भी काम नहीं कर सकते हैं, तो मैं इसे अपडेट करके खुश हूं।
जैसा कि आप देख सकते हैं, यह मूल की तुलना में बहुत अधिक जटिल है और आवश्यक रूप से ऐसा है: कम से कम एक फ़ंक्शन को पुनरावर्ती रूप से कहा जाना चाहिए जब तक कि आप कोड बहुत जटिल नहीं बनना चाहते (जैसे कि एक उपनिर्देशिका स्टैक का प्रबंधन और एक ही लूप में प्रसंस्करण)। चूंकि हमें फ़ाइल प्रकारों की जांच करनी है, विभिन्न ओएस, मानक पुस्तकालयों, आदि के बीच अंतर खेलने में आता है, इसलिए मैंने एक कार्यक्रम लिखा है जो किसी भी प्रणाली पर प्रयोग करने योग्य होने की कोशिश करता है जहां यह संकलित होगा।
जाँच में बहुत कम त्रुटि है, और count
फ़ंक्शन स्वयं त्रुटियों की रिपोर्ट नहीं करता है। केवल वही कॉल जो वास्तव में विफल हो सकते हैं opendir
और stat
(यदि आप भाग्यशाली नहीं हैं और एक सिस्टम है dirent
जिसमें फ़ाइल प्रकार पहले से मौजूद है)। मैं उप-पथ पथनाम की कुल लंबाई की जाँच करने के बारे में पागल नहीं हूं, लेकिन सैद्धांतिक रूप से, सिस्टम को किसी भी पथ के नाम की अनुमति नहीं देनी चाहिए जो उससे अधिक लंबा है PATH_MAX
। यदि चिंताएं हैं, तो मैं इसे ठीक कर सकता हूं, लेकिन यह सिर्फ और अधिक कोड है जिसे सी लिखने के लिए सीखने वाले किसी व्यक्ति को समझाया जाना चाहिए। इस कार्यक्रम का एक उदाहरण है कि कैसे उपनिर्देशिका में पुनरावृत्ति करना है।
#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
मैंने @FlyingCodeMonkey द्वारा सुझाए गए दो परिवर्तनों को शामिल किया है:
- के
lstat
बजाय का उपयोग करें stat
। यह प्रोग्राम के व्यवहार को बदल देगा यदि आपके पास जिस निर्देशिका में आप स्कैन कर रहे हैं उसमें सहानुभूति निर्देशिका है। पिछला व्यवहार यह था कि (लिंक किया हुआ) उपनिर्देशिका में इसकी फ़ाइल गणना समग्र गणना में जोड़ी जाएगी; नया व्यवहार यह है कि लिंक की गई निर्देशिका एक ही फ़ाइल के रूप में गिनेगी, और इसकी सामग्री को नहीं गिना जाएगा।
- यदि किसी फ़ाइल का पथ बहुत लंबा है, तो एक त्रुटि संदेश उत्सर्जित हो जाएगा और प्रोग्राम बंद हो जाएगा।
EDIT 2017-06-29
किसी भी भाग्य के साथ, यह इस उत्तर का अंतिम संपादन होगा :)
मैंने इस कोड को एक GitHub रिपॉजिटरी में कॉपी कर लिया है ताकि कोड प्राप्त करने के लिए इसे थोड़ा आसान बनाया जा सके (कॉपी / पेस्ट के बजाय, आप बस स्रोत डाउनलोड कर सकते हैं ), और इसके अलावा किसी को भी एक पुल सबमिट करके संशोधन का सुझाव देना आसान हो जाता है GitHub से -request।
स्रोत अपाचे लाइसेंस 2.0 के तहत उपलब्ध है। पैच * आपका स्वागत है!
- "पैच" वह है जो मेरे जैसे पुराने लोग "पुल अनुरोध" कहते हैं।