2016-02-29 11 views
9

Ich muss eine C++ - Routine entwickeln, die diese scheinbar triviale Aufgabe ausführt: Erstellen Sie eine Datei nur, wenn sie nicht existiert, sonst nichts/Fehler melden.Erstellen einer neuen Datei unter Vermeidung von Race-Bedingungen

Da ich Race Conditions vermeiden muss, möchte ich das Prinzip "Bitte Vergebung nicht Erlaubnis" verwenden (dh die beabsichtigte Operation versuchen und überprüfen, ob es erfolgreich war, im Gegensatz zur Überprüfung der Vorbedingungen), die meines Wissens , ist die einzige robuste und portable Methode für diesen Zweck [Wikipedia article][an example with getline].

Noch konnte ich einen Weg finden, um es in meinem Fall zu implementieren. Das beste, was ich mir vorstellen konnte, ist das Öffnen eines fstream in app Modus (oder ing mit "a"), das Überprüfen der Ausgabeposition mit tellp (C++) oder ftell (C) und Abbrechen, wenn diese Position nicht Null ist. Dies hat jedoch zwei Nachteile, nämlich dass, wenn die Datei existiert, sie gesperrt wird (wenn auch für eine kurze Zeit) und ihr Änderungsdatum geändert wird.

Ich habe andere mögliche Kombinationen von ios_base::openmode für fstream, sowie die mode Saiten fopen aber keine Option gefunden, die meine Bedürfnisse. Die weitere Suche in den C- und C++ - Standardbibliotheken sowie im Boost-Dateisystem erwies sich als unfruchtbar.

Kann jemand auf eine Methode hinweisen, um meine Aufgabe auf eine robuste Art und Weise auszuführen (keine Nebeneffekte, keine Race Conditions), ohne auf OS-spezifische Funktionen angewiesen zu sein? Mein spezifisches Problem ist in Windows, aber tragbare Lösungen würden bevorzugt.

EDIT: Die Antwort von BitWhistler löst das Problem für C-Programme vollständig. Dennoch bin ich erstaunt, dass keine C++ idiomatische Lösung zu existieren scheint. Entweder benutzt man open mit dem O_EXCL Attribut wie von Andrew Henle vorgeschlagen, das jedoch OS-spezifisch ist (in Windows scheint das Attribut _O_EXCL mit einem zusätzlichen Unterstrich [MSDN] genannt zu werden) oder man kompiliert eine C11-Datei und verknüpft sie aus dem C++ Code . Darüber hinaus kann der erhaltene Dateideskriptor nicht in einen Strom umgewandelt werden, außer bei nicht standardmäßigen Erweiterungen (z. B. GCC's __gnu_cxx::stdio_filebuf). Ich hoffe, dass eine zukünftige Version von C++ das "x" Subattribut und möglicherweise auch einen entsprechenden ios:: Modifikator für Dateiströme implementiert.

+0

Haben Sie Rennbedingungen zwischen mehreren Threads oder mehrere Prozesse vermeiden wollen? – user2807083

+3

Was ist dein Betriebssystem? POSIX bietet ['open (Dateiname, O_CREAT | O_EXCL ...)'] (http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html), um das zu tun, was Sie tun möchten. –

+1

Win32-API ermöglicht dies. Ich weiß das sicher. –

Antwort

3

Der neue C-Standard (C2011, der nicht Teil von C++ ist) fügt einen neuen Standardunterspezifikator ("x") hinzu, der an jeden beliebigen "w" -Spezifikator angehängt werden kann (um "wx", "wbx" zu bilden) "w + x" oder "w + bx"/"wb + x"). Dieser Unterspezifikator erzwingt, dass die Funktion fehlschlägt, wenn die Datei existiert, anstatt sie zu überschreiben.

Quelle: http://www.cplusplus.com/reference/cstdio/fopen/