Textfile schließen/löschen - mit Versuchszähler

Folgende Funktion kann als einfache Vorlage genutzt werden um geöffnete Textfiles zu schließen und eventuell anschließend zu löschen.

Parameter Beschreibung
const FILE ** fileToClose Adresse der FILE-Variable
const char * fileNameToDeleteFQ Filename, das gelöscht werden soll
int modus Zum Schließen / zum Schließen+Löschen
int maxRetry Maximale Zahl der Versuche, File zu schließen/löschen
int retryDelay Pause in Sekunden zwischen den Versuchen

:!: Alle im Quelltext festkodierte Konstanten sind nur Beispielswerte. Bei konkreter Umsetzung sollen die Werte verwendet werden, die für die jeweilige Anwendung für sinnvoll erscheinen. Noch sinnvoller wäre anstelle von festkodierten Konstanten globale Variablen oder Makros einzusetzen, damit solche Werte auf einfache Weise anwendungsweit angepaßt werden könnten.

int done_EinAusFile (const FILE ** fileToClose, const char * fileNameToDelete, int modus, int maxRetry, int retryDelay)
{
	int rc = RC_OK;
	int retry;
	int notDeleted;
 
	// Validierung: Vorhandensein von Variablen (darf kein NULL sein)
	if (!fileToClose) rc = RC_ERROR;
	// Validierung: Werte dürfen sich nur im definierten Bereich bewegen
	if (!(modus == FILE_CLOSE || modus == FILE_DELETE)) rc = RC_ERROR; // Darf 3 oder 4 sein
	if ((maxRetry < 1) || (maxRetry > 32767)) rc = RC_ERROR; // 1 bis 15^2-1 mal
	if ((retryDelay < 0) || (retryDelay > 86400)) rc = RC_ERROR; // 24 Std x 60 Min x 60 Sek
	// Validierung: Pointer-Variablen: Werte nur im definierten Bereich
	if (fileNameToDelete) if (strlen(fileNameToDelete) == 0 || strlen(fileNameToDelete) > FILENAME_LAENGE) rc = RC_ERROR; // Länge des Filenames
	if (fileToClose) if (!(*fileToClose)) rc = RC_ERROR; // File MUSS bereits geöffnet sein
	// Validierung: Kombination von Werten
	if (modus == FILE_DELETE) if (!fileNameToDelete) rc = RC_ERROR; // Beim Löschen muss der Filename angegeben werden
 
	if (rc) fprintf(stderr, "done_EinAusFile(): Validierungsfehler.\n");
 
	if (!rc) // File schließen
	{
		fprintf(stdout, "done_EinAusFile(): File [%s] wird geschlossen...\n", fileNameToDelete ? fileNameToDelete : "(FileName nicht angegeben)");
 
		for (retry = maxRetry; (retry > 0) && (*fileToClose); retry--) // Evtl. mehrere Versuche
		{
			if (fclose(*fileToClose) == 0) *fileToClose = NULL; // Falls erfolgreich geschlossen, den Zeiger zurücksetzen
 
			if ((retry > 1) && (*fileToClose)) sleep(retryDelay); // Falls Mißerfolg - kurze Pause einlegen (außer nach dem letzten Versuch).
		} // for (retry)
 
		if (!(*fileToClose)) fprintf(stdout, "done_EinAusFile(): ...erfolgreich\n");
		else rc = RC_ERROR;
 
		if (rc) fprintf(stderr, "done_EinAusFile(): Fehler beim Schließen des Files aufgetreten.\n");
	} // if
 
	if ((!rc) && (modus == FILE_DELETE)) // File löschen
	{
		fprintf(stdout, "done_EinAusFile(): File [%s] wird gelöscht...\n", fileNameToDelete);
 
		for (retry = maxRetry, notDeleted = 1; (retry > 0) && (notDeleted); retry--) // Evtl. mehrere Versuche
		{
			if (remove(fileNameToDelete) == 0) notDeleted = 0; // Falls erfolgreich gelöscht, den Flag zurücksetzen
 
			if ((retry > 1) && (notDeleted)) sleep(retryDelay); // Falls Mißerfolg - kurze Pause einlegen (außer nach dem letzten Versuch).
		} // for (retry)
 
		if (!notDeleted) fprintf(stdout, "done_EinAusFile(): ...erfolgreich\n");
		else rc = RC_ERROR;
 
		if (rc) fprintf(stderr, "done_EinAusFile(): Fehler beim Löschen des Files [%s] aufgetreten.\n", fileNameToDelete);
	} // if
 
	fflush(stderr);
	fflush(stdout);
 
	return rc;
} // done_EinAusFile(..)

wobei:
RC_OK und RC_ERROR, FILE_CLOSE und FILE_DELETE, FILENAME_LAENGE sind die vom Benutzer definierten Makros.

Beispiel eines Aufrufs:

#define FILENAME_LAENGE	8191
 
// TextFile schliessen
#define FILE_CLOSE	3
// TextFile schliessen und loeschen
#define FILE_DELETE	4
// Beim Öffnen maximal so viele Versuchen unternehmen:
#define FILE_RETRY	3
// Zwischen den Wiederholungen so viele Sekunden warten:
#define FILE_DELAY	1
 
 
FILE * fileInputDatei  = NULL; // Input-Datei
FILE * fileOutputDatei = NULL; // Output-Datei
 
 
char parFileNameInputDatei  [FILENAME_LAENGE + 1]; // FileName für die Input-Datei
char parFileNameOutputDatei [FILENAME_LAENGE + 1]; // FileName für die Output-Datei
 
 
int app_Done (int rc_Init, int rc_Run)
{
	int rc = RC_OK;
	int rc_FileClose = RC_OK;
 
	fprintf(stdout, "app_Done(): Ein-/Ausgabe-Files werden geschlossen.\n");
 
	// Die Input-Datei schließen
	if (fileInputDatei)
	{
		rc = done_EinAusFile(&fileInputDatei, parFileNameInputDatei, FILE_CLOSE, FILE_RETRY, FILE_DELAY);
		if (rc) fprintf(stderr, "app_Done(): ERROR (unkritisch): Das Schließen des Files [%s] ist fehlgeschlagen.\n", parFileNameInputDatei);
	} // if
 
	// Die Output-Datei schließen und löschen
	if (fileOutputDatei)
	{
		rc = done_EinAusFile(&fileOutputDatei, parFileNameOutputDatei, FILE_DELETE, FILE_RETRY, FILE_DELAY);
		if (rc) fprintf(stderr, "app_Done(): ERROR (kritisch): Das Schließen des Files [%s] ist fehlgeschlagen.\n", parFileNameAbkDatei);
	} // if
 
	if (rc_FileClose) errorMsgFatal(TODO_KEINABBRUCH, "app_Done(): Eine der Dateien konnte nicht geschlossen werden. Sie ist möglicherweise beschädigt und kann nicht verwendet werden.");
 
	fflush(stderr);
 
	return rc;
} // app_Done()

wobei:
errorMsgFatal() - eine Funktion, die kritische Meldungen ausgibt (und z.B. im Syslog protokolliert) und je nach Parameter, falls nötig, den Prozess zwangsweise abbricht.

Und ab und zu fflush(stderr); bzw. fflush(stdout); auch nicht vergessen.


Stand: 24.02.2010
: Jürgen Kreick

EOF