Быстрый счетчик файлов Linux для большого количества файлов

137

Я пытаюсь найти лучший способ найти количество файлов в определенном каталоге, когда существует очень большое количество файлов (> 100 000).

Когда файлов столько, выполнение ls | wc -lзанимает довольно много времени. Я считаю, что это потому, что он возвращает имена всех файлов. Я пытаюсь занять как можно меньше дискового ввода-вывода.

Я экспериментировал с некоторыми сценариями оболочки и Perl безрезультатно. Любые идеи?

ks1322
источник
2
убедитесь, что ваш «ls» - это / usr / bin / ls, а не псевдоним чего-то более интересного.
Гленн Джекман,
Аналогичный вопрос с интересными ответами здесь: serverfault.com/questions/205071/…
aidan
Стоит отметить, что большинство, если не все решения, представленные в этом вопросе, не относятся к Linux , а являются довольно общими для всех * NIX-подобных систем. Возможно, уместно удалить тег «Linux».
Кристофер Шульц

Ответы:

189

По умолчанию lsсортирует имена, что может занять некоторое время, если их много. Также не будет вывода, пока все имена не будут прочитаны и отсортированы. Используйте ls -fопцию, чтобы отключить сортировку.

ls -f | wc -l

Обратите внимание , что это также позволит -a, так ., ..и другие файлы , начинающиеся с .будут учитываться.

mark4o
источник
11
+1 И я подумала, что знаю все, что нужно знать ls.
моб
5
ZOMG. Сортировка 100К строк - ничто - по сравнению с stat()вызовом lsдля каждого файла. findне, stat()таким образом, это работает быстрее.
Dummy00001
12
ls -fтоже нет stat(). Но, конечно же, оба варианта lsи findвызываются, stat()когда используются определенные параметры, такие как ls -lили find -mtime.
mark4o
7
Для контекста это заняло 1-2 минуты, чтобы подсчитать 2,5 миллиона jpgs на маленьком блоке Slicehost.
philfreo
6
Если вы хотите добавить подкаталоги в счетчик, сделайтеls -fR | wc -l
Райан Уоллс
62

Самый быстрый способ - это специальная программа, например:

#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, это программа, скомпилированная из вышеуказанного источника.

РЕДАКТИРОВАТЬ 2016-09-26

По многочисленным просьбам я переписал эту программу, сделав ее рекурсивной, чтобы она переместилась в подкаталоги и продолжала отдельно подсчитывать файлы и каталоги.

Поскольку ясно, что некоторые люди хотят знать, как все это сделать, у меня есть много комментариев в коде, чтобы попытаться понять, что происходит. Я написал это и протестировал на 64-битном Linux, но он должен работать на любой POSIX-совместимой системе, включая Microsoft Windows. Сообщения об ошибках приветствуются; Я рад обновить это, если вы не можете заставить его работать на вашем AIX или OS / 400 или чем-то еще.

Как видите, это много сложнее, чем оригинал, и обязательно так: должна существовать по крайней мере одна функция для рекурсивного вызова, если вы не хотите, чтобы код стал очень сложным (например, управление стеком подкаталогов и обработка его в одном цикле). Поскольку мы должны проверять типы файлов, в игру вступают различия между различными ОС, стандартными библиотеками и т. Д., Поэтому я написал программу, которая пытается работать в любой системе, где она будет компилироваться.

Проверки ошибок очень мало, и сама countфункция на самом деле не сообщает об ошибках. Единственные вызовы, которые могут действительно потерпеть неудачу, это opendirи stat(если вам не повезло, и у вас есть система, в которой уже direntесть тип файла). Я не параноик по поводу проверки общей длины имен пути subdir, но теоретически система не должна разрешать любое имя пути длиннее, чем PATH_MAX. Если есть сомнения, я могу это исправить, но это просто дополнительный код, который нужно объяснить тому, кто учится писать C. Эта программа предназначена для того, чтобы быть примером того, как рекурсивно погружаться в подкаталоги.

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

РЕДАКТИРОВАТЬ 2017-01-17

Я включил два изменения, предложенные @FlyingCodeMonkey:

  1. Используйте lstatвместо stat. Это изменит поведение программы, если у вас есть каталоги с символическими ссылками в каталоге, который вы сканируете. Предыдущее поведение состояло в том, что (связанный) подкаталог будет иметь свое количество файлов, добавленное к общему количеству; новое поведение заключается в том, что связанный каталог будет учитываться как один файл, а его содержимое не будет учитываться.
  2. Если путь к файлу слишком длинный, выдается сообщение об ошибке и программа останавливается.

РЕДАКТИРОВАТЬ 2017-06-29

Если повезет, это будет последняя редакция этого ответа :)

Я скопировал этот код в репозиторий GitHub, чтобы немного упростить получение кода (вместо копирования / вставки вы можете просто загрузить исходный код ), плюс он позволяет любому предложить модификацию, отправив извлечение -запрос от GitHub.

Исходный код доступен по лицензии Apache License 2.0. Патчи * добро пожаловать!


  • «патч» - это то, что старые люди, такие как я, называют «запросом на получение ответа»
Кристофер Шульц
источник
2
Просто прекрасно! Спасибо! И для тех, кто не знает: вы можете скомпилировать приведенный выше код в терминале: gcc -o dircnt dircnt.cи использовать его так./dircnt some_dir
aesede
Есть ли простой способ сделать это рекурсивным?
ck_
@ck_ Конечно, это легко сделать рекурсивным. Вам нужна помощь с решением, или вы хотите, чтобы я написал все это?
Кристофер Шульц
1
@ChristopherSchultz, тесты, которые вы опубликовали выше - насколько велик был рассматриваемый каталог?
Dom Vinyard
1
Я действительно хотел использовать это в Python, поэтому я упаковал его как пакет ffcount . Спасибо за то, что сделали код доступным @ChristopherSchultz!
GjjvdBurg
35

Вы пытались найти? Например:

find . -name "*.ext" | wc -l
igustin
источник
1
Это рекурсивно найдет файлы в текущем каталоге.
mark4o
В моей системе find /usr/share | wc -l(~ 137 000 файлов) примерно на 25% быстрее, чем ls -R /usr/share | wc -l(~ 160 000 строк, включая имена dir, итоги dir и пустые строки) при первом запуске каждого и как минимум в два раза быстрее при сравнении последующих (кэшированных) запусков.
Приостановлено до дальнейшего уведомления.
11
Если ему нужен только текущий каталог, а не все дерево рекурсивно, он может добавить параметр -maxdepth 1 для поиска.
игустин
3
Кажется, причина findбыстрее, чем lsиз-за того, как вы используете ls. Если вы прекратите сортировку lsи будете findиметь аналогичные показатели.
Кристофер Шульц
17

find, ls и perl протестированы на 40000 файлов: одинаковая скорость (хотя я не пробовал очищать кеш):

[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

и с perl opendir / readdir одновременно:

[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

примечание: я использовал / bin / ls -f, чтобы обойти опцию псевдонима, которая может немного замедлиться, и -f, чтобы избежать упорядочения файлов. ls без -f в два раза медленнее, чем find / perl, за исключением того, что ls используется с -f, похоже, это то же самое время:

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

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

Я также хотел бы иметь некоторый сценарий для запроса файловой системы напрямую без всей ненужной информации.

тесты, основанные на ответе Питера ван дер Хейдена, Гленна Джекмана и mark4o.

Томас

Томас
источник
5
Между тестами обязательно нужно очищать кеш. Первый раз, когда я запускаю ls -l | wc -lпапку на внешнем 2,5-дюймовом жестком диске с 1M файлами, операция завершается примерно за 3 минуты. Во второй раз это занимает 12 секунд IIRC. Также это может потенциально зависеть и от вашей файловой системы. I использовал Btrfs.
Behrang Saeedzadeh
Спасибо, фрагмент perl - это решение для меня. $ 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

Вы можете изменить вывод в соответствии с вашими требованиями, но вот одна строчка из bash, которую я написал для рекурсивного подсчета и представления количества файлов в серии каталогов с числовыми именами.

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

Это выглядит рекурсивно для всех файлов (не каталогов) в данном каталоге и возвращает результаты в хэш-подобном формате. Простые настройки команды find могут сделать файлы, которые вы хотите подсчитывать, более конкретными и т. Д.

Результаты примерно такие:

1 => 38,
65 => 95052,
66 => 12823,
67 => 10572,
69 => 67275,
70 => 8105,
71 => 42052,
72 => 1184,
mightybs
источник
1
Я нашел пример немного запутанным. Мне было интересно, почему слева были номера, а не имена каталогов. Спасибо за это, хотя, я закончил тем, что использовал это с несколькими незначительными изменениями. (подсчет каталогов и удаление имени базовой папки. для i в $ (ls -1. | sort -n); {echo "$ i => $ (find $ {i} | wc -l)";}
TheJacobTaylor
Цифры слева - это имена каталогов из моих примеров данных. Извините, что сбил с толку.
Mightybs
1
ls -1 ${dir}не будет работать должным образом без дополнительных мест. Кроме того, нет никакой гарантии, что возвращаемое имя lsможет быть передано find, поскольку lsэкранирует непечатные символы для потребления человеком. ( mkdir $'oddly\nnamed\ndirectory'если вы хотите особенно интересный контрольный пример). Узнайте, почему вы не должны анализировать вывод команды ls (1)
Чарльз Даффи,
4

Удивительно для меня, но простая находка очень похожа на ls -f

> time ls -f my_dir | wc -l
17626

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

против

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

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

Конечно, значения в третьем десятичном знаке немного сдвигаются при каждом выполнении любого из них, поэтому они в основном идентичны. Обратите внимание, однако, что это findвозвращает одну дополнительную единицу, потому что она считает сам фактический каталог (и, как упоминалось ранее, ls -fвозвращает две дополнительные единицы, поскольку она также учитывает. И ..).

Богдан Стэнческу
источник
4

Просто добавляю это для полноты картины. Правильный ответ, конечно, уже был опубликован кем-то другим, но вы также можете получить количество файлов и каталогов с помощью древовидной программы.

Запустите команду, tree | tail -n 1чтобы получить последнюю строку, в которой будет что-то вроде «763 каталога, 9290 файлов». При этом файлы и папки подсчитываются рекурсивно, за исключением скрытых файлов, которые можно добавить с помощью флага -a. Для справки, на моем компьютере понадобилось 4,8 секунды, чтобы дерево посчитало весь мой домашний каталог, который был 24777 каталогов, 238680 файлов. find -type f | wc -lзанял 5,3 секунды, на полсекунды дольше, так что я думаю, что дерево довольно конкурентоспособно по скорости.

Если у вас нет вложенных папок, дерево - это быстрый и простой способ подсчета файлов.

Кроме того, и просто для удовольствия, вы можете использовать, tree | grep '^├'чтобы показывать только файлы / папки в текущем каталоге - это в основном намного более медленная версия ls.

Benubird
источник
Brew install tailдля OS X.
The Unfun Cat
@TheUnfunCat tailуже должен быть установлен в вашей системе Mac OS X.
Кристофер Шульц,
4

Fast Linux File Count

Самый быстрый счетчик файлов Linux, который я знаю,

locate -c -r '/home'

Там нет нет необходимости вызывать Grep! Но, как уже упоминалось, у вас должна быть свежая база данных (ежедневно обновляемая заданием cron или вручную sudo updatedb).

От человека найти

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

Кроме того, вы должны знать, что он также считает каталоги файлами!


Кстати: если вам нужен обзор ваших файлов и каталогов в вашей системе, введите

locate -S

Выводит количество каталогов, файлов и т. Д.

abu_bua
источник
обратите внимание, что вы должны убедиться, что база данных обновлена
phuclv
1
LOL, если у вас уже есть все значения в базе данных, то вы, безусловно, можете быстро считать. :)
Кристофер Шульц
3

Пишу здесь, поскольку у меня недостаточно репутационных баллов, чтобы комментировать ответ, но мне разрешено оставлять свой собственный ответ, что не имеет смысла. Тем не мение...

Что касается ответа Кристофера Шульца , я предлагаю изменить stat на lstat и, возможно, добавить проверку границ, чтобы избежать переполнения буфера:

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 - избегать использования символических ссылок, которые могут привести к циклам, если каталог содержит символическую ссылку на родительский каталог.

FlyingCodeMonkey
источник
2
Модернизация, потому что использование lstatбыло хорошим предложением, и вы заслужили за это карму. Это предложение было включено в мой код, опубликованный выше, а теперь и на GitHub.
Кристофер Шульц,
2

Вы могли бы попробовать , если используется opendir()и readdir()в Perlбыстрее. Пример этой функции можно найти здесь

Питер ван дер Хейден
источник
2
использование: perl -e 'opendir D, "."; @files = readdir D; closedir D; распечатать скаляр (@files) '
Гленн Джекман
2

Этот ответ здесь быстрее, чем почти все остальное на этой странице для очень больших, очень вложенных каталогов:

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

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

ck_
источник
1
Ницца. Поскольку у вас уже есть актуальная база данных всех файлов, вам не нужно возвращаться к ней снова. Но, к сожалению, вы должны убедиться, что команда updatedb уже запущена и завершена для этого метода.
Крис Рид,
вам не нужно использовать grep. Используйте locate -c -r '/path'как в решении
abu_bua
2

Я пришел сюда, когда пытался сосчитать файлы в наборе данных ~ 10K папок с ~ 10K файлами в каждой. Проблема многих подходов заключается в том, что они неявно оценивают файлы размером 100 млн., Что занимает много времени.

Я взял на себя смелость расширить подход Кристофера-Шульца, чтобы он поддерживал передачу каталогов через args (его рекурсивный подход также использует stat).

Поместите в файл следующее 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;
}

После gcc -o dircnt_args dircnt_args.cвы можете вызвать его так:

dircnt_args /your/dirs/*

На 100M файлах в 10K папках описанное выше выполняется довольно быстро (~ 5 минут для первого запуска, отслеживание в кэше: ~ 23 с).

Единственный подход , который закончил менее чем через час был Ls с примерно 1 мин на кэш: ls -f /your/dirs/* | wc -l. Счетчик сбился на пару символов новой строки в каталоге ...

Помимо ожидаемого, ни одна из моих попыток не findвернулась в течение часа: - /

Йорн Хис
источник
Для кого-то, кто не является программистом C, вы можете объяснить, почему это будет быстрее, и как он может получить тот же ответ, не делая то же самое?
Млисснер
вам не нужно быть программистом на C, просто поймите, что означает статистика файла и как представлены каталоги: каталоги - это, по сути, списки имен файлов и inode. Если вы регистрируете файл, вы получаете доступ к иноду, который находится где-то на диске, например, чтобы получить информацию, такую ​​как размер файла, разрешения, .... Если вас интересует только число в dir, вам не нужно получать доступ к информации inode, что может сэкономить вам много времени.
Йорн Хис
Эта ошибка в Oracle linux, gcc версии 4.8.5 20150623 (Red Hat 4.8.5-28.0.1) (GCC) ... кажется, что причиной являются относительные пути и удаленные fs
Rondo
2

Самый быстрый способ в linux (вопрос помечен как linux) - использовать прямой системный вызов. Вот небольшая программа, которая считает файлы (только без каталогов) в каталоге. Вы можете считать миллионы файлов, и это примерно в 2,5 раза быстрее, чем "ls -f", и примерно в 1,3-1,5 раза быстрее, чем ответ Кристофера Шульца.

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

PS: Это не рекурсивно, но вы можете изменить его для этого.

Николай Димитров
источник
1
Я не уверен, что согласен, что это быстрее. Я не проследил все, что компилятор делает с opendir/ readdir, но подозреваю, что в конечном итоге это сводится почти к одному и тому же коду. Выполнение системных вызовов таким образом также не переносимо, и, поскольку Linux ABI нестабилен, программа, скомпилированная в одной системе, не гарантирует правильную работу в другой (хотя это довольно хороший совет компилировать что-либо из исходного кода в любой системе * NIX IMO ). Если скорость является ключевым фактором, это хорошее решение, если оно действительно увеличивает скорость - я не тестировал программы отдельно.
Кристофер Шульц,
1

lsтратит больше времени на сортировку имен файлов, использование -fдля отключения сортировки сэкономит время:

ls -f | wc -l

или вы можете использовать find:

find . -type f | wc -l
Мохаммад Анини
источник
0

Я понял, что не использовать обработку памяти, когда у вас есть огромное количество данных, быстрее, чем "конвейерная обработка" команд. Я сохранил результат в файл и проанализировал его.

ls -1 /path/to/dir > count.txt && cat count.txt | wc -l
Марсело Луис Онхате
источник
это не самое быстрое решение, потому что жесткие диски очень медленные. Есть и другие более эффективные способы, которые были опубликованы за много лет до вас
phuclv
0

Вместо ls / find следует использовать "getdent".

Вот одна очень хорошая статья, в которой описан подход гетедентов.

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

Вот выдержка:

ls и практически любой другой способ перечисления каталога (включая python os.listdir, find.) полагаются на libc readdir (). Однако readdir () считывает только 32 КБ записей каталога за раз, что означает, что если у вас много файлов в одном каталоге (то есть, 500 М записей каталога), это займет безумно много времени, чтобы прочитать все записи каталога. , особенно на медленном диске. Для каталогов, содержащих большое количество файлов, вам нужно копать глубже, чем инструменты, которые полагаются на readdir (). Вам нужно будет использовать системный вызов getdent () напрямую, а не вспомогательные методы из libc.

Мы можем найти код C для вывода списка файлов с помощью getdent () отсюда :

Вам нужно будет сделать две модификации, чтобы быстро вывести список всех файлов в каталоге.

Во-первых, увеличьте размер буфера с X примерно до 5 мегабайт.

#define BUF_SIZE 1024*1024*5

Затем измените основной цикл, где он печатает информацию о каждом файле в каталоге, чтобы пропустить записи с inode == 0. Я сделал это, добавив

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

В моем случае я действительно заботился только об именах файлов в каталоге, поэтому я также переписал оператор printf (), чтобы печатать только имя файла.

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

Скомпилируйте его (ему не нужны внешние библиотеки, поэтому это очень просто сделать)

gcc listdir.c -o listdir

Теперь просто беги

./listdir [directory with insane number of files]
Dev123
источник
Обратите внимание, что Linux выполняет упреждающее чтение, поэтому на readdir()самом деле он не медленный. Мне нужна твердая цифра, прежде чем я пойму, что ради такого увеличения производительности стоит отказаться от переносимости.
fuz
-1

Я предпочитаю следующую команду, чтобы отслеживать изменения количества файлов в каталоге.

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

Команда будет держать окно открытым, чтобы отслеживать количество файлов в каталоге с частотой обновления 0,1 с.

Ануп Тоффи
источник
Вы уверены, что ls | wc -lзакончите для папки с тысячами или миллионами файлов за 0,01 с? даже ваш lsочень неэффективен по сравнению с другими решениями. И ОП просто хочет получить счетчик, а не сидеть и смотреть, как меняется выходной сигнал
phuclv
Хорошо. Хорошо. Я нашел элегантное решение, которое мне подходит. Я хотел бы поделиться тем же, поэтому и сделал. Я не знаю, что команда ls в Linux очень неэффективна. Что вы используете вместо этого? А 0,01 с - это частота обновления. Не время если вы не использовали часы, обратитесь к страницам руководства.
Anoop Toffy
ну, я прочитал watchруководство после этого комментария и увидел, что 0,01 с (не 0,1 с) - это нереалистичное число, потому что частота обновления большинства экранов ПК составляет всего 60 Гц, и это никоим образом не отвечает на вопрос. ОП спрашивал о «Fast Linux File Count для большого количества файлов». Вы также не читали ни одного доступного ответа перед публикацией
phuclv
Я прочитал ответы. Но то, что я опубликовал, - это способ отслеживать изменение количества файлов в каталоге. например, при копировании файла из одного места в другое количество файлов сохраняется. с помощью метода, который я пишу, можно это отслеживать. Я согласен с тем, что пост, который я сделал, нигде не изменяет и не улучшает предыдущие посты.
Ануп Тоффи
-2

Первые 10 директоров с наибольшим количеством файлов.

dir=/ ; for i in $(ls -1 ${dir} | sort -n) ; { echo "$(find ${dir}${i} \
    -type f | wc -l) => $i,"; } | sort -nr | head -10
user2546874
источник
3
Это, безусловно, выглядит удивительно похоже на ответ (с теми же ошибками), написанный mightybs . Если вы собираетесь расширять или изменять код, написанный кем-то другим, уместно указать их. Понимание кода, который вы используете в своих ответах, достаточно для выявления и исправления ошибок, еще более уместно.
Чарльз Даффи