CPlusPlus und Windows spezifische Dateibehandlung

Aus bknowledgebase
Zur Navigation springen Zur Suche springen


Einleitung[Bearbeiten]

Hier eine kurze Beschreibung wie man mittels der Programmiersprache C++Windows Bibliothek windows.h respektive fileapi.h mehr mit Dateien machen kann als mit den Standardboardmitteln von C++.


Anleitung[Bearbeiten]

Es steht eine recht große Bibliothek für windows Spezifische Funktionen zur Verfügung die mit der mit der windows.h includes werden kann. Hier will ich einige Beispiele ablegen was man mit der wiederum hierin enthalteten fileapi.h so alles anfangen kann. Dies ist also eine Teilmenge der gesamten Bibliothek die sich natürlich auf viel mehr als "nur" Filehandling beschränkt.

Notwendige Datentypen[Bearbeiten]

Einige Datentypen und/oder Objekttypen die es zu verstehen gilt sind:

HANDLE[Bearbeiten]

Einige der genutzten Funktionen erwarten ein Objekt vom Typ HANDLE oder geben ein solches zurück. Ein HANDLE kann vieles sein. Es kann im Prinzip fast alles in sich aufnehmen. Wichtig ist wie es weiterverwendet wird. Der Vorteil bei der Verwendung ist, dass z.B. HANDLE ein objekttyp ist. somit könnte ich z.B. auch objekte verschiedenen Typs, die aber von HANDLE erben zusammen in einem Container packen usf.

Die Idee ist quasi, dass vom eigentlichen Typ abstrahiert wird...

DWORD[Bearbeiten]

DWORD bedeutet Double-Word. Ein Word sind 16 Bit in Abgrenzung zum Byte (8Bit). Ein DWORD entspricht per Definition einem "Unsigned Long" in C++. Er heißt nur anders.

siehe:

 8 bit = BYTE
 16 bit = WORD
 32 bit = DWORD (Double-word)
 64 bit = QWORD (quad-word).


Ein Unsigned Long also auch DWORD kann 32 Bit also Zahlen zwischen 0 und circa 4,2 Milliarden fassen.


WIN32_FIND_DATA[Bearbeiten]

Hier wird immer wieder der Datentyp WIN32_FIND_DATA verwendet. Dieser ist in der "Winbase.h" headerdatei definiert und stellt ein "Struct" dar.

Hierüber kann man dann leicht auf verschiedene Eigenschaften der Files zugreifen:

typedef struct _WIN32_FIND_DATA { 
 DWORD dwFileAttributes; 
 FILETIME ftCreationTime; 
 FILETIME ftLastAccessTime; 
 FILETIME ftLastWriteTime; 
 DWORD nFileSizeHigh; 
 DWORD nFileSizeLow; 
 DWORD dwOID; 
 TCHAR cFileName[MAX_PATH]; 
} WIN32_FIND_DATA; 

Siehe: https://msdn.microsoft.com/en-us/library/ms915521.aspx

LPCWSTR[Bearbeiten]

Dies soll ein Pointer auf einen 16Bit unicode String sein. LPCWSTR bedeutet Long Pointer to Constant Wide String. Und der Rest verweist auf einen wchar_t typ. Also einen "Wide" oder "Large" Character der 16 Bit anstatt der 8 Bit bei einem "normalen" char benötigt.

Um einen "normalen" String direkt zuzuweisen kann man folgende Syntax nutzen:

LPCWSTR myWideStr = L'das ist mein stringtext';


Siehe: https://msdn.microsoft.com/en-us/library/cc230352.aspx

LARGE_INTEGER[Bearbeiten]

Dieser Datentyp ermöglicht wohl 32 Bit Systemen 64 Bit Integer zu verarbeiten. Er kann über ".lowpart" und ".highpart" angesprochen werden und teilt die Daten dann quasi in 2 * 32 Bit auf.

Datei finden und Datei öffnen[Bearbeiten]

Dazu ist zu sagen, dass es früher eine "OpenFile-Funktion" gab. Es soll aber laut Microsoft nun "CreateFile" verwendet werden.

Weiterhin sind hier 2 unabhängige Aktionen aufgezeigt. Eine Datei finden und dann eine Datei öffnen. Das zweite hängt nicht vom ersten ab.

#include <iostream>
#include <string>
#include <Windows.h>

using namespace std;

int main()
{
	WIN32_FIND_DATA filedata;
	size_t length_of_arg;
	HANDLE fileHandle = INVALID_HANDLE_VALUE;
	DWORD dwerror = 0; //unsigned Long
        LPCWSTR wPfad = L"c:\\test\\test.txt"; //mit dem L kann man den string in dieses format(w_str32) packen.
	LPCSTR pfad = "c:\\test\\test.txt";


	//1. Datei Finden und Handle zuordnen
	fileHandle = FindFirstFile(wPfad, &filedata);

	//Wenn keine Datei gefunden wurde, gib das zurück.
	if (INVALID_HANDLE_VALUE == fileHandle)
		{
			cout << "Datei nicht gefunden." << endl;
			return 0;
	}
	else {
		cout << "Datei gefunden. Wir können Zugreifen.";
	}



	//2. Datei zum lesen/schreiben öffnen
	
	fileHandle = CreateFileA(pfad, GENERIC_READ, FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

	CloseHandle(fileHandle); //eine geöffnete Datei sollte immer auch wieder geschlossen werden.
	return 0;
}

Siehe auch: https://docs.microsoft.com/de-de/windows/desktop/api/fileapi/nf-fileapi-createfilea

Ordner durchsuchen und Inhalte auflisten[Bearbeiten]

Diese Funktion berücksichtigt auch Dateigrößen > 4GB (also größer 32 Bit Systeme)

#include <iostream>
#include <string>
#include <Windows.h>
using namespace std;

int main()
{
	WIN32_FIND_DATA filedata;
	size_t length_of_arg;

	HANDLE fileHandle = INVALID_HANDLE_VALUE;
	LARGE_INTEGER filesize;
	ULONGLONG filesizelong;
	DWORD dwerror = 0; //unsigned Long
	wstring strPfad = L"c:\\test";
	LPCWSTR pfad = L"c:\\test"; //mit dem L kann man den string in dieses format(w_str32) packen.



	fileHandle = FindFirstFile(pfad, &filedata); //Datei/Ordner finden und Pointer auf "filedata" Struktur liefern

	if (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
	{
		cout << "das ist ein Ordner. Den durchsuche ich jetzt" << endl;
		//also Backslash und Stern anhängen
		strPfad.append(L"\\*");
		pfad = strPfad.c_str();
		
		fileHandle = FindFirstFile(pfad, &filedata); //Datei/Ordner finden und Pointer auf "filedata" Struktur liefern

		do
		{
			if (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			{
				cout << ".DIR" << endl;
			}
			else
			{
				wcout << "Filename: " << filedata.cFileName << endl;

				//Entweder selbst ausrechnen, dann braucht man die Variable "filesize" nicht -> 
				// filesizelong = static_cast <ULONGLONG>((filedata.nFileSizeHigh) * MAXDWORD) + 1 + filedata.nFileSizeLow;
				//oder

				filesize.HighPart = filedata.nFileSizeHigh;
				filesize.LowPart = filedata.nFileSizeLow;
				filesizelong = filesize.QuadPart;

				cout << endl << "Filesize: " << filesizelong <<  " bytes." << endl << endl << endl;

			}
		} while (FindNextFile(fileHandle, &filedata) != 0);

		dwerror = GetLastError();

		if (dwerror != ERROR_NO_MORE_FILES)
		{
			cout << "no more files" << endl;
		}

		FindClose(fileHandle);
		return dwerror;

	}
	else{
		cout << "das ist kein ordner;" << endl;
		system("pause");
		return 0;
	};

	return 0;


}

Dateiattribute auswerten[Bearbeiten]

Hier gibt es ein paar Worte zu sagen. Die Dateiatrribute von Windowsfiles werden als DWORD zurückgeliefert, der wiederum nur ein unsigned long integer ist. Es wird also pro Datei nur ein Wert zurückgeliefert. Wie kann das aber sein, wenn eine Datei verschiedene Attribute haben kann?

Die Dateiattribute werden über eine klassische logische Oder-Verknüpfung quasi "zusammengeführt". Jedem Bit wird per Definition eine andere Bedeutung in Bezug auf Dateiattribute zugewiesen und je nach dem welche Bits gesetzt sind können so alle Attribute ausgelesen werden. Dabei schließen sich bestimmte Attribute logisch aus.

Mehr dazu in einem eigenen Artikel hier: Attribute Bitweise mit Logischem Oder verknüpfen

Beispielcode:

#include "pch.h"
#include <iostream>
#include <windows.h>

using namespace std;

int main()
{
	WIN32_FIND_DATA FileData; //repräsentation der Filedaten
	HANDLE myhandle = FindFirstFile(L"c:\\Test", &FileData);  //Handle zum file

	if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) //bedeutet also quasi.. "ist dieses attribut enthalten?" !!!
	{
		cout << endl << "ein verzeichnis";
	}
	if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE)
	{
		cout << endl << "Archiviert";
	}
	if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == FILE_ATTRIBUTE_HIDDEN)
	{
		cout << endl << "versteckt";
	}

	cout << endl << "ende";
	//Im Prinzip schaut man quasi einfach nur ob das entsprechende Bit gesetzt ist. Mit & eliminiert man alle anderen Bits wenn man explizit mit dem gesuchten wert "verundet.".
}



	//wenn dwFileAttributes z.B. 48
	//also													00110000
	// dann &(UND)												&
	// FILE_ATTR...DIRECTORY (16)							00010000
	// dann ist das ergebnis ungleich 0 hier nämlich z.B: 16

H@ppy H@cking