C Bestimmte Daten in einer Datei finden

DeusExMachina

Lieutenant
Registriert
Jan. 2008
Beiträge
618
Moin Moin,

für mein Studium betrachten wir grade C und wir haben die Aufgabe bekommen in einer Dicom Datei die Bilddaten zu extrahieren.
Für uns interessant im Praktikum sind die Bilddaten, die in diesen Dateien abgespeichert sind. Zunächst kommt der so genannte Header der Datei, der eine
Menge an anderen Informationen enthält (um die wir uns NICHT kümmern) und auch eine variable Größe besitzt. Danach kommt an einer bestimmten Stelle die Information, dass nun die Bilddaten kommen. Diese Information findet sich dadurch, dass man die Daten (als short!) einliest und wenn die hexadezimale Zahlenkombination (0x7FE0,0x0010) gefunden wird, mussen noch vier char-Daten übersprungen werden, dann kommt als long die Anzahl der Bildpunkte und dann beginnen die Bilddaten (nachzulesen im DICOM-Standard). Die Größe der Bilder ist (bei der Computertomographie) 512 x 512 und die Bilddaten sind als short- Variablen gespeichert.

Die Daten werden dann auf verschiedenste Art und Weiße manipuliert aber das ist alles schon fertig programmiert und stellt kein Problem da ich habe massivst Probleme mit zwei Punkten:
1.
Ich bekomme es nicht hin die Datei nach der hexadezimalen Zahlenkombination (0x7FE0,0x0010) zu durchsuchen.
(und wie springe ich dann noch einen long weiter wenn ich vorher mit shorts gearbeitet hab? fseek() evtl.?)

Versucht hatte ich es in der Richtung:
Code:
int main()
{
	FILE *fpi,*fpo;
	short helpvar;
	short fpi = fopen("file_out","r");
	if(fpi == NULL)
		printf("Cyptic ERROR 404\n");
	else
	{
		while((helpvar=fscanf(fpi))!=EOF)
		{
		if (helpvar == 0x7FE0)
		{
			if ((helpvar = fscanf(fpi)) == 0x0010)
		}

		}
		fcloseall();
	}
	return 0;
}

das aber nicht besonders elegant noch funktioniert es wie ich das will

2. die daten dann als short in die matrix einzulesen

Wenn mir jemand nen passenden Denkanstoß geben kann wäre ich sehr verbunden, danke im Voraus.
 
Zuletzt bearbeitet:
Dem compiler ist es egal ob du den Wert in Hex oder in Dezimal( also var = 0xA entspricht var = 10), dementsprechend auch der vergleich bei if

Du kannst entweder die Datei blockweise einlesen oder im ganzen. Das richtet sich danach wie groß die Datei ist. Mehr als 500 MB würde ich nicht unbedingt komplett auf einmal in den Speicher laden.

Für das Blockweise einlesen benötigst du einen Buffer den du mit den daten aus der Datei füllst und vergleichst:

Code:
for schleife ..
if (buffer[i] == 0x7FE0 && buffer[i+1] == 0x0010) ...

für die größe eines Typen kannst du sizeof verwenden sizeof(long) sollte 4 entsprechen. Dies kannst du dann über fseek(fp,sizeof(long),SEEK_CUR) steuern. Das SEEK_CUR gibt an er soll um den wert der Parameter 2 hat verschoben werden, dies kann auch negativ sein. Allerdings hast du das ganze hierbei schon im Zwischenspeicher, von welchem du die bildgröße in einen Speicherbereich für das Bild kopieren kannst. Alternativ kannst du auch per fseek um die größe des Buffers zurück und dann wieder um i nach vorne um die Position zu finden wo die Information steht das das Bild nun kommt. Dann überspringst du diese Informationen noch bis zum Anfang der Bilddaten

Falls du die ganze Datei komplett in den Speicher gelesen hast musst du den Pointer entsprechend um die Größe des long verschieben.

beim Auslesen ist nun noch die frage was das Bild für eine Farbtiefe hat um einen entsprechend großen Speicherbereich zum hineinladen bereit zu stellen. Ich nehm nun mal an es ist 1 short pro farbe (ohne alpha), also 3*2Bytes = 6. Dann benötigst du einen Speicherbereich von 512x512x6 = 1572864 Byte, welchen du dynamisch per malloc/calloc anfordern solltest.

Ich hoff das war nun nicht zu kryptisch aus dem Kopf geschrieben und es hilft
 
Helfen tut es schon das meiste kenne ich ja deswegen passt das schon.

2 Fragen hab ich aber noch:

Wenn dich die Datei in Blöcken einlese (hier bietet sich ja short als Blockgröße an) und ich den fseek() auf die Position setze wo ich grade bin nimmt er den aktuellen Filepointer oder? aber der steht ja nach dem einlesen von i+1 schon auf dem ersten der 4 chars oder irre ich da grade?


Und zum Blockweise einlesen selber:
Die ganze Datei erstmal als einen langen Array speichern (via malloc/calloc damits nicht zu groß wird) und dann den Array durch suchen.
So hab ich des jetzt zu mindestens verstanden.

Wenn ich das aber so machen kann ich ja auch ne Funktion schreiben dir mir die Sprunggröße für den fseek() ausrechnet um direkt zu den Bilddaten springen zu können oder verrenne ich mich da grade?
 
Also nochmal

Du kannst die Datei komplett einlesen (sollte aber nicht sehr groß sein):

Code:
fp = fopen("datei.dat","rb");
fseek(fp,0,SEEK_END);
filesize= ftell(fp);
bigbuffer = malloc(filesize);
fseek(fp,0,SEEK_SET);
fread(bigbuffer,1,filesize,fp);
fclose(fp);

Oder du kannst es in blöcken einlesen, bei großen Dateien zu empfehlen

Code:
short buffer[4096];
fp = fopen("datei.dat","rb");
while(fread(buffer,1,4096,fp) != EOF)
{
for(i = 0; i < 4096; i++)
{
if (buffer[i] == 0x7FE0 && buffer[i+1] == 0x0010)
{
//hier wurde der eintrag gefunden
//und nun entweder weiter einlesen über blöcke
//oder
//fseek(fp,-sizeof(buffer) - i,SEEK_CUR);
//fseek(fp,2 * sizeof(short) + 4*sizeof(char), SEEK_CUR);
//fread(bildpunkte,1,sizeof(long),fp);
//Hier dann das Bild einlesen
}
}
}
fclose(fp);

der Code ist aus dem Kopf und nicht geprüft auf funktionalität, aber sollte veranschaulichen wie es funktioniert
 
Hier der Denkanstoß :D

Short ist 2 Byte groß

Damit machen hier fscanf und fread nicht das was es soll, nämlich 2 Bytes lesen. Bei fscanf kannst du ein Format angeben, bei fread die Anzahl Bytes
 
Moinsen,

mit dem folgendem Code hat das ganze dann Funktioniert. Ich danke noch mal für die Hilfsbereitschaft.

Code:
int get_matrix(char file_out[50], short original[512][512])
{
	short finder = 0;
	long offset = 0;
	FILE *read;
	read = fopen(file_out,"rb");
	if(read == NULL)
	{
		printf("Fehler beim Oeffnen zum Auslesen der Bildmatrix!\n");
		return EXIT_FAILURE;
	}
	else
	{
		
		short a=0,b=0;
		
		do	
		{
			a=b;
			fread(&b, sizeof(short),1,read);
		}
		while(a!=0x7FE0 || b!=0x0010);
	}

	offset = ((3 * sizeof(short)) + sizeof(long));
	fseek(read,offset,1);
	
             //ab hier dann die Einlesefunktion für die Matrix aber die brauche ich ja nicht posten
             // hat ja nix mit der Frage zu tun

	return 0;
}
 
Zurück
Oben