5 Stimmen

Wie kann ich sicher in einen gegebenen Dateipfad in Cocoa schreiben, indem ich bei Bedarf ein numerisches Suffix hinzufüge?

Wir wollen in die Datei "foo.txt" in einem bestimmten Verzeichnis schreiben. Wenn "foo.txt" bereits existiert, soll in "foo-1.txt" geschrieben werden, usw.

Es gibt ein paar Codeschnipsel, die versuchen, diese Frage zu beantworten, aber keiner davon ist wirklich zufriedenstellend. Z.B.. diese Lösung bei CocoaDev verwendet NSFileManager, um zu prüfen, ob ein Pfad existiert, um einen sicheren Pfad zu erstellen. Dies führt jedoch zu offensichtlichen Race Conditions zwischen dem Abrufen eines Pfades und dem Schreiben in diesen. Es wäre sicherer, atomare Schreibvorgänge zu versuchen und bei Fehlern das numerische Suffix in einer Schleife zu speichern.

Los geht's!

1voto

Peter Hosey Punkte 94684

を使用します。 open Systemaufruf mit dem O_EXCL y O_CREAT Möglichkeiten. Wenn die Datei nicht bereits existiert, open erstellt sie, öffnet sie und gibt den Dateideskriptor an Sie zurück, falls er existiert, open scheitert und setzt errno a EEXIST .

Von dort aus sollte es offensichtlich sein, wie man die Schleife konstruiert, die versucht, die Dateinamen zu inkrementieren, bis sie einen Dateideskriptor zurückgibt oder einen zu langen Dateinamen konstruiert. In Bezug auf den letzten Punkt sollten Sie sicherstellen, dass Sie die errno wenn open scheitert - EEXIST y ENAMETOOLONG sind nur zwei der Fehler, auf die Sie stoßen können.

1voto

Jason Coco Punkte 77369
int fd;
uint32_t counter;
char filename[1024]; // obviously unsafe

sprintf(filename, "foo.txt");
if( (fd = open(filename, O_CREAT | O_EXCL | O_EXLOCK, 0644)) == -1 && errno == EEXIST ) 
{
    for( counter = 1; counter < UINT32_MAX; counter++ ) {
      sprintf(filename, "foo-%u.txt", counter);
      if( (fd = open(filename, O_CREAT | O_EXCL | O_EXLOCK, 0644)) == -1 && errno == EEXIST )
        continue;
      else
        break;
    }
}

if( fd == -1 && counter == UINT32_MAX ) {
    fprintf(stderr, "too many foo-files\n");
} else if( fd == -1 ) {
    fprintf(stderr, "could not open file: %s\n", strerror(errno));
}

// otherwise fd is an open file with an atomically unique name and an
// exclusive lock.

1voto

Mike Abdullah Punkte 14832

Wie wäre es damit:

  1. Schreiben Sie die Datei in ein temporäres Verzeichnis, von dem Sie wissen, dass es keine Kollisionen geben kann.
  2. Verwenden Sie NSFileManager, um die Datei an das gewünschte Ziel zu verschieben
  3. Wenn Schritt 3 fehlschlägt, weil bereits eine Datei vorhanden ist, fügen Sie ein numerisches Suffix hinzu und wiederholen Sie Schritt 2.

Sie würden im Grunde Cocoa's atomare Datei schreiben Handhabung neu zu erstellen, sondern fügen Sie die Funktion der Gewährleistung einer eindeutigen Dateinamen. Ein großer Vorteil dieses Ansatzes ist, dass, wenn der Strom ausfällt oder Ihre Anwendung mitten im Schreibvorgang abstürzt, die halbfertige Datei in einem tmp-Ordner versteckt und vom System gelöscht wird; nicht für den Benutzer verlassen, um zu versuchen und arbeiten mit.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X