Narzędzia użytkownika

Narzędzia witryny


filesystem

To jest stara wersja strony!


Biblioteka boost::filesystem

wersja robocza

Wstęp

Biblioteka boost::filesystem wprowadza przenośne udogodnienia w zarządzaniu ścieżkami dostępu do katalogów i plików.

Cechy

  • Programy używające tej biblioteki charakteryzuje pełna przenośność. Składnia, jak i zachowanie kodu programu są całkowicie niezależne od systemu operacyjnego.
  • Użycie biblioteki uważa się za bezpieczne, ponieważ ewentualne błędy nie mogą zostać zignorowane, gdyż większość funkcji zwraca wyjątki przy napotkaniu błędów.

Pliki nagłówkowe

  • Nagłówek <boost/filesystem.hpp> wprowadza klasę basic_path i jej pochodne: path i wpath. Poza tym udostępnia wiele pomocnych operacji na plikach i katalogach. Klasa basic_directory_iterator umożliwia niezwykle użytczne iteracje po zawartości katalogów.
  • Nagłowek <boost/filesystem/fstream.hpp> wprowadza takie same elementy co nagłówek fstream standardowej biblioteki C++, lecz same pliki są identyfikowane przez obiekty basic_path, a nie char *s.

Podstawowe klasy

basic_path

Klasa path posiada konstruktory konwersji z const char* i std::string&, więc pomimo tego, że biblioteka Filesystem używa parametru formalnego path& to i tak dozwolone jest podawanie jako parametrów napisów w stylu C:

remove_all("plik");
create_directory("teczka");
if(!exists("katalog/obraz"))
	std::cout << "Błędna ścieżka\n";

Ścieżki mogą zawierać odwołanie do bieżącego katalogu używając notacji „.”, a także do nadkatalogu, używając zapisu „..”.

basic_directory_iterator

Klasa basic_directory_iterator jest ważnym elementem biblioteki Filesystem. Wprowadza iterator wejściowy po zawartości katalogu z wartością typu basic_path. Jako przykład użycia tego iteratora przedstawiona zostanie funkcja, która rekursywnie wyszukuje plik o podanej nazwie w podanym katalogu i jego podkatalogach. Zwraca wartość bool i ewentualnie ścieżkę do odnalezionego pliku:

namespace bf = boost::filesystem;
 
bool find_file( const bf::path& dir_path,
				const std::string& file_name,
				path& path_found ) {
	if(!exists(dir_path) || !is_directory(dir_path))
		return false;
	directory_iterator iter(dir_path), end_iter;
	for(; iter != end_iterl ++iter) {
		if(bf::is_directory(*iter)) {
			if(find_file(*iter, file_name, path_found))
				return true;
		}
		else if(iter->leaf() == file_name) {
			path_found = *iter;
			return true;
		}
	}
	return false;
}

Funkcja najpierw sprawdza czy podana ścieżka w path_dir istnieje i jest katalogiem. Później tworzy obiekt directory_iterator podając ściężkę do konstruktora. Pętla iteruje po wszystkich elementach katalogu i dla każdego napotkanego podkatalogu wywołuje rekursywnie funkcję szukającą. Każdy rozpoznany plik jest porównywany co do nazwy z paramatrem file_name i jeśli znaleziony zostanie plik o podanej nazwie to do path_found kopiowana jest scieżka do tego pliku i zwracana jest wartość 'true'. Jeśli nic nie zostanie znalezione to zwrcana jest wartość 'false'.

Gramatyka?

Pomocne funkcje

void copy_file(const Path1& from_fp, const Path2& to_fp);

Funkcja kopiuje zawartość pliku from_fp do pliku to_fp.

void rename(const Path1& from_p, const Path2& to_p);

Funkcja zmienia nazwę pliku from_fp na nową to_p/

bool remove(const Path& p);

Funkcja usuwa plik p, jeśli plik taki istnieje. Zwraca wartość wyrażenia exists(p).

bool create_directory(const Path& dp);

Funkcja tworzy katalog dp. Zwraca wartość true, jeśli katalog został utworzony, w przeciwnym razie zwraca wartość false.

uintmax_t file_size(const Path& p);

Funkcja zwraca rozmiar pliku p w bajtach.

std::time_t last_write_time(const Path& p);

Funkcja zwraca czas ostatniej modyfikacji elementu p.

void last_write_time(const Path& p, const std::time_t new_time);

Funkcja ustawia czas ostatniej modyfikacji pliku p na new_time.

template <class Path> typename Path::string_type extension(const Path & p);

Funkcja zwracająca rozszerzenie pliku. Jeśli p.leaf() zawiera kropkę, to funkcja zwraca podciąg z p.leaf() zaczynający się od ostatniej kropki aż do ostatniego znaku nazwy. W przeciwnym razie wypadku zwraca pusty łańcuch.

template <class Path> typename Path::string_type basename(const Path & p);

Funkcja zwracająca nazwę pliku bez rozszerzenia. Jeśli p.leaf() zawiera kropkę, to funkcja zwraca podciąg z p.leaf() zaczynający się od początku nazwy do ostatniej kropki (kropka nie jest zawarta). W przeciwnym wypadku zwraca p.leaf().

template <class Path> Path replace_extension(const Path & p, const typename Path::string_type & new_extension);

Funkcja zmienia rozszerzenie pliku p na nowe new_extension.

Przykład użycia

Prosty program wypisujący zawartość katalogu:

namespace bf = boost::filesystem;
 
void listing(const bf::path& p) {
	unsigned long dir_count = 0;
	unsigned long file_count = 0;
	unsigned long other_count = 0;
	unsigned long err_count = 0;
 
	if(!bf::exists(p)) {
		std::cout << "Nieprawidlowa sciezka: " << p.native_file_string() << std::endl;
		return;
	}
 
	if(bf::is_directory(p)) {
		std::cout << "W katalogu: " << p.native_file_string() << "\n\n";
		bf::directory_iterator iter(p), end_iter;
		for(; iter != end_iter; ++iter) {
			try {
				if(bf::is_directory(*iter)) {
					++dir_count;
					std::cout << iter->leaf() << " [katalog]\n";
				}
				else if(fs::is_regular(iter->status())) {
					++file_count;
					std::cout << iter->leaf() << " ("  << bf::file_size(*iter) <<" B)\n";
				}
				else {
					+other_count;
					std::cout << iter->leaf() << " [inny]\n";
				}
			} catch(const std::exception& ex) {
				++err_count;
				std::cout << iter->leaf() << ": " << ex.what() << std::endl;
			}	
		}
		std::cout	<< std::endl << file_count << " plikow\n"
					<< dir_count << " katalogow\n"
					<< other << " innych\n"
					<< err_count << " błedów\n";
	}
	else {	// musi byc plikiem
		std::cout << "Plik: " << p.native_file_string() << std::endl;
	}
}

Uwagi

Przy całym dobrodziejstwie niesionym przez bibliotekę Filesystem trzeba także pamiętać o pewnych pułapkach czyhających na programistę. Otóż podczas wykonywania funkcji może wystąpić wyścig, a wtedy wartość zwracana przez funkcję może ulec zmianie do czasu powrotu do funkcji wywołującej.

Pliki lub katalogi są często współdzielone i przez to ich stan może zostać zmieniony prze inny wątek, proces, a nawet inny komputer posiadający sieciowy dostęp do systemu plików. Oto kilka przykładów pokazujących istotę problemu:

assert(exists("foo") == exists("foo"));

W tym przypadku może się zdarzyć, iż nieistniejący plik bądź katalog zostanie utworzony lub istniejący zostanie usunięty pomiędzy pierwszy a drugim wywołaniem exists(). Taka sytuacja może nastąpić, jeśli podczas wykonania przykładowego kodu inny wątek, proces lub komputer także operuje w tym samym folderze.

remove_all("foo");
assert(!exists("foo"));

Taka próba nie powiedzie się, jeśli między wywołaniem remove_all() a wywołaniem exists() inny wątek, proces lub komputer stworzy plik bądź katalog o nazwie „foo”.

assert(is_directory("foo") == is_directory("foo"));

Zawiedzie, w przypadku gdy inny wątek, proces badź też komputer pomiędzy dwoma wywołaniami is_directory() usunie istniejący plik „foo” i stworzy katalog o nazwie „foo”.

filesystem.1208378681.txt.gz · ostatnio zmienione: 2008/04/16 22:44 przez michal.wasiak