Schneller Weg, um festzustellen, ob eine Datei eine SQLite-Datenbank ist

8

Ich suche nach einer Möglichkeit, Dateitypen in einem Ordner mit Tausenden von Dateien zu bestimmen. Dateinamen verraten nicht viel und haben keine Erweiterung, sind aber verschiedene Typen. Insbesondere versuche ich festzustellen, ob eine Datei eine SQLite-Datenbank ist.

Bei Verwendung des fileBefehls wird der Typ von 2-3 Dateien pro Sekunde bestimmt. Dies scheint ein guter Weg zu sein, um das Problem anzugehen, außer es ist zu langsam.

Dann habe ich versucht, jede Datei mit sqlite3 zu öffnen und zu überprüfen, ob ich einen Fehler erhalte. Auf diese Weise kann ich 4-5 Dateien pro Sekunde überprüfen. Viel besser, aber ich denke, dass es einen besseren Weg gibt, dies zu tun.

dmars
quelle
Als Zeitreferenz, filelaufen auf 2115 Dateien ohne spezielle Optionen 0m0.117s user 0m0.078s sys 0m0.044sfür mich
Glenn Plas

Antworten:

7

2-3 Dateien pro Sekunde getestet mit filescheint mir sehr langsam. fileführt tatsächlich eine Reihe verschiedener Tests durch, um den Dateityp zu bestimmen. Da Sie nach einem bestimmten Dateityp (SQLite) suchen und sich nicht darum kümmern, alle anderen zu identifizieren, können Sie mit einer bekannten SQLite-Datei experimentieren, um festzustellen, welcher Test sie tatsächlich identifiziert. Sie können dann die anderen mithilfe des -eFlags ausschließen und für Ihren vollständigen Dateisatz ausführen. Siehe die Manpage :

 -e, --exclude testname
         Exclude the test named in testname from the list of tests made to
         determine the file type. Valid test names are:

         apptype
            EMX application type (only on EMX).
         text
            Various types of text files (this test will try to guess the
            text encoding, irrespective of the setting of the ‘encoding’
            option).
         encoding
            Different text encodings for soft magic tests.
         tokens
            Looks for known tokens inside text files.
         cdf
            Prints details of Compound Document Files.
         compress
            Checks for, and looks inside, compressed files.
         elf
            Prints ELF file details.
         soft
            Consults magic files.
         tar
            Examines tar files.

Edit: Ich habe selbst einige Tests ausprobiert. Zusammenfassung:

  1. Das Anwenden meines Ratschlags mit den richtigen Flags kann sich filebei Tests zur Bestimmung von SQLite um etwa 15% beschleunigen . Welches ist etwas, aber nicht die enorme Verbesserung, die ich erwartet hatte.
  2. Ihre Dateitests sind sehr langsam. Ich habe 500 auf einer Standardmaschine in der Zeit gemacht, in der Sie 2-3 gemacht haben. Sind Sie auf langsamer Hardware oder überprüfen Sie riesige Dateien, führen Sie eine alte Version von aus fileoder ...?
  3. Sie müssen den "weichen" Test beibehalten, um eine Datei erfolgreich als SQLite zu identifizieren.

Für eine 16 MB SQLite-DB-Datei habe ich Folgendes getan:

#!/bin/bash
for  i in {1..1000}
do
    file sqllite_file.db | tail > out
done

Timing in der Kommandozeile:

~/tmp$ time ./test_file_times.sh; cat out

real    0m2.424s
user    0m0.040s
sys 0m0.288s
sqllite_file.db: SQLite 3.x database

Wenn Sie versuchen, die verschiedenen Tests auszuschließen, und vorausgesetzt, dass die Bestimmung auf der Grundlage eines einzelnen Tests erfolgt, ist es der "weiche" Test (dh die Suche nach magischen Dateien), der die Datei identifiziert. Dementsprechend habe ich den fileBefehl geändert , um alle anderen Tests auszuschließen:

file -e apptype -e ascii -e encoding -e tokens -e cdf -e compress -e elf -e tar sqllite_file.db | tail > out

1000 Mal ausgeführt:

~/tmp$ time ./test_file_times.sh; cat out

real    0m2.119s
user    0m0.060s
sys         0m0.280s
sqllite_file.db: SQLite 3.x database
ire_and_curses
quelle
Danke für die ausführliche Antwort. Ich fand auch heraus, dass ein "weicher" Test erforderlich ist. Das Ausschalten der anderen Tests (bei 10000 Iterationen) ergab ungefähr das gleiche Ergebnis.
dmars
Nach Ihrem Kommentar, dass die Ausführungszeit zu langsam ist, habe ich angefangen, die Prozedur, die sie ausführt, in Frage zu stellen, und festgestellt, dass dies sqlite=$(echo $filetype | grep -c SQLite)mindestens die gleiche Zeit wie der Dateibefehl erfordert. Und ich habe einige andere Befehle, die den Vorgang zusätzlich verlangsamen. Interessanterweise war das Ausführen sqlite3 $filename ".schema"immer noch zweimal schneller als der Dateibefehl.
dmars
4

Wenn Sie sich Folgendes ansehen: http://www.sqlite.org/fileformat.html , beginnt das SQLite-Format mit der Zeichenfolge "SQLite-Format 3 \ 000". Es scheint mir, dass Sie head -c 16die Datei überprüfen könnten , um das Format zu überprüfen. Ich würde erwarten, dass dies schneller ist als mit allgemeineren Tools.

Winston Ewert
quelle
3

Wenn Sie sich filedie magische Beschreibung für SQLite-Dateien ansehen , sucht sie entweder SQLite format 3oder ** This file contains an SQLiteam Anfang der Datei.

Sie können also entweder eine magische Datei mit nur diesen Überprüfungen erstellen (und die integrierten Tests wie in der Lösung @ire_and_curses deaktivieren) oder die Überprüfung manuell durchführen:

case $(head -c 31 < "$file") in
  ("** This file contains an SQLite"*) echo sqlite 2;;
  ("SQLite format 3"*) echo sqlite 3;;
esac

Nicht sehr effizient, da eine headDatei ausgeführt wird. Mit ein wenig Aufwand könnten Sie es wahrscheinlich in Perl tun, um die ersten 31 Bytes mehrerer Dateien in einem Perl-Aufruf zu lesen.

Stéphane Chazelas
quelle
Vielen Dank. Es stellte sich heraus, dass der Versuch, mit sqlite3 zu öffnen, immer noch der schnellere Weg war. In Bezug auf die Leistung lag das Problem hauptsächlich bei anderen Befehlen in der Prozedur, die ich nicht berücksichtigt habe.
dmars