[C] fclose(file) dauert lang, warum?

posi90

Erfahrenes Mitglied
Hallo,

Mein Programm lädt über FTP eine 700 mb Datei runter und speichert diese blockweise auf eine Datei. Es dauert immer ne Weile bis ich das Programm beenden kann.
Erst dachte ich es lag an der recv-Funktion, dass die hängen bleibt, doch dann bemerkte ich, dass es an dem abschließenden fclose() liegt.

Warum dauert das so lange?
Kann man das nicht schneller machen?
Was macht dieses fclose() eigentlich genau?

Programmiere mit MVC++ eine Konsolenanwendung, wird aber später in eine Win32 Anwendung includiert.

mfg. Poseidon
 
Öhm fclose() schließt die angegebene Datei und damit andere Programme wieder Zugriff darauf haben.
Bist du sicher, dass es an fclose() liegt? Vielleicht ist dein Programm mit dem Schreiben der Daten in die Datei noch nicht fertig. Schreibst du vielleicht mit einem anderen Thread in die Datei? Was sagt der Debugger?

MfG Manuel
 
Hi,

das fclose() kann länger dauern, wenn das Betriebssystem die Daten noch nicht auf den Datenträger durch-geschrieben habt und somit noch in einem Cache / Puffer oder dergleichen hat. Der Aufruf von fclose() ruft erstmal fflush() auf, wodurch die Daten dann endgültig geschrieben werden. Das dauert halt seine Zeit.

Mein Tip: Wenn du die Daten empfängst, dann rufe alle 8 MB (oder größer / kleiner, musst halt ein bisschen experimentieren) die Funktion fflush() auf, dann sollte das schließen der Datei schneller gehen.

Gruß
BK
 
Hallo,

Ja, ich bin mir ziemlich sicher, dass das fclose die Verzögerung verursacht. So sieht mein code aus:

C++:
	while(1)
	{
		FD_ZERO(&rfds);
		FD_SET(dat_sock,&rfds);
		tv.tv_sec = 0; tv.tv_usec = 0;
		rc=select(0,&rfds, NULL, NULL, &tv);
		
		if(rc==1)
		{
			len=recv(dat_sock, pbuff, DAT_RECV_BUFFLEN,0);
			if(len==0) break;	
			fwrite(pbuff,len,1,f);			
		}
	}
	printf("Download finnished.");
	fclose(f);//<- Hier die Verzögerung
	printf("fclose() finnished.");
	getchar();

Ich werd das gleich mal mit dem fflush() ausprobiern.
Mein Server überträgt 100mb/sek++ , danke der SSD, und mein Ziel ist eine externe HDD.

Danke auf jeden Fall für den Tipp =)

mfg. Poseidon
 
Hm... die Downloadrate ist etwas langsamer, leider hat sicht nichts verändert. Auch nicht wenn ich jedes mal nach der Funktion fwrite() die Funktion fflush aufrufe. Von SSD zu SSD funktioniert es, nur von SSD zur externen HDD noch nicht.

So sieht nun mein recieve Abschnitt aus:

C++:
	int flushcount=0;

	for(;;flushcount++)
	{
		FD_ZERO(&rfds);
		FD_SET(dat_sock,&rfds);
		tv.tv_sec = 0; tv.tv_usec = 0;
		rc=select(0,&rfds, NULL, NULL, &tv);
		
		if(rc==1) 
		{
			len=recv(dat_sock, pbuff, DAT_RECV_BUFFLEN,0);//DAT_RECV_BUFFLEN=512
			if(len==0) break;	
			fwrite(pbuff,len,1,f);
			//fflush(f);
			if(flushcount>=16384) //alle ~8mb
			{					
					fflush(f);
					flushcount=0;
			}			
		}
	}
	printf("Download finnished!");
	fclose(f);
	printf("File closed.");

mfg. Poseidon
 
Zuletzt bearbeitet:
Hi.

Was heißt denn "es dauert lange"?

Was ist das für eine externe HDD? Welche Schnittstelle? USB 2.0 High Speed?

USB 2.0 High Speed schafft max. ungefähr 40MB/s zu übertragen. Normale Platten liegen beim Schreiben um die 24MB/s.

D.h. mit mind. 30 Sek. mußt du schon rechnen bis die Datei auf der externen Platte landet - wo die Verzögerung auftritt dürfte letztlich egal sein, oder?!

Gruß
 
USB 2.0 High Speed denke ich mal, also der Download fängt langsam an und steigert sich bis ~27MB/sek.
Die Zeit, die zwischen der Ausgabe: "Download finnished!" und "File closed." vergeht beträgt ~8.5 Sek.
Wobei fflush jede Runde ausgeführt wird, also nach jedem fwrite().

Der Download dauert laut FileZilla Server Interface 28 Sek. Und dann halt noch die 9 Sek. vom fclose() dran ...

Zu den Daten von der Festplatte: Chiligreen MediaDisk II mit 1TB Speicher, eine SAMSUNG HD 103SJ ist da verbaut.

mfg.
 
USB 2.0 High Speed denke ich mal, also der Download fängt langsam an und steigert sich bis ~27MB/sek.
Die Zeit, die zwischen der Ausgabe: "Download finnished!" und "File closed." vergeht beträgt ~8.5 Sek.
Wobei fflush jede Runde ausgeführt wird, also nach jedem fwrite().

Der Download dauert laut FileZilla Server Interface 28 Sek. Und dann halt noch die 9 Sek. vom fclose() dran ...
Wie lange der Download braucht ist nicht so relevant. Es braucht seine Zeit bis die Datei auf der Platte ist.

Die genannten Zeiten erreicht man nur unter optimalen Bedingungen. 30 Sek sind die absolute Obergrenze. 37 Sek. hört sich ziemlich gut an.

Dabei spielen einige Faktoren eine Rolle:

USB Controller
USB Hub?
Write Behind Cache (angeschaltet?)
Cache auf der Platte selbst

Du könntest höchstens statt fflush mal das probieren:
C:
HANDLE hf = _get_osfhandle(_fileno(f));

for (...) {
  FlushFileBuffers(hf);
}
Das sollte eine Änderung im Verhalten bringen (so dass fclose nicht mehr so lange braucht), aber wohl kaum eine Geschwindigkeitssteigerung insgesamt.

Gruß
 
Sehr merkwürdig. Ich hab ja schon viel mit Dateien gemacht, sowohl sehr große als auch kleine aber noch NIE musste ich ansatzweise auch nur 1s warten bei fclose...geschweigedenn 8-9s.
Prüf doch mal vor dem Aufruf von fclose(), ob die Datei schon komplett geschrieben wurde.
 
_get_osfhandle(); gibt einen intptr_t-Wert zurück, keinen HANDLE-Wert. Funktioniert bei mir nicht.

Zu den Faktoren: Ich weiß das alles nicht so genau, welchen controller oder cache die Platte hat. Ein USB Verteiler ist auch nicht dazwischen, einfach am Motherboard angeschlossen. Falls es nur an der Platte liegt wäre das Thema hier abgeschlossen, da das Programm nicht nur für diese HDD gecoded wird.

Wie kann ich denn prüfen ob die Datei schon komplett geschrieben wurde? Habe nun überall ein fflush() reingetan wo es sinnvoll ist. Keine Änderung.

Die datei wurde übrigends so geöffnet:
C++:
 f=fopen("test.avi","wb");


mfg. Poseidon
 
Zurück