Як керувати величезною кількістю файлів у оболонці?


9

$ ls ./dir_with_huge_amount_of_files/errors/

Припустимо, в каталозі повно зображень із часовими позначками unix, я маю на увазі багато, розмірене в багатьох ГБ або навіть більше. Команди оболонки, як-от ls, отримуватимуть попереджень у стилі переповнення, оскільки вони не розроблені для роботи з мільйонами (або більше) малюнків. Як я можу керувати такою величезною кількістю файлів? Якщо, наприклад, я хочу знайти зображення посередині (відповідно до часової позначки в назві та часі створення), чи є якась файлова система, яка пропонує вбудовану функцію пошуку? Які команди ви б використали? Я спробував зручне lsіfindз необхідними прапорами, але вони були або дуже повільними, або генерували попередження, тому я думаю, що або мені потрібна краща файлова система або db, або щось подібне, щоб попередньо індексувати зображення. Мені в основному потрібен один масив, до якого вкладені фотографії розміщуються у хронологічному порядку. Як це зробити? Пізніше можуть бути додані метадані з часовими позначками unix.

[Оновлення]

У поточних відповідях є серйозний недолік, люди просто розміщують сортування відповідей без емпіричних тестів. Якби вони перевірили свої пропозиції, вони, ймовірно, не зможуть. Отже, я створив вам інструмент командного рядка, за допомогою якого ви можете створити пісочницю, щоб створити величезну кількість файлів і протестувати свої пропозиції, як-от кількість файлів 1e7. Генерування файлів може зайняти тривалий час, тому будьте терплячі. Якщо хтось знає швидший спосіб це зробити, відредагуйте код. Введіть, python code.py --helpщоб отримати допомогу. Веселіться!

Приклад використання для створення безлічі брудних файлів

$ ls ./data2
ls: ./data2: No such file or directory
$ python testFill.py -n 3 -d 7                                                 
$ tree data2/                                                                  
data2/
|-- 0
|   |-- 1302407302636973
|   |-- 1302407302638022
|   `-- 1302407302638829
|-- 1
|   |-- 1302407302639604
|   |-- 1302407302641652
|   `-- 1302407302642399
|-- 2
|   |-- 1302407302643158
|   |-- 1302407302645223
|   `-- 1302407302646026
|-- 3
|   |-- 1302407302646837
|   |-- 1302407302649110
|   `-- 1302407302649944
|-- 4
|   |-- 1302407302650771
|   |-- 1302407302652921
|   `-- 1302407302653685
|-- 5
|   |-- 1302407302654423
|   |-- 1302407302656352
|   `-- 1302407302656992
`-- 6
    |-- 1302407302657652
    |-- 1302407302659543
    `-- 1302407302660156

7 directories, 21 files

Код testFill.py

# Author: hhh
# License: ISC license

import os, math, time, optparse, sys

def createHugeAmountOfFiles(fileAmount, dirAmount):
   counter = 0
   DENSITY = 1e7
   dir = "./data/"

   do = dir+str(counter)+"/"
   while (os.path.exists(do)):
      counter = counter+1
      do = dir+str(counter)+"/"

   os.mkdir(do)

   for d in range(int(dirAmount)):
      for f in range(int(fileAmount)):
         timeIt = int(time.time()*1e6)
         if (not os.path.exists(do)):
            os.mkdir(do)

         if (timeIt % DENSITY == 0):
            counter = counter+1
            do = dir+str(counter)+"/"

            if (not os.path.exists(do)):
               os.mkdir(do)


         do = dir+str(counter)+"/"
         if(not os.path.exists(do)):
            os.mkdir(do)

         f = open(do+str(timeIt), 'w')
         f.write("Automatically created file to test Huge amount of files.")
         f.close()
      counter = counter +1


def ls(dir):
   for root, dirs, files in os.walk("./data/"+dir):
      print(files)

def rm(dir):
   for root, dirs, files in os.walk("./data/"+dir):
      for f in files:
         os.remove("./data/"+dir+"/"+f)


def parseCli():
   parser = optparse.OptionParser()
   parser.add_option("-f", "--file", dest="filename",
                     help="Location to remove files only in ./Data.", metavar="FILE")
   parser.add_option("-n", "--number", dest="number",
                     help="Number of files to generate", metavar="NUMBER")
   parser.add_option("-r", "--remove", dest="remove",
                     help="Data -dir content to remove", metavar="NUMBER")
   parser.add_option("-d", "--dir", dest="dir",
                     help="Amount of dirs to generate", metavar="NUMBER")
   parser.add_option("-q", "--quiet",
                     action="store_false", dest="verbose", default=True,
                     help="don't print status messages to stdout")

   return parser.parse_args()

def main():
   (options, args) = parseCli()

   if (options.filename):
      ls(options.filename)
   if (options.number and options.dir):
      createHugeAmountOfFiles(options.number, options.dir)
   if (options.remove):
      rm(options.remove)


main()

2
@hhh для набору даних на цій шкалі, належним чином індексований db - це, мабуть, єдиний варіант
xenoterracide

@xenoterracide: але навіть dbs повинні здійснювати швидкий пошук з чимось на зразок масивів, db звучить надмір. Джерело для створення зображень тут: github.com/fsphil/fswebcam . Можливо, я міг би модифікувати це трохи часу, коли він зберігає зображення, щоб я міг додати рядок з inode-номером & unix-time-штамп до файлу. Тепер не з картинками, а з лінією, було б набагато швидше шукати зображення. Або ще простіше, кожного разу, коли зображення зберігається на диску, я додаю рядок до файлу його часової позначки. Рішення навколо. Але це не вирішить проблему з поточними зображеннями, тому питання актуальне.

@hhh яку файлову систему ви використовуєте? або це ще не важливо ... ext має деякі функції для підвищення продуктивності, які можуть бути не включені за замовчуванням. Хоча навіть ті, напевно, не матимуть справи в масштабі, про який ви говорите. Бази даних оптимізовані для цих речей і мають різні рішення щодо індексації для їх вирішення. наприклад, індекс btree - це не просто простий масив ...
xenoterracide

@xenoterracide: ext3, не впевнений, чи це має значення. Я думаю, що проілюстроване нами рішення виправляє проблему для майбутньої проблеми пошуку, але це зовсім не допомагає на поточних фотографіях, для цього потрібно багато часу.

1
У вас є мільйони файлів в одному каталозі? Якщо так, то ви можете розглянути їх розділення на один або два рівні глибокі підкаталоги на основі перших знаків імені файлу, наприклад:a/b/abcdef.jpg
alex

Відповіді:


4

Спробуйте іншу оболонку. Я рекомендую спробувати zsh, наприклад, і побачити, чи дозволяє він більше параметрів.

Якщо я правильно розумію, частина імені файлу - це часова мітка UNIX. Можливо, доцільно розділити файли на папки. Якщо формат дати / часу є номером епохи UNIX, покладіть фрагменти дробів цього числа, скажімо, 10000, в окрему папку.

Якщо часова позначка ISO 8601 є частиною імені файлу, просто розділіть його на рік, місяць чи день.


1
ls і find не є вбудованими ні в bash, ні в zsh, тому незрозуміло, як комутація оболонок допоможе в цьому випадку.
Робін Грін

Йдеться про розширення оболонки. Якщо оболонка не може розширити глобус, це може бути проблемою.
полемон

Я зробив кілька тестів , виконання команд на близько 1E6 файлів, ЗШ стикається з тими ж проблемами: "$ cp * Test/ ksh: cp: Argument list too long % rm * zsh: sure you want to delete all the files in /home/user/Downloads [yn]? y zsh: argument list too long: rm % ls * zsh: argument list too long: ls ". Вибачте, але я не можу зрозуміти, як це пов'язано з питанням -1, оскільки це було так просто перевірити, створити лише файли 1e6 та запустити команди.

1

Чи допоможе вам locate(і звичайно updatedb)?


1
updatedbвикористовує find.
dave1010

@ dave1010, звичайно, але це робиться у фоновому режимі раз у раз, тому, якщо ОП є прийнятним, не потрібно бути в курсі щохвилини, але, можливо, раз на день, а потім розкладати оновленняb у тиху годину (або графік оновлюється часто, але з низьким пріоритетом, який у будь-якому випадку має бути), то за допомогою функції пошуку дуже швидко можна знайти те, що ви хочете. Тож ключовим питанням є те, наскільки актуальним повинен бути БД (або індекс для будь-якої іншої такої системи).
asoundmove
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.