25 Nisan 2018 Çarşamba

filesystem

Giriş
Şu satırı dahil ederiz.
#include <boost/filesystem.hpp>
Linklemek için şöyle yaparız.
g++ .... -lboost_filesystem 
Eğer depricate edilmiş metodları istemezsek şöyle yaparız.
#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <boost/filesystem.hpp>
Kullanılan isim alanı uzunsa şöyle yapabiliriz.
namespace fs = boost::filesystem;
Ya da tüm sınıfları dahil etmek için şöyle yaparız.
using namespace boost::filesystem;
C++17 ile filesystem C++ standardına girecek.

Dosya ve Dizin Metodları - Operational Functions

Metodlar arasında dosya sahipliği ile ilgili - chown gibi - metodlar yoktur.

absolute metodu
Şöyle yaparız. "\\T4 2.0\\Data" gibi çözümlenen dizini "C:\\T4 2.0\\Data" haline getirir. Yani path'i kök dizinden başlayacak hale getirir.
boost::filesystem::path from = ...; 
from = boost::filesystem::absolute (from);
absolute metodu sonucunda path içinde halen "." veya ".." gibi karakterler olabilir. Bunlardan kurtulmak için canonical metodu kullanılır.

canonical metodu
Açıklaması şöyle.
canonical converts path p to a canonical absolute path, i.e. an absolute path that has no dot, dot-dot elements or symbolic links.
Since canonical must also dereference the symbolic links contained in the path it can only accept paths of existing files or directories.
Path içindeki "." veya ".." gibi karakterleri siler.
Örnek 1
Şöyle yaparız.
fs::path parentPath = fs::current_path() / "..";
std::cout << parentPath << " → " << fs::canonical(parentPath) << std::endl;
Örnek 2
Current Path şu olsun
"D:\test\build"
Bir üst dizine çıktığım ve .. karakterini sildiğim için çıktı olarak şunu alırım. Windows'ta dizin ayracı da ters çevrilir.
"D:/test"
Linux'ta ise şu çıktıyı alırım.
"/home/myuser/build/.."  "/home/myuser"
Örnek 3
Eğer yolumuz bir dosya veya dizine çıkmıyorsa exception fırlatır. Örnek std::experimental::filesystem ile olsa da boost için de aynı şey geçerli. Şöyle yaparız.
#include <string>
#include <iostream>
#include <experimental/filesystem>

namespace fs = std::experimental::filesystem;

int main()
{
  fs::path p("/usr/include/c++/../sys/*");
  p = fs::canonical(p);
}
Fırlatılan exception şu olabilir.
boost::filesystem::current_path: No such file or directory
copy metodu - path + path
Bu metod çok iyi çalışmıyor. Exception fırlatması gerekirken fırlatmayabiliyor.
try
{
  boost::filesystem::copy("./test.h", "./copied.cpp"); // works
  boost::filesystem::copy("./test.h", "./copied.cpp"); // should throw
}
catch (...)
{
  std::cout << "Caught" << std::endl; // never reached...
}
Bu metod yerine error_code alan türevi veya copy_file() kullanılabilir.

copy_directory metodu - path + path
Şöyle yaparız.
// test throwing upon copy_directory because source folder does not exist:
try
{
  boost::filesystem::copy_directory("s", "b");
}
catch (...)
{
  std::cout << "Caught" << std::endl; // works OK
}
create_directory metodu - path
Açıklaması şöyle. Mevcut dizini bir daha yaratmak hata değil.
Creation failure because p resolves to an existing directory shall not be treated as an error.
Şöyle yaparız.
bfs::path p("...");
bfs::create_directory (p);
Aynı şeyi Windows'ta yapmak için mkdir (deprecated) veya _mkdir kullanılabilir.

create_directory metodu - path + error_code
Şöyle yaparız.
boost::system::error_code ec;
if (!bfs::create_directory(p, ec)) {
  std::cerr << "couldn't create directory\n";
  std::cerr << ec.message() << "\n";
}
create_directories metodu
Açıklaması şöyle. Altta create_directory() metodunu çağırır.
Effect: Establishes the postcondition by calling create_directory() for any element of p that does not exist.
Postcondition: is_directory(p)
Şöyle yaparız.
try {
  bfs::path dirPath("I:\\Documents\\Directory\\SubDir\\SubSubDir\\MyFile.txt");
  bfs::create_directories(dirPath.parent_path());
}
catch(const bfs::filesystem_error& err) {
  std::cerr << err.what() << std::endl;
}
current_path metodu - getter
Açıklaması şöyle
This may or may not be the location of the executable because it depends on the directory from which the program was run and whether or not the working directory has been changed by the program
Current working directory yolunu döner. Şöyle yaparız.
bfs::path cwd (boost::filesystem::current_path());
Bu dizini yazdırmak için şöyle yaparız.
std::cout << "Current path is " << fs::current_path() << '\n'
Çıktı olarak şunu alırım
"D:\test\build"
Aynı şeyi şöyle de yapabilirim.
std::string cwd = getcwd (NULL, 0);
boost::filesystem::path p (cwd);
current-path - setter
Şöyle yaparız.
try
{
  boost::filesystem::current_path("/public/tst");
  std::cout << "Worked" << std::endl; // works OK
}
catch (...)
{
  ...
}
exists metodu - path
Açıklaması şöyle. Eğer dosyayı okuma izni yoksa exception fırlatabilir.
bool exists(file_status s) noexcept
Returns: status_known(s) && s.type() != file_not_found
bool status_known(file_status s) noexcept
Returns: s.type() != status_error
Şöyle yaparız.
const bfs::path filePath ("/tmp/hello.log" );
if (bfs::exists (filePath)) {...}
exists metodu - path + error_code
İmzası şöyle. Exception fırlatmaz.
bool exists(const path& p, system::error_code& ec) noexcept;
Şöyle yaparız.
const bfs::path filePath = ...;
boost::system::error_code ec;
if(bfs::exists(filePath, ec)) {
  bfs::remove(filePath);
}
file_size metodu - path
Dosyanın büyüklüğünü bulmak için kullanılır. Parametre olarak path alır. Ancak path sınıfının bir sürü explicit olmayan constructor metodu olduğu için farklı parametre tipleriyle rahatça kullanabiliriz.
char *
Şöyle yaparız.
char* str = ...;
file_size (str);
std::string
Şöyle yaparız.
string filename("c:\\test.zip");
long long fileSize = bfs::file_size(filename);
path
Şöyle yaparız.
recursive_directory_iterator it = ...;
size_t size = file_size (*it);
is_directory metodu
Örnek
const path dirPath=...
if ( bfs::is_directory (dirPath) ) {...}
is_regular_file metodu - Depricated
Metodun içi şöyle
inline bool is_regular_file(file_status f) BOOST_NOEXCEPT {
  return f.type() == regular_file;
}
is_regular metodu
Metodun içi şöyle. is_regular_file metodu ile aynı'dır. Sadece isim değiştirmiştir.
inline bool is_regular(file_status f) BOOST_NOEXCEPT {
  return f.type() == regular_file;
}
is_symlink metodu
Şöyle yaparız.
const path p = ...;if (bfs::is_symlink (p) ) {...}
last_write_time metodu - getter
Örnek
Şöyle yaparız.
path filePath("path/to/the/file.ext");

std::cout << last_write_time(filePath) << "\n"; // Getting write/modified time
Örnek
Bu metod UTC döner. Yerel zaman çevirmek için şöyle yaparız.
#include <boost/filesystem.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/c_local_time_adjustor.hpp>

void PrintTime(boost::filesystem::path _file) {
  using boost::posix_time::ptime;
  using adj = boost::date_time::c_local_adjustor<ptime>;

  time_t const sys_time = last_write_time(_file);
  ptime const utc       = boost::posix_time::from_time_t(sys_time);
  ptime const local     = adj::utc_to_local(utc);

  std::cout << "utc: " << utc << "\n";
  std::cout << "local: " << local << "\n";
  {
    long h{ local.time_of_day().hours() };
    long m{ local.time_of_day().minutes() };
    long s{ local.time_of_day().seconds() };

    //...print h, m, s.
    std::cout << h << ":" << m << ":" << s << '\n';
  }
}
Çıktı olarak şunu alırız.
utc: 2018-Feb-27 15:19:45
local: 2018-Feb-27 16:19:45
16:19:45
Örnek
Eğer creation time gerekiyorsa boost bunu sağlamaz. Windows'ta şöyle yaparız.
WIN32_FIND_DATA GetFileInfo(char const *path) { 
  WIN32_FIND_DATA data;

  HANDLE h;

  h = FindFirstFile(path, &data);
  FindClose(h);
  return data;
}
last_write_time metodu - setter
Birinci parametre path tipindendir. İkinci parametre time_t tipindendir.

native metodu
Açıklaması şöyle
A name_check function returns true if its argument is valid as a directory and regular file name for a particular operating or file system. A number of these functions are provided. ...
Full path için değil, sadece dosya ismi veya dizin ismi gibi ayraç içermeyen şeyler için kullanılır. Şu kullanım yanlıştır.
std::string p = "D:\\Programing Projects\\Debug";
if (!boost::filesystem::native(p))
{
  ...
}
permission metodu
Şöyle yaparız.
bfs::path p = "...";
bfs::permissions (p, add_perms|owner_write|group_write|others_write);
read_symlink metodu
Şöyle yaparız.
bfs::path symlink = "c:\\T4 2.0\\ApplicationSymlinks\\T4";
bfs::path path_linked_to = bfs::read_symlink (symlink); 
relative metodu
Bir yoldan diğeri gitmek için geçilmesi gereken yolu verir. Şöyle yaparız.
#include <boost/filesystem.hpp>
#include<iostream>
namespace bfs = boost::filesystem;

int main()
{
  bfs::path parentPath("/home/user1/");
  bfs::path childPath("/home/user1/Downloads/Books");
  bfs::path relativePath = bfs::relative(childPath, parentPath);
  std::cout << relativePath << std::endl;
}
remove metodu
Belirtilen dosyayı siler. İşlem başarısız olursa 'boost::filesystem::remove Access denied' gibi bir exception fırlatılır

remove_all metodu
İmzası şöyle
boost::filesystem::remove_all(dir_to_remove)
Verilen dizin ve altındaki diğer dizin ve dosyalar silinirler. Şöyle yaparız. İşlem başarısız olursa exception fırlatılır
namespace bfs = boost::filesystem;
namespace bs = boost::system;
bs::error_code c;
bfs::path p("...");

if (bfs::exists(p)) {
  try {
    bfs::remove_all (p, c);
  } catch (const boost::filesystem::filesystem_error &e) {
    ...
  }
}
space metodu
Şöyle yaparız.
fs::path p = ...;

fs::space_info sp = space(p);

cout<<"\n filesystem capacity is: "<< sp.capacity;
cout<<"\n filesystem free is: "<< sp.free;
cout<<"\n filesystem available is: "<< sp.available;'
status metodu
Şöyle yaparız.
bfs::path p = ...;
bfs::file_status s = bfs::status(p);
printf("%o\n",s.permissions());
file_status sınıfının permissions metodunun imzası şöyle
perms permissions() const noexcept; 
//Returns: The value of
//permissions() specified by the postconditions of the most recent call
//to a constructor, operator=, or permissions(perms) function.
temp_directory_path
Windows'ta şöyle bir çıktı alırız.
"C:\Users\acelya\AppData\Local\Temp"
temp dizin + dosya ismi için şöyle yaparız.
boost::filesystem::path getTemporaryFilePath()
{
  auto ss = std::stringstream{};
  ss << "MMap_test_" << boost::uuids::random_generator{}();

  return boost::filesystem::temp_directory_path() / ss.str();
}
unique_path - default model
Bu metod güvenlik gerekçesiyle C++17'ye dahil edilmedi. Açıklaması şöyle
unique_path was removed because it was a potential attack vector for malware. There is a window of opportunity between calling unique_path and opening a file at that location during which some other process could create the same file. Depending on what the user does with the file, this may or may not constitute a security vulnerability. A similar issue exists with the POSIX function tmpnam.

As noted in this discussion, this issue will be dealt with in the next iteration of the Filesystem library. Until then, you can either continue using Boost.Filesystem, use the std::tmpnam function provided in <cstdio>, or use safer platform-specific alternatives like mkstemp.
Bu metod temp file ismi üretir. POSIX'teki mkstemp hem dosya ismi üretir hem de dosyayı yaratır ve file descriptor olarak döndürür. unique_path ise daha çok std::tmpnam gibi sadece dosya ismi üretiyor. Bu metodun ismi aslında generate_random_filename() gibi bir şey olmalıydı. Eğer dosyayı da açmak istersek bu metodu şöyle kullanmak gerekir.
for(;;) {
  name = create_likley_unique_name();
  file = open(name, O_EXCL | O_CREAT, mode);
  if(valid(file)) {
    return file;
  }
}
Örnek
Şöyle yaparız. Windows'ta şöyle bir çıktı alırız
"xxxx-xxxx-xxxx-xxxx-xxxx"
// Boost.Filesystem VERSION 3 required
#include <string>
#include <boost/filesystem.hpp>
bfs::path temp = bfs::unique_path();
const std::string tempstr    = temp.native();  // optional
Dizin + dosya için şöyle yaparız.
boost::filesystem::path filename;
filename /= boost::filesystem::temp_directory_path();
filename /= boost::filesystem::unique_path();
unique_path - model
Modeli vermek için şöyle yaparız.
auto filename = boost::filesystem::unique_path("%%%%-%%%%-%%%%-%%%%");

Hiç yorum yok:

Yorum Gönder