Operacje na systemie plików w systemach Windows i Linux w C++
Tym razem notka o tym, w jaki sposób można wykonywać różne operacje w systemie plików w wymienionych w temacie systemach. Oczywiście każdy programista C/C++ zna funkcje wykonujące podstawowe operacje na plikach, takie jak:
- odczyt, modyfikacja, zapis (funkcja fopen i poboczne oraz klasy fstream)
- zmiana nazwy pliku lub katalogu (funkcja rename())
- usunięcie pliku (funkcja remove())
Nieco więcej problemów sprawiają pozostałe operacje, takie jak np. pobranie pełnej ścieżki do pliku czy przeglądanie listy plików w katalogu, ponieważ w bibliotece standardowej nie ma do tego celu odpowiednich funkcji, zatem należy ich szukać w API systemu. Niestety co API to różne funkcje, ale zdarzają się i takie, które istnieją w obu systemach.
Na początek pobieranie pełnej ścieżki do bieżącego katalogu, czyli funkcja getcwd. Jej prototyp w systemie Windows jest następujący:
#include <direct.h> char* _getcwd(char* _DstBuf, int _SizeInBytes); |
a w systemie Linux:
#include <unistd.h> char* getcwd(char* _DstBuf, int _SizeInBytes); |
Jak widać prototyp obu funkcji jest identyczny, więc nic nie stoi na przeszkodzie utworzenia sobie odpowiedniego aliasu nazwy za pomocą typedef.
Trochę lepiej jest z funkcją stat() i jej strukturą o tej samej nazwie (thx C…, typedef needed), która istnieje w obu systemach. Funkcja ta służy do pobierania pełnych informacji o pliku, czyli np. daty modyfikacji, typu czy rozmiaru. Jej przykładowe użycie wygląda następująco:
1 2 3 4 5 6 7 8 9 10 11 | #include <sys/stat.h> typedef struct stat FileStatus; // thx C /*...*/ FileStatus fileStatus; if(stat(szFullPath.c_str(), &fileStatus) < 0) { return; } unsigned int uFileSize = fileStatus.st_size; // Pobranie rozmiaru pliku |
Nieco gorzej jest z wyciąganiem listy plików w katalogu, ponieważ w tym przypadku oba systemy mają do tego różne funkcje. W przypadku systemu Windows wygląda to tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <windows.h> /*...*/ WIN32_FIND_DATA info; HANDLE hFind = FindFirstFile(szDirPath, &info); if(INVALID_HANDLE_VALUE == hFind) { printf("Error"); return; } do { if((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { printf("Directory: %s\n", info.cFileName); } else { printf("File: %s\n", info.cFileName); } } while(FindNextFile(hFind, &info) != 0); FindClose(hFind); |
A w systemie Linux tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <dirent.h> #include <string.h> // c-string operations typedef struct dirent DirEntry; typedef struct stat DirEntryStat; // thx C again DIR* pDir; pDir = opendir(szDirPath); if(pDir == null) { printf("Error"); return; } DirEntry* pDirent; DirEntryStat dirEntryStat; while((pDirent = readdir(pDir)) != null) { char buffer[255]; strcpy(buffer, szDirPath); strcat(buffer, pDirent->d_name); // Do ponizszej funkcji potrzebna jest sciezka z biezacego katalogu if(stat((buffer, &dirEntryStat) < 0) { printf("Error"); continue; // file corrupted... NEXT! } if((dirEntryStat.st_mode & S_IFDIR) != 0) // Katalog { printf("Directory: %s\n", pDirent->d_name); } else if((dirEntryStat.st_mode & S_IFREG) != 0) // Plik { printf("File: %s\n", info.pDirent->d_name); } } closedir(pDir); |
Można zauważyć, że funkcja z WinAPI jest nieco przyjaźniejsza, ponieważ operuje na uchwycie do żądanego katalogu, w przeciwieństwie do funkcji Linuksowej, która po prostu zwraca nazwę tego co siedzi w katalogu i nic więcej.