Was ist die beste Vorgehensweise zum Benennen hochgeladener Bilder?

15

Angenommen, ich habe ein Formular in meiner Webanwendung, in das Benutzer ein Profilbild hochladen können.

Ich habe nur wenige Anforderungen bezüglich Dateigröße, Abmessungen usw., aber wenn der Benutzer das Bild hochlädt, wie soll ich sie auf meinem System benennen? Ich nehme an, es müsste konsistent und auch einzigartig sein.

Vielleicht eine GUID?

a5c627bedc3c44b7ae7c06a44fb3fcf8.jpg

Ein Zeitstempel?

129899740140465735.jpg

Ein Hash? Beispiel: md5

b1a9acaf295cf14ffbc5b6538294562c.jpg

Gibt es einen Standard oder einen empfohlenen Weg, dies zu tun?

Rowan Freeman
quelle
7
Wenn es Ihr Ziel ist, nur ein Profilbild pro Benutzer zu speichern, würden einige sagen, die naheliegende Wahl wäre, der Datei den gleichen Namen wie der Benutzer-ID zu geben.
Alan Barber
Der Zeitstempel ist keine gute Idee, da DateTime.Now nur alle 15 ms aktualisiert wird. Es besteht eine hohe Wahrscheinlichkeit einer Kollision, zum Beispiel während Bulkloads, Anfragen in der Warteschlange usw.
jhexp

Antworten:

27

Sie sollten versuchen, zwei Ziele zu erreichen: Einzigartigkeit und Nützlichkeit.

Die Verwendung einer GUID garantiert die Eindeutigkeit, aber eines Tages können sich die Dateien von ihrer ursprünglichen Quelle lösen, und Sie werden in Schwierigkeiten geraten.

Meine typische Lösung besteht darin, wichtige Informationen in den Dateinamen einzubetten, z. B. die Benutzer-ID (wenn sie einem Benutzer gehört) oder das Datum und die Uhrzeit des Uploads (wenn dies von Bedeutung ist) oder den beim Upload verwendeten Dateinamen.

Dies kann Ihre Haut eines Tages wirklich retten, wenn die in den Dateinamen eingebetteten Informationen es Ihnen ermöglichen, beispielsweise nach einem Fehler oder dem versehentlichen Löschen von Datensätzen wiederherzustellen. Wenn alles, was Sie haben, GUIDs sind und Sie den Katalog verlieren, werden Sie einen verdammten Job haben, der das aufräumt.

Wenn zum Beispiel eine Datei "My Holiday: Florida 23.jpg" von userID 98765 am 04.04.2013 um 12:51:23 hochgeladen wird, würde ich sie folgendermaßen benennen und eine zufällige Zeichenfolge hinzufügen ad8a7dsf9:

20130404125123-ad8a7dsf9-98765-my-holiday-florida-23.jpg

  • Die Eindeutigkeit wird durch Datum und Uhrzeit sowie durch eine zufällige Zeichenfolge sichergestellt (vorausgesetzt, diese stammt ordnungsgemäß aus / dev / urandom oder CryptGenRandom.
  • Wenn die Datei jemals getrennt wurde, können Sie den Benutzer, das Datum und die Uhrzeit sowie den Titel identifizieren.
  • Alles wird zu Kleinbuchstaben gefaltet und alles, was nicht alphanumerisch ist, wird entfernt und durch Bindestriche ersetzt, wodurch der Dateiname mit einfachen Werkzeugen leicht zu handhaben ist (z. B. keine Leerzeichen, die schlecht geschriebene Skripte verwirren können, keine Doppelpunkte oder andere Zeichen, die in einigen Dateisystemen verboten sind) , und so weiter).
Ben
quelle
7
Im Interesse der Verwaltung würde ich empfehlen, separate Verzeichnisse pro Benutzer-ID zu erstellen, damit Sie beim Löschen eines Benutzers nicht nach allen Bildern suchen müssen. - so98765/20130404125123-ad8a7dsf9-my-holiday-florida-23.jpg
Shadur
1
Theoretisch wird die Eindeutigkeit nicht durch die Zufallszeichenfolge bereitgestellt.
Kolyunya
4
@Kolyuny, das stimmt, in dem Sinne, dass garantierte globale Eindeutigkeit keine Eigenschaft ist, die selbst GUIDs im wirklichen Leben haben (selbst v1-Guids werden aufgrund der Vergabe doppelter MAC-Adressen zerstört). Alles, was Sie bekommen können, ist eine statistische Wahrscheinlichkeit der Eindeutigkeit. Sie können die Eindeutigkeit jedoch sicherstellen, indem Sie prüfen, ob die Datei bereits vorhanden ist (atomar CreateFilemit CREATE_NEW), und in diesem Fall eine andere Zufälligkeit verwenden.
Ben
‚Alles ist gefaltet in Kleinbuchstabe und etwas nicht-alphanumerische wird entfernt und durch Bindestriche ersetzt,‘ ich es gemischten Fall halten würde, entfernen Sie alle nicht alphanumerische und ersetzen mit unter Noten mit Ausnahme des letzten Strich
tgkprog
4

Sie möchten Anwendungen (z. B. Explorer) nicht belasten und beim Öffnen des Verzeichnisses zum Absturz bringen. Obwohl es unwahrscheinlich ist, dass Sie das eigentliche Dateisystem belasten, müssen Sie dies berücksichtigen, wenn Sie Tausende von Dateien speichern möchten.

Wenn Sie damit rechnen, Tausende von Dateien zu speichern, ist mein Vorschlag, in Ordner zu partitionieren. Zum Beispiel upload\silo001,upload\silo002 können usw. Sie entweder Ihre Dateien balancieren oder warten , bis ein Ordner eine bestimmte Anzahl von Dateien trifft und dann noch erstellen.

In Bezug auf die Benennung benenne ich eine Datei immer mit einer GUID, da diese global eindeutig ist. Ich ziehe die Erweiterung aus dem Upload und stelle die Erweiterung der Datei so ein, dass sie übereinstimmt, aber der tatsächliche Name wird in einer neuen Guid festgelegt.

Wenn Sie dies in Verbindung mit einem RDBMS tun und mehrere Kategorien haben, dh Produkte, Kategorien usw., die Sie haben könnten upload\products,upload\categories und so weiter, und man konnte die Zeilen - ID als Dateinamen verwenden.

Auch ich habe in der Vergangenheit nach Best Practices gesucht und nichts gefunden. Ich habe mir das oben Genannte ausgedacht, als ich mit einigen meiner Entwickler darüber gesprochen habe.

Sam
quelle
2

In einer der Lösungen, an denen ich vor Jahren gearbeitet habe, haben wir Folgendes getan: Unterordner für einen Teil der Benutzer-ID. Wenn Ihre Benutzer-ID also 232950192 lautet

Wir hätten Unterordner images / 23/29/50/192/232950192

Im letzten Ordner befinden sich Ordner für Albuns und Profilbilder usw

Wir speichern jedoch auch alles in der Datenbank und speichern es im Dateisystem, um einen schnellen Zugriff auf den Webserver zu ermöglichen (auch mit Caching).

Auf jeden Fall würde das endgültige Bild den ursprünglichen Bildnamen haben. Versionen mussten nicht aufbewahrt werden. Aber was kann mehr Unterordner unter den endgültigen Albumnamen oder in der Datenbank mit einer Versions-ID halten. Es ist schwierig, Dinge ohne zeitaufwändige und fehleranfällige Korrekturen in der aktuellen Struktur zu ändern, wenn die Produktion erst einmal angelaufen ist

Es ist sehr einfach, einen Unterordner in Java zu erstellen und eine Datei darin zu erstellen:

    File folder = new File(pathwithslashes);// like "images/23/29/50/192/232950192"
    folder.mkdirs();
    File imgFile = new File(folder, name);
    //Now get output stream etc

So rufen Sie den Datumsstempel in Unterordnern ab: SimpleDateFormat sdf = new SimpleDateFormat ("/ jjjj / MM / tt /"); pathwithslashes = pathwithslashes + sdf.format (jetzt); // jetzt ist ein util.Date File folder = new File (pathwithslashes);

Dot net /programming/5482230/c-sharp-equivalent-of-javas-mkdirs

tgkprog
quelle
+1 für das Vorschlagen von verschachtelten Verzeichnissen. Ich denke , das ist wichtig, da unterschiedliche Dateisysteme zu prüfen , können Leistungsprobleme auftreten , wenn Ordner „zu viele“ Dateien enthalten: stackoverflow.com/questions/197162/... , support.microsoft.com/kb/130694/en-us etc.
Deizel
1
Ja, auf einem anderen System hing einer der Webserver, als wir versuchten, rmdir auf einem Verzeichnis mit mehr als 400.000 Dateien auszuführen. Wir hatten mehr Ordner wie diesen. Verwenden Sie dann ein benutzerdefiniertes Programm mit dem Namen dir / p, um einige Dateien gleichzeitig zu löschen. dauerte ein paar Stunden, aber keine
Ausfallzeit
1

Ich würde empfehlen, nur md5 oder ähnliches zu verwenden. Durch das Umbenennen von Dateien durch Auflösen von Inhalten wird nicht nur die Eindeutigkeit gewährleistet (Bilder immer so lange wie möglich zwischenspeichern, und durch das inhaltsbasierte Umbenennen können Sie Bilder praktisch für immer zwischenspeichern).

Auch das ist keine große Sache, aber es ist kein rein hypothetischer Fall, wenn verschiedene Benutzer genau das gleiche Bild hochladen. Direkt nach dem Auspacken haben Sie eine kleine Optimierung der Datenspeicherung.

Wie für etwas anderes vorgeschlagen: wie für mich, ich bin ein starker Gegner zu halten jede Art von Zusatzinformationen in einem Dateinamen. Als ich viel jünger war (und ein bisschen schlanker :), war ich ein Perl-Entwickler und hatte die zweifelhafte Angewohnheit, so viele Zusatzinformationen im Dateinamen zu speichern, wie es mir der gesunde Menschenverstand erlaubte, da die Perl-String-Pattern-Funktionen fantastisch sind. Und ich bin zu dem Schluss gekommen, dass es im Zusammenhang mit der Webentwicklung immer besser ist, die mit der Datei verknüpften Daten vom Dateinamen getrennt zu halten.

Denken Sie daran, dass heutzutage, wenn mobile Schnittstellen dominieren, der tatsächliche Dateiname eine weniger wichtige Sache ist als vor 5, 10 Jahren. Aber selbst wenn dies im Kontext Ihrer Anwendung von entscheidender Bedeutung ist, können Sie immer ein wenig Old-School-Magie in die Einbindung von Content-Disposition: attachment; filename="pretty_file_name.jpg"HTTP-Headern mit einbeziehen und einen beliebigen relevanten Dateinamen erstellen. Außerdem ebnen moderne Browser den Weg zum neuen HTML5-Attribut Download . Ich glaube nicht, dass Sie in den meisten Fällen darüber nachdenken sollten, wenn Sie tatsächlich einen von Menschen lesbaren Bildnamen sehen.

UPD: Eine Änderung kann vorgenommen werden, um nicht zu viele Dateien in einem Verzeichnis zu haben. Nehmen Sie einfach den ersten 3 Buchstaben und erstellen Sie das Verzeichnis.

shabunc
quelle
1
ist md5 wirklich einzigartig?
I.devries
@ I.devries, ich bin kein Spezialist, aber soweit ich weiß, ist es für diese Zwecke gut genug. Vor allem , wenn Sie zusätzlich die Größe der Datei überprüfen, da eine gute Hash - Algorithmus tatsächlich , dass gleich große Einheiten gewähren wird weniger wahrscheinlich eine Kollision haben - stackoverflow.com/questions/2442632/...
shabunc
-1

Die Wahrscheinlichkeit von Kollisionen mit so etwas wie sha4 ist unendlich gering. Wenn Sie den Hash mit der Benutzer-ID oder sogar einem einfachen Datum kombinieren, ist dies umso weniger der Fall.

Evan Zamir
quelle