Binärdateien kopieren

Pitchblack

Mitglied
Hallo,
ich versuche eine Funktion zu erstellen, die eine Binärdatei kopiert. Ich stoße dabei allerdings auf Probleme mit der write() Methode. Mir ist nicht ganz klar, wie ich sie einsetzen muss.

Hier erstmal mein Code:

Code:
void kopieren_binaer(char cVon[100],char cNach[100]){
	ifstream In;
	ofstream Out;

	In.open(cVon,ios::binary);
	if(!In){
		cout<<"Datei nicht vorhanden";
		exit(-1);
	}
	Out.open(cNach,ios::binary);
	if(!Out){
		cout<<"Datei konnte nicht geoeffnet werden";
		exit(-1);
	}
	while(!In.bad()){
		Out.write(cNach); //Problem
	}

}

Die formalen Parameter stellen jeweils den Pfad dar.
Ich hoffe, jemand weiß weiter.
 
Du solltest erst etwas lesen (mit read(...)), und es dann schreiben (mit write).
Am besten ermittelst Du erst die Dateigröße, legst dann einen Puffer im Speicher in dieser Größe an. Dann liest Du die Datei en bloc in den Puffer ein, danach schreibst Du den Puffer in die Zieldatei.
Schau' Dir mal folgende istream-Methoden an: seekg, tellg, read, write.
Und vergiss nicht, die Dateien danach auch wieder zu schließen.
 
So, ich habe es jetzt soweit umgeschrieben:

Code:
#include<iostream>
#include<fstream>
using namespace std;
void main(){
	char cVon[100];
	char cNach[100];

	cout<<"Quelle: ";
	cin>>cVon;
	cout<<"\nZiel: ";
	cin>>cNach;

	ifstream In;
	ofstream Out;
	int laenge;
	char *buffer;

	In.open(cVon,ios::binary);
	if(!In){
		cout<<"Datei nicht vorhanden";
		exit(-1);
	}
	//Dateigröße bestimmen
	In.seekg(ios::end); 
	laenge=In.tellg();   
	In.seekg(ios::beg);

	//Speicher alloziieren
	buffer=new char [laenge];

	In.read(buffer,laenge);
	In.close();

	
	Out.open(cNach,ios::binary);
	if(!Out){
		cout<<"Datei konnte nicht geoeffnet werden";
		exit(-1);
	}
	In.close();
	Out.write(buffer,laenge);
	Out.close();
}

Das Problem ist aber, dass die Länge immer 2 beträgt und die Daten somit unvollständig in den Buffer eingelesen werden.
 
Bis auf die Tatsache, daß Du 'in.close()' zweimal aufrufst ist der Code. soweit ich sehen kann, eigentlich korrekt. So sollte es funktionieren. Du solltest nur noch den mit 'new' allokierten Puffer mit 'delete[]' wieder freigeben.
Wie groß ist denn die Datei?

EDIT: Ich hab Deinen Code mal ausprobiert, bei mir ist die Länge ebenfalls 2. Warum das so ist, weiß ich im Moment allerdings auch nicht. Leider habe ich mit der STL noch relativ wenig Erfahrung, da ich meistens MFC programmiere.
Bestimmt gibt es hier jemanden, der das Rätsel lösen kann :-)
 
Zuletzt bearbeitet:
Delete habe ich eingefügt und das doppelte close entfernt.

Das Problem ist aber immer noch da. Die Dateien sind unterschiedlich groß. Meistens zwischen 1kb und 500kb. Ich wüsste aber nicht, dass die Größe der Datei relevant ist.

Die Methode tellg() gibt mir immer 2 zurück. Somit werden auch immer nur die ersten 2 Zeichen kopiert.
 
Ich habe es gelöst.

Hier der Code:

Code:
#include<iostream>
#include<fstream>
using namespace std;
void main(){
	char cVon[100],cNach[100];

	cout<<"Quelle: ";
	cin>>cVon;
	cout<<"Ziel: ";
	cin>>cNach;

	ifstream In;
	ofstream Out;
	int laenge;
	char *buffer;

	In.open(cVon,ios::binary);
	if(!In){
		cout<<"Datei nicht vorhanden";
		exit(-1);
	}
	//Dateigröße bestimmen
	In.seekg(0,ios::end); //hier war der Fehler. seekg() erwartete zwei Parameter
	laenge=In.tellg();   
	In.seekg(0,ios::beg);
	int abfang=In.tellg();
	//Speicher alloziieren
	buffer=new char [laenge];

	In.read(buffer,laenge);
	In.close();
	Out.open(cNach,ios::binary);

	if(!Out){
		cout<<"Datei konnte nicht geoeffnet werden";
		exit(-1);
	}

	Out.write(buffer,laenge);
	delete buffer;
	Out.close();
}
 
Oh, Mann! Da war ich aber auch blind! Ist ja klar, wenn man nur einen Parameter angibt, dann nimmt er die seekg-Version, die zu der angegebenen Position springt. Und der Wert von ios::end ist nun mal 2.
 
Hi,

achja nur mal so am Rande.
Bei deinem Algorithmus wirst du bei großen Dateien Schwierigkeiten bekommen, da
1. Der Speicher begrenzt ist
2. Die größe eines zusammenhängenden Blockes im Heap auch nochmal begrenzt ist.
3. Du nicht prüfst ob der Speicher auch allozierbar war (was wegen 1. und 2. durchaus schief gehen kann)
4. Ein signed int ist zu klein, für die maximale Größe einer Datei, da alles was größer als 2GB+1Byte ist einen overflow erzeugen würde.

Besserere Vorgehensweise:
Die Dateigröße in einem anderen Datentyp speichern:
Etwas besser wäre ein "unsigned int", was aber theoretisch auch nur für Dateigrößen von 4GB-1Byte geeignet ist und da wir wissen, dass NTFS mehr kann, bietet sich ein "unsigned __int64" an, der fasst immerhin theortisch 16 Exabyte-1Byte (1 Exabyte = 1024 Petabyte = 1048576 Terabyte = 1073741824 Gigabyte, mit faktor 1024) das sollte heutzutage reichen.

Der Speicher sollte nicht aufeinmal alloziert werden, da man einfach keine 4GB von Windows (32Bit) bekommen kann und schon garnicht zusammenhängen an einem Stück, stattdessen soll das in Blöcken von einer Festen größe passieren, die Größe der Blöcke ist abhängig von der Dateigröße ein gutes mittelmas wären da 64Kb (65536 Bytes).
Dadurch wird auch der Kopiervorgang bei größeren Dateien um einiges Schneller.
Diese Blockgrößen werden dann von der Quelldatei gelesen und in die Zieldatei geschrieben, dann kommt der nächste Block, bis die Datei zu Ende ist.
Am Ende wird dann natürlich der Rest (kleiner oder gleich des 64Kb-Blocks) gelesen.

Das Ganze klingt komplizierter als man denkt, aber man sollte das schon beachten.

Gruß Daniel
 
Zurück