SUCKUP.de

C-Programm – Dateien kopieren unter Linux

This blog post has been published on 2011-01-17 and may be out of date.

In dem Buch “Linux-Programmierung” habe ich einige interessante Beispiele zum kopieren von Dateien unter Linux gefunden.

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

int main() {
	char c;
	int in, out;

	// open - mit dem Systemaufruf open kann ein neuer Dateideskriptor erstellt werden
	// ---------------------
	// Modus -> Beschreibung
	// ---------------------
	// O_RDONLY -> nur zum lesen oeffnen
	// O_WONLY	-> nur zum schreiben oeffnen
	// O_RDWR	-> zum lesen und schreiben oeffnen
	// ---------------------
	// optionaler Modus -> Beschreibung
	// ---------------------
	// O_APPEND	-> am Ende der Datei schreiben
	// O_TRUNC	-> Inhalt der vorhandenen Datei wird geloescht
	// O_CREAT	-> erstellt die Datei mit Berechtigungen 
	// O_EXCL	-> stellt sicher, dass nicht zwei Programme
	//				die selbe Datei, zur gleichen Zeit erstellen 
	// ---------------------
	// Berechtigung -> Beschreibung
	// ---------------------
	// S_IRUSR 	-> Lesen, Eigentuemer (owner)
	// S_IWUSR	-> Schreiben, Eigentuemer (owner)
	// S_IXUSR	-> Ausfuehren, Eigentuemer (owner)
	// S_IRGRP	-> Lesen, Gruppe (group)
	// S_IWGRP	-> Schreiben, Gruppe (group)
	// S_IXGRP	-> Ausfuehren, Gruppe (group)
	// S_IROTH	-> Lesen, Andere (others)
	// S_IWOTH	-> Schreiben, Andere (others)
	// S_IXOTH	-> Ausfuehren, Andere (others)
	//
	// weitere Infos unter: man 2 open 
	//
	// 1 MB Datei erstellen -> dd if=/dev/zero of=file.in bs=1024 count=10240
	// 
	// Datei "file.in" zum lesen oeffnen
	in = open("file.in", O_RDONLY);
	// Datei "file.out" erstellen (Eigentuemer -> Lesen + Schreiben) 
	out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
	// Zeichen fuer Zeichen einlesen ...
	while(read(in,&c,1) == 1) {
		// ... und jedes Zeichen in die neue Datei schreiben
		write(out,&c,1);
	}
	exit(0);
}

Wir gehen in diesem Beispiel davon aus, dass die Datei “file.in” (10 MB) bereits vorhanden ist.

Test:

dd if=/dev/zero of=file.in bs=1024 count=10240
time ./copy_system

Ausgabe:

./copy_system  7,54s user 88,56s system 99% cpu 1:36,23 total

Wie wir sehen, dauerte der Kopiervorgang insgesamt ~ 1 1/2 Minuten, da wir die Datei Zeichen für Zeichen kopiert haben, im nächsten Beispiel werden jeweills 1024 Byte eingelesen und in die neue Datei geschrieben.

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

int main() {
	char block[1024];
	int in, out, nread;

	// open - mit dem Systemaufruf open kann ein neuer Dateideskriptor erstellt werden
	// ---------------------
	// Modus -> Beschreibung
	// ---------------------
	// O_RDONLY -> nur zum lesen oeffnen
	// O_WONLY	-> nur zum schreiben oeffnen
	// O_RDWR	-> zum lesen und schreiben oeffnen
	// ---------------------
	// optionaler Modus -> Beschreibung
	// ---------------------
	// O_APPEND	-> am Ende der Datei schreiben
	// O_TRUNC	-> Inhalt der vorhandenen Datei wird geloescht
	// O_CREAT	-> erstellt die Datei mit Berechtigungen 
	// O_EXCL	-> stellt sicher, dass nicht zwei Programme
	//				die selbe Datei, zur gleichen Zeit erstellen 
	// ---------------------
	// Berechtigung -> Beschreibung
	// ---------------------
	// S_IRUSR 	-> Lesen, Eigentuemer (owner)
	// S_IWUSR	-> Schreiben, Eigentuemer (owner)
	// S_IXUSR	-> Ausfuehren, Eigentuemer (owner)
	// S_IRGRP	-> Lesen, Gruppe (group)
	// S_IWGRP	-> Schreiben, Gruppe (group)
	// S_IXGRP	-> Ausfuehren, Gruppe (group)
	// S_IROTH	-> Lesen, Andere (others)
	// S_IWOTH	-> Schreiben, Andere (others)
	// S_IXOTH	-> Ausfuehren, Andere (others)
	//
	// weitere Infos unter: man 2 open 
	//
	// 1 MB Datei erstellen -> dd if=/dev/zero of=file.in bs=1024 count=10240
	// 
	// Datei "file.in" zum lesen oeffnen
	in = open("file.in", O_RDONLY);
	// Datei "file.out" erstellen (Eigentuemer -> Lesen + Schreiben) 
	out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
	// 1024 Byte werden eingelesen ...
	while((nread = read(in,block,sizeof(block))) > 0) {
		// ... und in die neue Datei geschrieben
		write(out,block,nread);
	}
	exit(0);
}

Test:

rm file.out
time ./copy_block 

Ausgabe:

./copy_block  0,01s user 0,15s system 98% cpu 0,158 total

Hier dauerte der gleiche Vorgang nur noch ~ 0,16 Sekunden. Daher nutzt man zum kopieren von ganzen Festplatten auch gerne “dd”! :-) Zum Schluss noch ein Beispiel, wo die Bibliothek (stdio.h) von C genutzt wurden.

#include <stdio.h>
#include <stdlib.h>

int main() {
	char c;
	FILE *in, *out;

	// fopen - oeffnet eine Datei 
	// ---------------------
	// Modus -> Beschreibung
	// ---------------------
	// r	-> nur zum lesen oeffnen
	// w	-> nur zum schreiben oeffnen
	// a	-> am Ende der Datei anhaengen
	// r+	-> zum Aktualisieren oeffnen (schreiben + lesen)
	// w+	-> zum Aktualisieren oeffnen, auf Null-Laenge abschneiden
	// a+	-> zum Aktualisieren oeffnen, am Ende der Datei anhaengen
	//
	// weitere Infos unter: man fopen 
	//
	// fgetc - liefert das naechste Byte als Zeichen aus einem Datei-Stream zurueck,
	// 			die Funktion liefert EOF (End of File) beim Ende der Datei bzw.
	//			bei einem Fehler zurück
	//
	// weitere Infos unter: man fgetc
	//
	// fputc - schreibt ein Zeichen in einen Ausgabe-Datei-Stream
	//
	// weitere Infos unter: man fputc
	//
	// 1 MB Datei erstellen -> dd if=/dev/zero of=file.in bs=1024 count=10240
	// 
	// Datei "file.in" zum lesen oeffnen
	in = fopen("file.in", "r");
	// Datei "file.out" erstellen (Eigentuemer -> Lesen + Schreiben) 
	out = fopen("file.out", "w");
	// Zeichen fuer Zeichen einlesen (+ interner Puffer in der Struktur FILE) ...
	while((c = fgetc(in)) != EOF) {
		// ... und jedes Zeichen in die neue Datei schreiben
		fputc(c,out);
	}
	exit(0);
}

Test:

rm file.out
time ./copy_system_2

Ausgabe:

./copy_system_2  1,10s user 0,09s system 99% cpu 1,196 total

Hier brauchen wir für 10 MB zirka 1,2 Sekunden, was um einiges schneller ist als das erste Beispiel, wo die Zeichen einzeln kopiert wurden.