[c] fread() Programmabsturz

cwriter

Erfahrenes Mitglied
Hallo Welt

Ich habe folgendes Problem:
Ich möchte eine Datei binär auslesen und dann in eine andere Datei schreiben. Dazu benutze ich fread(), da fgets() ja nicht binär funktioniert. Es funktioniert soweit auch alles, nur mit meinem Versuchscode:
C:
//i = Grösse der zu kopierenden Datei, j ist der Zähler
//char temp hat grösse [4]
//f = zu kopierende Datei
while(j != i)
{
	fseek(f,j,SEEK_SET);
	fread(temp,1,1,f);
	fprintf(target,"%c",temp[0]);
	j++;
}
dauert das halt bei grossen Dateien ewig. Deshalb wollte ich das ganze ein wenig beschleunigen:
C:
//temp auf 1024 gesetzt
while(j != i && (i-j) >= 10)
{
	fseek(f,j,SEEK_SET);
	fread(temp,10,10,f);
	fprintf(target,temp);
	j = j+10;
}
while(j != i)
{
	fseek(f,j,SEEK_SET);
	fread(temp,1,1,f);
	fprintf(target,"%c",temp[0]);
	j++;
}
Resultat: Programmabsturz. Was mache ich falsch?


Gruss
cwriter
 
Hi

in welcher Zeile passiert es?
Warum immer ein fseek?
Warum 1024, wenn du nur 10 nimmst?

printf ist auch nicht für binäres Zeug geeignet.
Das wird der Absturzgrund sein.
Dafür gibts fwrite.

int i = Grösse der zu kopierenden Datei, int j ist der Zähler
char temp hat grösse [1024]
f = zu kopierende Datei
target = Zieldatei
C++:
//öffnen...
int k;
while(j < i)
{
    K = i - j;
    if(k > 1024)
        k -= 1024;
    if(k != fread(temp, 1, k, f))
        //Fehler, Ende
    if(k != fwrite(temp, 1, k, target))
        //Fehler, Ende
    j += k;
}
//schließen...
Ungetestet.

Gruß
 
Vielen Dank für die Hilfe sheel

Ich Trottel habe aber dem falschen char array 1024 zugewiesen :-( Man kann ja auch schlecht 10 chars in einen 4 array schreiben...
Jetzt funktioniert's auch.
Zum fprintf(): Das funktioniert eigentlich gut. Ich habe mal den Test mit einer .png-Datei gemacht. Mit fgetc() / fgets() und fputc() / fputs() geht's nicht, mit fread() / fprintf() aber sehr gut.

Naja, nochmal Danke für die Hilfe und Entschuldigung für die Nichtigkeit :-(

cwriter
 
DOch doch, mit fgetc/fputc gehts schon auch.
Die machen nur alles einzeln.

Und wenns mit fprintf bei dir geht ist das nur Glück.
Da eigentlich ein \0-terminierter String reingehört, darf das so gar nicht funktionieren.
Hast zufällig einen \0 dahinter rein kompiliert...muss aber nicht jedesmal so sein.
 
Ok, geht nun doch nicht. Dafür gibt's eine andere Fehlermeldung. Juchu :rolleyes:
Code:
fread:
Expression: num <= (SIZE_MAX / elementSize)
Weisst du etwas? Code:
C:
int packe(char Obj1[],char Obj2[],char Ziel[])
{
	//PACKEN
	char path[256];
	sprintf(path,"%s.xyz",Ziel);
	FILE* target = fopen(path,"wb");
	FILE* f = fopen(Obj1,"rb");
	if(f == NULL) return -1;
	unsigned long i = 0;
	unsigned long j = 0;
	char temp[102400];
	while(fgetc(f) != EOF) i++;
	printf("Dateigroesse: %d\n",i);
	fprintf(target,"%d:",i);
	
	while(j != i && (i-j) >= 100000)
	{
		fseek(f,j,SEEK_SET);
		fread(temp,100000,100000,f);
		fprintf(target,temp);
		j = j+100000;
	}
	while(j != i && (i-j) >= 10000)
	{
		fseek(f,j,SEEK_SET);
		fread(temp,10000,10000,f);
		fprintf(target,temp);
		j = j+10000;
	}
	while(j != i && (i-j) >= 1000)
	{
		fseek(f,j,SEEK_SET);
		fread(temp,1000,1000,f);
		fprintf(target,temp);
		j = j+1000;
	}
	while(j != i && (i-j) >= 100)
	{
		fseek(f,j,SEEK_SET);
		fread(temp,100,100,f);
		fprintf(target,temp);
		j = j+100;
	}
	while(j != i && (i-j) >= 10)
	{
		fseek(f,j,SEEK_SET);
		fread(temp,10,10,f);
		fprintf(target,temp);
		j = j+10;
	}
	while(j != i)
	{
		fseek(f,j,SEEK_SET);
		fread(temp,1,1,f);
		fprintf(target,"%c",temp[0]);
		j++;
	}
	fclose(f);

Und, nein, ich terminiere nicht. Seltsam.

Gruss
cwriter
 
Zuletzt bearbeitet:
Nochmal Kurz: (f/s/w/v/bla-) printf DARF NICHT funktionieren.
Das solls gar nicht. Je nach Compiler/Datei wirds manchmal funktionieren, manchmal abstürzen, manchmal falsche Daten in die Datei schreiben (Bytes auslassen oder falsche Bytes dazunehmen).

Und zu fread/fwirte gibts mehr als einen Dokueintrag.
Du hast 102400 Arrayelemente mit je 1 Byte,
willst aber 100000 mit je 100000 Byte aus der Datei lesen.
10000000000 ist zu viel für 102400.
10GB vs 100KB
 
Oh, na aua. Ich dachte, es seien ENTWEDER 100000 Bytes ODER 100000 Zeichen. Ich habe es jetzt auf 100 Bytes / 100000 Zeichen runtergeschraubt und es funktioniert. Auch mit fprintf(). Aber vielleicht liegt das auch am VC++ Compiler.

Naja, nochmals Danke für die Hilfe

cwriter
 
:rolleyes: seufz...du wirst es schon noch merken...
Auch MS kann nicht zaubern.

Und Bytes/Zeichen: Es hat schon einen Sinn, dass man da ordentliche Werte eingeben sollte.
Es wird nicht einfach multipliziert, Big/Little-Endian spielen auch eine Rolle.
100-100 ist nicht 10000-1.

Aber mach ruhig...
 
So, jetzt verzweifle ich aber langsam:
Solange ich alles in 1-Byte-Schritten mache, geht alles gut. In grösseren aber ist die entpackte Datei beschädigt... Ich probier's jetzt mal mit fwrite(). Hoffe mal, dass das geht.

cwriter

EDIT: Ja fail, jetzt weiss ich auch, weshalb das ohne \0-Terminierung ging: Ich benutzte ja nur den [0] teil des arrays. Na super. Dann wird fwrite() wohl funktionieren. Hattest Recht sheel, wie immer :)

Also folgendes:
C:
FILE* target = fopen(path,"wb");
	FILE* f = fopen(Obj1,"rb");
	if(f == NULL) return -1;
	unsigned long i = 0;
	unsigned long j = 0;
	char temp[1024];
	while(fgetc(f) != EOF) i++;
	printf("Dateigroesse: %d\n",i);
	fprintf(target,"%d:",i);
	
	char t[256];
	itoa(i,t,10);
	while(j < i)
	{
		fseek(f,j,SEEK_SET);
		fread(temp,1024,1,f);
		fseek(target,j + strlen(t) + 1,SEEK_SET);
		fwrite(temp,1024,1,target);
		j++;
	}
	fclose(f);
Funktioniert nicht. Auch sheels Bespiel nicht. Aber mit der 1 Zeichen Technik problemlos...
 
Zuletzt bearbeitet:
Hi
Funktioniert nicht.
Was heißt denn das jetzt? Absturz? Ungültige Daten drin? Nicht vollständig geschrieben?

Grundsätzlich, bei I/O Operationen, ist es eine gute Idee eine Schleife zu bauen, die direkt von dem Erfolg der I/O Operation abhängt.

Du hast da eine Zählschleife, du prüfst keine Fehlercodes. Da kannst du überhaupt nicht sagen ob die Daten richtig gelesen und richtig geschrieben wurden.

Wenn du die ganze Datei übertragen willst, dann mach doch einfach eine while (fread(...) != NULL) Schleife.

Warum verwendest du nicht fseek + ftell zur Ermittelung der Dateigröße?

Warum schiebst du j denn immer nur 1 Zeichen weiter in der Schleife, wenn du (potenziell) 1024 Bytes gelesen hast? Das ist übrigens auch der Fehler: du liest max. 1024 Bytes, prüfst aber nie wieviel überhaupt gelesen wurden und schreibst dann immer alle 1024 Bytes raus...

Gruß
 
Zurück