Jak zarządzać ogromną ilością plików w powłoce?

9

$ ls ./dir_with_huge_amount_of_files/errors/

Załóżmy, że katalog jest pełen zdjęć z uniksowymi znacznikami czasu, mam na myśli wiele mierzonych w wielu GB lub nawet więcej. Takie polecenia powłoki lsotrzymają ostrzeżenia w stylu przepełnienia, ponieważ nie są zaprojektowane do pracy z milionami (lub więcej) zdjęć. Jak mogę zarządzać tak dużą ilością plików? Jeśli na przykład chcę znaleźć obraz na środku (zgodnie ze znacznikiem czasu w nazwie i czasie utworzenia), czy istnieje jakiś system plików, który oferuje wbudowaną funkcję wyszukiwania? Jakich poleceń byś użył? Próbowałem wygodne lsifindz niezbędnymi flagami, ale były albo bardzo powolne, albo generowały ostrzeżenia, więc myślę, że potrzebuję lepszego systemu plików lub db albo czegoś takiego, aby wstępnie zindeksować zdjęcia. Zasadniczo potrzebuję jednej tablicy, do której powinny być umieszczone inody zdjęć w kolejności chronologicznej. Jak to zrobić? Później można dodać metadane z uniksowymi znacznikami czasu.

[Aktualizacja]

W obecnych odpowiedziach występuje poważna wada, ludzie po prostu publikują rodzaj odpowiedzi bez testów empirycznych. Gdyby przetestowali swoje sugestie, prawdopodobnie by się nie powiedzieli. Dlatego stworzyłem ci narzędzie wiersza polecenia, za pomocą którego możesz utworzyć piaskownicę, aby utworzyć ogromną liczbę plików i przetestować swoje sugestie, tak jak w przypadku liczby plików 1e7. Wygenerowanie plików może zająć dużo czasu, więc bądź cierpliwy. Jeśli ktoś wie, jak to zrobić szybciej, edytuj kod. Wpisz, python code.py --helpaby uzyskać pomoc. Baw się dobrze!

Przykład użycia do tworzenia wielu plików dirred

$ 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

Kod 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()
Kevin Bowen
źródło
2
@ hhh dla zestawów danych na tej skali prawdopodobnie jedyną opcją jest właściwie zindeksowana db
xenoterracide
@xenoterracide: ale nawet dbs musi wdrożyć szybkie wyszukiwanie za pomocą czegoś takiego jak tablice, db brzmi przesadnie. Źródło do robienia zdjęć znajduje się tutaj: github.com/fsphil/fswebcam . Być może mógłbym go trochę zmodyfikować w czasie, w którym zapisuje obraz, aby dołączyć do pliku linię z numerem i-węzła i znacznikiem czasu unix. Teraz nie ze zdjęciami, ale liniami, wyszukiwanie zdjęć byłoby znacznie szybsze. Lub jeszcze łatwiej, za każdym razem, gdy zdjęcie jest zapisywane na dysku, dołączam wiersz do pliku jego znacznika czasu. Okrągłe rozwiązanie. Ale nie rozwiąże problemu z bieżącymi zdjęciami, więc zadaj odpowiednie pytanie.
@ hhh jakiego systemu plików używasz? lub nie ma to jeszcze znaczenia ... ext ma pewne funkcje zwiększające wydajność, które mogą nie być domyślnie włączone. Chociaż nawet ci prawdopodobnie nie poradzą sobie na skalę, o której mówisz. DB są zoptymalizowane do tych rzeczy i mają różne rozwiązania indeksowania, aby sobie z nimi poradzić. na przykład indeks btree to nie tylko prosta tablica ...
xenoterracide
@xenoterracide: ext3, nie jestem pewien, czy to ma znaczenie. Myślę, że rozwiązanie, które zilustrowałem, rozwiązuje problem dla przyszłego wyszukiwania, ale w ogóle nie pomaga w przypadku bieżących zdjęć, jego wyszukiwanie jest bardzo czasochłonne.
1
Czy masz miliony plików w jednym katalogu? Jeśli tak, możesz rozważyć podzielenie ich na podkatalogi głębokie na jeden lub dwa poziomy, na podstawie pierwszych znaków nazwy pliku, np .:a/b/abcdef.jpg
Alex

Odpowiedzi:

4

Wypróbuj inną powłokę. Polecam na przykład wypróbowanie zsh i sprawdź, czy pozwala to na więcej parametrów.

Jeśli dobrze rozumiem, część nazwy pliku jest znacznikiem czasu UNIX. Wskazane może być podzielenie plików na foldery. Jeśli format daty / godziny jest liczbą z epoki UNIX, umieść fragmenty tej liczby, powiedzmy 10000, w osobnym folderze.

Jeśli znacznik czasu ISO 8601 jest częścią nazwy pliku, po prostu podziel go według roku, miesiąca lub dnia.

polemon
źródło
1
ls i find nie są wbudowanymi ani w bash, ani w zsh, więc nie jest jasne, w jaki sposób przełączanie powłok mogłoby pomóc w tym przypadku.
Robin Green,
Chodzi o rozszerzenie powłoki. Jeśli powłoka nie może rozwinąć globowania, może to być problem.
polemon
Zrobiłem kilka testów z systemem poleceń na około 1E6 plików ZSH napotyka te same problemy: "$ 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 ". Przepraszam, ale nie widzę, jak to się ma do pytania -1, ponieważ tak łatwo było to przetestować, utworzyć tylko pliki 1e6 i uruchomić polecenia.
1

Czy locate(i oczywiście updatedb) byłby dla ciebie pomocny?

asoundmove
źródło
1
updatedbwykorzystuje find.
dave1010
@ dave1010, oczywiście, ale robi to w tle raz na jakiś czas, więc jeśli OP może zaakceptować, że niekoniecznie musi być na bieżąco co minutę, ale może raz dziennie, a następnie zaplanuj aktualizację o spokojnej godzinie (lub harmonogram aktualizowany często, ale z niskim priorytetem, który i tak powinien być), a następnie za pomocą lokalizowania bardzo szybko znajdziesz to, czego szukasz. Kluczowym pytaniem jest więc, jak aktualna musi być DB (lub indeks dla każdego innego takiego systemu).
asoundmove