Çok sayıda dosya için Hızlı Linux Dosya Sayısı


137

Çok sayıda dosya (> 100.000) olduğunda belirli bir dizindeki dosya sayısını bulmak için en iyi yolu bulmaya çalışıyorum.

Bu kadar çok dosya olduğunda, gerçekleştirmenin ls | wc -lyürütülmesi oldukça uzun sürer. Bunun tüm dosyaların isimlerini döndürdüğü için olduğuna inanıyorum. Mümkün olduğunca az disk IO almaya çalışıyorum.

Ben boşuna bazı kabuk ve Perl betikleri ile denedim. Herhangi bir fikir?


2
"ls" / usr / bin / ls olduğundan emin olun ve bir şey meraklısı için bir takma ad değil.
glenn jackman

Burada ilginç cevaplar ile benzer bir soru: serverfault.com/questions/205071/…
aidan

Bu soruya sunulan tüm çözümlerin Linux'a özgü olmadığını , ancak tüm * NIX benzeri sistemler için oldukça genel olduğunu belirtmek gerekir. Belki de "Linux" etiketini kaldırmak uygundur.
Christopher Schultz

Yanıtlar:


189

Varsayılan olarak ls, isimleri sıralar, eğer çok varsa biraz zaman alabilir. Ayrıca tüm isimler okunana ve sıralanıncaya kadar çıktı alınmayacaktır. ls -fSıralamayı kapatmak için seçeneği kullanın .

ls -f | wc -l

Not Bu da mümkün kıldığına -a, bu nedenle ., ..ile başlayan ve diğer dosyaları .sayılacaktır.


11
+1 Ve bilmem gereken her şeyi bildiğimi düşündüm ls.
mafya

5
ZOMG. 100K satırlarının sıralanması hiçbir şeydir - her dosyadaki stat()çağrıya kıyasla ls. böylece daha hızlı findçalışmaz stat().
Dummy00001

12
ls -fdeğil stat(). Ama tabii her ikisinin lsve findçağrı stat()belirli seçenekler gibi kullanıldığında ls -lveya find -mtime.
mark4o

7
Bağlam için, bu küçük bir Slicehost kutusunda 2,5 milyon jpgs saymak 1-2 dakika sürdü.
philfreo

6
Sayıya alt dizinler eklemek istiyorsanız, yapınls -fR | wc -l
Ryan Walls

62

En hızlı yol, bu gibi özel olarak tasarlanmış bir programdır:

#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;
}

Önbelleğe bakılmaksızın testlerimden, önbellek tabanlı veri çarpıklığını önlemek için her birini yaklaşık 50 kez aynı dizine karşı tekrar tekrar çalıştırdım ve kabaca aşağıdaki performans numaralarını aldım (gerçek saatte):

ls -1  | wc - 0:01.67
ls -f1 | wc - 0:00.14
find   | wc - 0:00.22
dircnt | wc - 0:00.04

Sonuncusu dircnt, yukarıdaki kaynaktan derlenen programdır.

DÜZENLE 2016-09-26

Yoğun talep nedeniyle, bu programı yinelemeli olarak yeniden yazdım, bu yüzden alt dizinlere düşecek ve dosyaları ve dizinleri ayrı olarak saymaya devam edecek.

Bazı insanlar tüm bunların nasıl yapılacağını bilmek istediği açık olduğundan, neler olduğunu açık hale getirmek için kodda bir sürü yorum var. Bunu yazdım ve 64-bit Linux üzerinde test, ama gerektiği Microsoft Windows dahil olmak üzere herhangi POSIX uyumlu sistem üzerinde çalışıyoruz. Hata raporları açıktır; AIX veya OS / 400'nizde veya başka herhangi bir şeyde çalıştıramazsanız bunu güncellemekten mutluluk duyarız.

Gördüğünüz gibi , orijinalden çok daha karmaşık ve zorunlu olarak öyle: kodun çok karmaşık hale gelmesini istemiyorsanız (örneğin bir alt dizin yığınını yönetme ve bunu tek bir döngüde işleme koyma) en az bir işlev yinelemeli olarak çağrılmalıdır. Dosya türlerini kontrol etmemiz gerektiğinden, farklı işletim sistemleri, standart kütüphaneler, vb. Arasındaki farklar devreye girer, bu yüzden derleyeceği herhangi bir sistemde kullanılabilir olmaya çalışan bir program yazdım.

Çok az hata kontrolü var ve countfonksiyonun kendisi gerçekten hataları rapor etmiyor. Gerçekten başarısız olabilen tek çağrılar opendirve stat(eğer şanslı değilseniz ve direntzaten dosya türünü içeren bir sisteminiz varsa ). Alt dizin yol adlarının toplam uzunluğunu kontrol etme konusunda paranoyak değilim, ancak teorik olarak, sistem daha uzun olan herhangi bir yol adına izin vermemelidir PATH_MAX. Endişeler varsa, bunu düzeltebilirim, ancak C yazmayı öğrenen birine açıklanması gereken sadece daha fazla kod var.

#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 tarafından önerilen iki değişiklik ekledim:

  1. Yerine lstatkullanın stat. Bu, taradığınız dizinde işaretlenmiş dizinleriniz varsa programın davranışını değiştirir. Önceki davranış, (bağlantılı) alt dizinin dosya sayısının toplam sayıya eklenmesiydi; yeni davranış, bağlantılı dizinin tek bir dosya olarak sayılması ve içeriğinin sayılmamasıdır.
  2. Bir dosyanın yolu çok uzunsa, bir hata mesajı verilir ve program durur.

DÜZENLE 2017-06-29

Herhangi bir şansla, bu cevabın son düzenlemesi olacak :)

Kodu almayı biraz daha kolaylaştırmak için bu kodu bir GitHub deposuna kopyaladım (kopyala / yapıştır yerine, sadece kaynağı indirebilirsiniz ), ayrıca herkesin bir çekme göndererek bir değişiklik önermesini kolaylaştırır GitHub'dan talep.

Kaynak Apache Lisansı 2.0 altındadır. Yamalar * hoş geldiniz!


  • "yama" benim gibi yaşlı insanların "çekme isteği" dediği şeydir.

2
Harika! Teşekkürler! Ve farkında olmayanlar için: yukarıdaki kodu terminalde tamamlayabilirsiniz: gcc -o dircnt dircnt.cve kullanım böyle./dircnt some_dir
aesede

Bunu yinelemeli yapmanın kolay bir yolu var mı?
ck_

@ck_ Elbette, bu kolayca tekrarlanabilir hale getirilebilir. Çözümle ilgili yardıma mı ihtiyacınız var, yoksa her şeyi yazmamı mı istiyorsunuz?
Christopher Schultz

1
@ChristopherSchultz, yukarıda yayınladığınız karşılaştırmalar - söz konusu dizinin büyüklüğü neydi?
Dom Vinyard

1
Bunu gerçekten Python'da kullanmak istedim, bu yüzden ffcount paketi olarak paketledim. @ChristopherSchultz kodunu sunduğunuz için teşekkür ederiz!
GjjvdBurg

35

Bulmayı denedin mi? Örneğin:

find . -name "*.ext" | wc -l

1
Bu , geçerli dizinin altındaki dosyaları yinelemeli olarak bulur.
mark4o

Sistemimde, find /usr/share | wc -l(~ 137.000 dosya) ls -R /usr/share | wc -lher birinin ilk çalışmasında (dir adları, dir toplamları ve boş satırlar dahil ~ 160.000 satır ) yaklaşık% 25 daha hızlıdır ve sonraki (önbelleğe alınmış) çalıştırmaları karşılaştırırken en az iki kat daha hızlıdır.
sonraki duyuruya kadar duraklatıldı.

11
Sadece mevcut dizini istiyorsa, tüm ağacı tekrar tekrar değil, bulmak için -maxdepth 1 seçeneğini ekleyebilir.
igustin

3
Nedeni nasıl kullandığınızdan finddaha hızlı görünüyor . Sıralamayı durdurur ve benzer performansa sahipseniz. lslslsfind
Christopher Schultz

17

bulmak, ls ve perl 40 000 dosyalara karşı test: aynı hızda (gerçi önbelleği temizlemek için deneyin vermedi):

[user@server logs]$ time find . | wc -l
42917

real    0m0.054s
user    0m0.018s
sys     0m0.040s
[user@server logs]$ time /bin/ls -f | wc -l
42918

real    0m0.059s
user    0m0.027s
sys     0m0.037s

ve perl opendir / readdir ile aynı zamanda:

[user@server logs]$ time perl -e 'opendir D, "."; @files = readdir D; closedir D; print scalar(@files)."\n"'
42918

real    0m0.057s
user    0m0.024s
sys     0m0.033s

Not: Ben bin / ls takma seçeneği baypas emin olmak için -f / kullanılan olabilir biraz yavaşlatabilir ve -f dosya sipariş önlemek için. -f'siz ls, find / perl'den iki kat daha yavaştır, ancak ls -f ile birlikte kullanılırsa, aynı zaman gibi görünür:

[user@server logs]$ time /bin/ls . | wc -l
42916

real    0m0.109s
user    0m0.070s
sys     0m0.044s

Ayrıca tüm gereksiz bilgiler olmadan dosya sistemine doğrudan sormak için bazı komut dosyası istiyorum.

Peter van der Heijden, glenn jackman ve mark4o'nun cevaplarına dayanan testler.

Thomas


5
Testler arasındaki önbelleği kesinlikle temizlemelisiniz. ls -l | wc -lHarici bir 2.5 "HDD üzerinde 1M dosyaları olan bir klasörde ilk kez çalıştığımda , işlemin tamamlanması yaklaşık 3 dakika sürüyor. İkinci kez 12 saniye sürüyor IIRC. Ayrıca bu muhtemelen dosya sisteminize de bağlı olabilir. kullanıyordum Btrfs.
Behrang Saeedzadeh

Teşekkürler, perl snippet benim için bir çözüm. $ time perl -e 'opendir D, "."; @files = readdir D; closedir D; print scalar(@files)."\n"' 1315029 real 0m0.580s user 0m0.302s sys 0m0.275s
Pažout

5

Çıktıyı gereksinimlerinize göre değiştirebilirsiniz, ancak burada bir dizi sayısal olarak adlandırılan dizinlerdeki dosya sayısını tekrar tekrar saymak ve raporlamak için yazdığım bir bash tek katmanlı.

dir=/tmp/count_these/ ; for i in $(ls -1 ${dir} | sort -n) ; { echo "$i => $(find ${dir}${i} -type f | wc -l),"; }

Bu, belirli bir dizindeki tüm dosyaları (dizinleri değil) yinelemeli olarak arar ve sonuçları karma benzeri bir biçimde döndürür. Bul komutuna yapılan basit ayarlamalar, ne tür dosyaları saymak istediğinizi daha kesin hale getirebilir.

Bunun gibi bir şeyle sonuçlanır:

1 => 38,
65 => 95052,
66 => 12823,
67 => 10572,
69 => 67275,
70 => 8105,
71 => 42052,
72 => 1184,

1
Örneği biraz kafa karıştırıcı buldum. Neden dizin isimleri yerine solda rakamlar olduğunu merak ediyordum. Bunun için teşekkür ederim, ancak birkaç küçük ayar ile kullandım. .. (sayma dizinleri ve adını klasör tabanını bırakarak i için $ (ls -1 in |;; | sort -n) {echo "wc-l) $ i => $ ($ {i} bulmak"}
TheJacobTaylor

Soldaki sayılar örnek verilerimdeki dizin isimlerim. Üzgünüm, kafa karıştırıcıydı.
mightybs

1
ls -1 ${dir}daha fazla alan olmadan düzgün çalışmaz. Ayrıca, insan tüketimi için yazdırılamayan karakterlerden kaçtığından , döndürülen adın lsiletilebileceğine dair bir garanti yoktur . ( özellikle ilginç bir test örneği istiyorsanız). Bkz Eğer ls çıkışını (1) ayrıştırması gerektiğini Nedenfindlsmkdir $'oddly\nnamed\ndirectory'
Charles Duffy

4

Şaşırtıcı bir şekilde benim için, çıplak kemiklerin bulunması ls -f ile çok benzer

> time ls -f my_dir | wc -l
17626

real    0m0.015s
user    0m0.011s
sys     0m0.009s

karşı

> time find my_dir -maxdepth 1 | wc -l
17625

real    0m0.014s
user    0m0.008s
sys     0m0.010s

Tabii ki, üçüncü ondalık basamaktaki değerler, bunlardan her birini yürüttüğünüzde biraz kayıyor, bu yüzden temelde aynılar. Bununla birlikte find, gerçek dizinin kendisini saydığından (ve daha önce de belirtildiği gibi, ls -fiki önemli birim de döndürdüğünden, ve ayrıca sayılır.).


4

Bunu tamlık uğruna eklemek. Elbette doğru cevap zaten başka biri tarafından gönderildi, ancak ağaç programıyla bir dizi dosya ve dizin de alabilirsiniz.

tree | tail -n 1"763 dizinleri, 9290 dosyaları" gibi bir şey söyleyecek son satırı almak için komutu çalıştırın . Bu, bayrakla eklenebilecek gizli dosyalar hariç, dosyaları ve klasörleri yinelemeli olarak sayar -a. Başvuru için, bilgisayarımda 4.8 saniye sürdü, ağacın tüm ev dizinimi sayması 24777 dizin, 238680 dosyaydı. find -type f | wc -l5.3 saniye, yarım saniye daha uzun sürdü, bu yüzden ağacın oldukça rekabetçi olduğunu düşünüyorum.

Alt klasörleriniz olmadığı sürece, ağaç dosyaları saymanın hızlı ve kolay bir yoludur.

Ayrıca ve sadece eğlenmek için, tree | grep '^├'sadece geçerli dizindeki dosyaları / klasörleri göstermek için kullanabilirsiniz - bu temelde çok daha yavaş bir sürümüdür ls.


Brew install tailOS X için
The Unfun Cat

@UnfunCat tailzaten Mac OS X sisteminize yüklenmiş olmalıdır.
Christopher Schultz

4

Hızlı Linux Dosya Sayısı

Bildiğim en hızlı linux dosya sayısı

locate -c -r '/home'

Orada hiçbir grep çağırmak için ihtiyaç! Ancak belirtildiği gibi yeni bir veritabanına sahip olmalısınız (cron işi tarafından günlük olarak güncellenir veya manuel olarak sudo updatedb).

Gönderen adam bulmak

-c, --count
    Instead  of  writing  file  names on standard output, write the number of matching
    entries only.

Ayrıca , dizinleri dosya olarak saydığını da bilmelisiniz!


BTW: Sistem türünüzdeki dosya ve dizinlere genel bir bakış istiyorsanız

locate -S

Dizin, dosya vb. Sayısını verir.


veritabanının güncel olduğundan emin olmanız gerektiğini unutmayın
phuclv

1
LOL zaten bir veritabanında tüm sayıları varsa, o zaman kesinlikle hızlı bir şekilde sayabilirsiniz. :)
Christopher Schultz

3

Bunu burada yazmak , bir cevap hakkında yorum yapmak için yeterli itibar puanım yok , ancak mantıklı olmayan kendi cevabımı bırakmama izin verildi . Neyse ...

İlgili Christopher Schultz tarafından cevap , ben değiştirmeniz önerilir , stat için lstat ve muhtemelen önlemek hafıza taşması sınırlarla kontrolün eklenmesi:

if (strlen(path) + strlen(PATH_SEPARATOR) + strlen(ent->d_name) > PATH_MAX) {
    fprintf(stdout, "path too long (%ld) %s%c%s", (strlen(path) + strlen(PATH_SEPARATOR) + strlen(ent->d_name)), path, PATH_SEPARATOR, ent->d_name);
    return;
}

Lstat kullanmanın önerisi, bir dizin bir üst dizine bir sembolik bağlantı içeriyorsa döngülere yol açabilecek sembolik bağları takip etmekten kaçınmaktır.


2
Kullanımı nedeniyle modifikasyon lstatiyi bir öneriydi ve bunun için karmayı hak ediyorsunuz. Bu öneri, yukarıda ve şimdi GitHub'da yayınlanan koduma dahil edildi.
Christopher Schultz


2

Buradaki yanıt, çok büyük, çok iç içe dizinler için bu sayfadaki hemen hemen her şeyden daha hızlıdır:

https://serverfault.com/a/691372/84703

locate -r '.' | grep -c "^$PWD"


1
Güzel. Zaten tüm dosyaların güncel bir db'sine sahip olduğunuzdan, tekrar gitmenize gerek yoktur. Ancak ne yazık ki, bu yöntem için updatedb komutunun zaten çalıştığından ve tamamlandığından emin olmalısınız.
Chris Reid

grep'e gerek yok. Abu_bua'nın çözümülocate -c -r '/path' gibi kullanın
phuclv

2

Buraya her biri ~ 10K dosyaları olan ~ 10K klasörlerinin bir veri kümesindeki dosyaları saymaya çalışırken geldim. Birçok yaklaşımla ilgili sorun, 100M dosyalarını dolaylı olarak yaşlandırmalarıdır.

Christopher-schultz'un yaklaşımı genişletme özgürlüğünü aldım, böylece dizinleri argümanlar üzerinden geçirmeyi destekledi (özyinelemeli yaklaşımı stat de kullanıyor).

Aşağıdakileri dosyaya koyun dircnt_args.c:

#include <stdio.h>
#include <dirent.h>

int main(int argc, char *argv[]) {
    DIR *dir;
    struct dirent *ent;
    long count;
    long countsum = 0;
    int i;

    for(i=1; i < argc; i++) {
        dir = opendir(argv[i]);
        count = 0;
        while((ent = readdir(dir)))
            ++count;

        closedir(dir);

        printf("%s contains %ld files\n", argv[i], count);
        countsum += count;
    }
    printf("sum: %ld\n", countsum);

    return 0;
}

Bir sonra gcc -o dircnt_args dircnt_args.cbunu şöyle çağırabilirsiniz:

dircnt_args /your/dirs/*

10K klasöründeki 100M dosyalarda yukarıdakiler oldukça hızlı bir şekilde tamamlanır (ilk çalıştırma için ~ 5 dk, önbellekte takip: ~ 23 sn).

Bir saatten daha kısa sürede biten diğer yaklaşım önbellekte yaklaşık 1 dk ls -f /your/dirs/* | wc -l. Kont başına birkaç satır yeni satır tarafından kapalı olsa da ...

Beklenenden başka, findbir saat içinde iade girişimlerimden hiçbiri : - /


C programcısı olmayan biri için, bunun neden daha hızlı olacağını ve aynı şeyi yapmadan aynı cevabı nasıl alabildiğini açıklayabilir misiniz?
mlissner

bir C programcısı olmanıza gerek yok, sadece bir dosyayı statünün ne anlama geldiğini ve dizinlerin nasıl temsil edildiğini anlayın: dizinler esas olarak dosya adları ve inode listeleridir. Bir dosyaya bakarsanız, örneğin dosya boyutu, izinler, ... gibi bilgileri almak için sürücünün bir yerinde bulunan inode'a erişirsiniz. Dir başına sayımlarla ilgileniyorsanız, size çok zaman kazandırabilecek inode bilgisine erişmeniz gerekmez.
Jörn Hees

Oracle linux, gcc sürüm 4.8.5 20150623 (Red Hat 4.8.5-28.0.1) (GCC) üzerindeki bu segfaults ... göreceli yollar ve uzak f'ler bunun nedeni gibi görünüyor
Rondo

2

Linux'ta en hızlı yol (soru linux olarak etiketlenir), doğrudan sistem çağrısı kullanmaktır. İşte bir dizindeki dosyaları (sadece dirs yok) sayan küçük bir program. Milyonlarca dosyayı sayabilirsiniz ve "ls -f" den 2,5 kat, Christopher Schultz'un cevabından yaklaşık 1,3-1,5 kat daha hızlıdır.

#define _GNU_SOURCE
#include <dirent.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/syscall.h>

#define BUF_SIZE 4096

struct linux_dirent {
    long d_ino;
    off_t d_off;
    unsigned short d_reclen;
    char d_name[];
};

int countDir(char *dir) {


    int fd, nread, bpos, numFiles = 0;
    char d_type, buf[BUF_SIZE];
    struct linux_dirent *dirEntry;

    fd = open(dir, O_RDONLY | O_DIRECTORY);
    if (fd == -1) {
        puts("open directory error");
        exit(3);
    }
    while (1) {
        nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
        if (nread == -1) {
            puts("getdents error");
            exit(1);
        }
        if (nread == 0) {
            break;
        }

        for (bpos = 0; bpos < nread;) {
            dirEntry = (struct linux_dirent *) (buf + bpos);
            d_type = *(buf + bpos + dirEntry->d_reclen - 1);
            if (d_type == DT_REG) {
                // Increase counter
                numFiles++;
            }
            bpos += dirEntry->d_reclen;
        }
    }
    close(fd);

    return numFiles;
}

int main(int argc, char **argv) {

    if (argc != 2) {
        puts("Pass directory as parameter");
        return 2;
    }
    printf("Number of files in %s: %d\n", argv[1], countDir(argv[1]));
    return 0;
}

Not: Özyinelemeli değil, ancak bunu başarmak için değiştirebilirsiniz.


1
Bunun daha hızlı olduğuna katıldığımdan emin değilim. Derleyicinin opendir/ ile yaptığı her şeyi takip readdiretmedim, ancak sonunda neredeyse aynı koda kadar kaydığından şüpheleniyorum. Sistem çağrılarını bu şekilde yapmak da taşınabilir değildir ve Linux ABI sabit olmadığından, bir sistemde derlenen bir programın başka bir sistemde düzgün çalışacağı garanti edilmez (ancak herhangi bir * NIX sistemi IMO'sundan kaynaktan herhangi bir şey derlemek oldukça iyi bir tavsiye. ). Hız önemliyse, bu gerçekten hızı arttırıyorsa iyi bir çözümdür - programları ayrı olarak karşılaştırmadım.
Christopher Schultz

1

lsdosya adlarını sıralamak için daha fazla zaman harcar -f, sıralamayı devre dışı bırakmak için kullanmak bazen kaydeder:

ls -f | wc -l

veya şunları kullanabilirsiniz find:

find . -type f | wc -l

0

Ben büyük miktarda veri varken bellek işleme kullanmamanın komutları "piping" daha hızlı olduğunu fark ettim. Sonucu bir dosyaya kaydettim ve analiz ettikten sonra

ls -1 /path/to/dir > count.txt && cat count.txt | wc -l

bu en hızlı çözüm değildir çünkü sabit diskler oldukça yavaştır.
Senden

0

Ls / find yerine "getdents" kullanmalısınız

İşte getdents yaklaşımını anlatan çok iyi bir makale.

http://be-n.com/spw/you-can-list-a-million-files-in-a-directory-but-not-with-ls.html

İşte özü:

ls ve pratikte bir dizin listeleme (python os.listdir, find. dahil) diğer her yöntem libc readdir () dayanmaktadır. Ancak readdir () aynı anda yalnızca 32K dizin girdisini okur, yani aynı dizinde çok fazla dosyanız varsa (yani dizin girişlerinin 500M'si) tüm dizin girişlerini okumak çok uzun zaman alacaktır , özellikle yavaş bir diskte. Çok sayıda dosya içeren dizinler için, readdir () yöntemine dayanan araçlardan daha derine inmeniz gerekir. Libc'den yardımcı yöntemler yerine getdents () syscall öğesini doğrudan kullanmanız gerekir.

Getdents () kullanarak dosyaları listelemek için C kodunu burada bulabiliriz :

Bir dizindeki tüm dosyaları hızlı bir şekilde listelemek için yapmanız gereken iki değişiklik vardır.

İlk olarak, arabellek boyutunu X'ten 5 megabayt'a yükseltin.

#define BUF_SIZE 1024*1024*5

Daha sonra ana döngüyü inode == 0 ile girişleri atlamak için dizindeki her dosya hakkındaki bilgileri yazdırdığı yerde değiştirin.

if (dp->d_ino != 0) printf(...);

Benim durumumda ben de sadece sadece dizindeki dosya adlarını umursadım, ben de sadece dosya adını yazdırmak için printf () deyimini yeniden yazdım.

if(d->d_ino) printf("%sn ", (char *) d->d_name);

Derleyin (herhangi bir harici kütüphaneye ihtiyaç duymaz, bu yüzden yapmak çok kolaydır)

gcc listdir.c -o listdir

Şimdi sadece koş

./listdir [directory with insane number of files]

Linux'un bir ileri okuma yaptığını, bu yüzden readdir()aslında yavaş olmadığını unutmayın. Bu performans artışı için taşınabilirliği atmaya değer olduğuna inanmadan önce sağlam bir rakama ihtiyacım var.
fuz

-1

Bir dizindeki dosya sayısındaki değişiklikleri takip etmek için aşağıdaki komutu tercih ederim.

watch -d -n 0.01 'ls | wc -l'

Komut, dizinde bulunan ve 0,1 saniyelik yenileme hızıyla dosya sayısını takip etmek için bir pencereyi açık tutar.


ls | wc -l0,01 saniyede binlerce veya milyonlarca dosya içeren bir klasör için tamamlanacağından emin misiniz? sizin bile lsdiğer çözümlere kıyasla çok verimsiz. Ve OP sadece sayıyı almak istiyor, çıktıya bakarak orada
oturmuyor

İyi. İyi. Benim için işe yarayan zarif bir çözüm buldum. Ben de aynısını paylaşmak istiyorum. Linux 'ls' komut bilmiyorum oldukça verimsiz. Bunun yerine ne kullanıyorsun? Ve 0.01s yenileme hızıdır. Zaman değil. Eğer saat kullanmadıysanız lütfen man sayfalarına bakın.
Anoop Toffy

Peki ben watchbu yorumdan sonra kılavuzu okudum ve çoğu PC ekranlarının yenileme oranı sadece 60Hz olduğu için 0.01s (0.1s değil) gerçekçi olmayan bir sayı olduğunu gördüm ve bu herhangi bir şekilde soruyu cevaplamıyor. OP, "Çok sayıda dosya için Hızlı Linux Dosya Sayımı" hakkında sorular sordu. Ayrıca göndermeden önce uygun bir cevap
okumadınız

Cevapları okudum. Ama ne gönderdiğim bir dizindeki dosya sayısını değişen izlemenin bir yoludur. örneğin: dosyayı bir konumdan diğerine kopyalarken dosya sayısı değişiklikleri korur. Ben poster yöntemi ile bunu takip edebilirsiniz. Hiçbir yerde yaptığım gönderinin önceki yazıları değiştirdiğini veya geliştirdiğini kabul ediyorum.
Anoop Toffy

-2

En yüksek dosya sayısına sahip ilk 10 yönetmen.

dir=/ ; for i in $(ls -1 ${dir} | sort -n) ; { echo "$(find ${dir}${i} \
    -type f | wc -l) => $i,"; } | sort -nr | head -10

3
Bu kesinlikle mightybs tarafından yazılan cevaba (aynı böceklerle) şaşırtıcı derecede benzer görünüyor . Başka biri tarafından yazılan kodu genişletecek veya değiştirecekseniz, bunlara kredi eklemek uygundur. Yanıtlarınızda kullandığınız kodu, hatalarını tanımlamak ve düzeltmek için yeterince anlamak daha da uygundur.
Charles Duffy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.