Adresářová struktura

Kolem práce s adresářovou strukturou je spousta problémů. Jde o to, že různé operační systémy používají rozličné způsoby uchovávání dat. Například v Unixech existují ke každému souboru a adresáři přístupová práva, která musíte při vytváření a mazání respektovat, zatímco třeba v DOSu nikoliv. Zde probírané funkce se proto liší systém od systému, překladač od překladače.

Příklad, který najdete na konci kapitoly, byl odladěn v operačním systému Linux, v DOSovém překladači Borland C a windowsovém Dev-C++. Měl by vám být dostatečným návodem k tomu, abyste (s pomocí nápovědy) dokázali vše, co zde bude popisováno.

Jo a ještě jeden problém tu je. Deklarace těch samých funkcí v různých překladačích jsou v různých hlavičkových souborech. Proto je zde nebudu uvádět (hledejte si sami, už jste dost velký :-). V Linuxu hledejte v manuálových stránkách v sekci 2 a 3. Trochu vám může napovědět příklad na konci této kapitoly.

Aktuální adresář

Ke zjištění aktuálního adresáře slouží funkce getcwd(). Aktuální adresář je ten, ve kterém se nacházíte při spouštění programu, nikoliv ten, ve kterém se nachází spouštěný program.

char *getcwd(char *buf,size_t size);

První argument, buf, je ukazatel na textové pole, kam se uloží název aktuálního adresáře. Druhý argument, size, je maximální velikost, která se do pole může uložit. V případě chyby (např. jméno aktuálního adresáře je delší než size) vrátí getcwd() ukazatel NULL.

Vytvoření adresáře

K vytvoření adresáře se používá funkce mkdir(). Bohužel zde narážíme na již zmíněný problém s kompatibilitou různých operačních systémů/překladačů. Proto zde uvedu dvě deklarace funkce mkdir(). První je pro DOSový překladač Borland C, druhá pro Linuxový překladač gcc.

V Linuxu mají adresáře (i soubory) přístupová práva. Ty umožňují, mimo jiné, zabránit zápisu do adresáře. Jelikož však budeme chtít do vytvořeného adresáře vstoupit nebo do něj něco zapsat, je třeba mu nastavit správně práva. Proto má funkce mkdir() v Linuxu jeden argument navíc. Přístupová práva se navíc kombinují s hodnotou umask. Tento problém však přesahuje rámec výuky jazyka C, ale týká se spíše operačních systémů Unix/Linux. Proto jej zde nebudu řešit a odkážu vás na dokumentaci. Odkazuji vás na dokumentaci.

int mkdir(const char *pathname);               /* DOSová verze */
int mkdir(const char *pathname, mode_t mode);  /* LINUXová verze */

Argument pathname je pochopitelně jméno adresáře, který chcete vytvořit. Může to být například "jmeno", nebo "../jmeno" atp. Dvě tečky, jak jistě víte, označují předchozí adresář v adresářové struktuře. Lomítko je oddělovač jmen adresářů. Ovšem pozor, v DOSu (Windows) je to obrácené lomítko \ (backslash), kdežto v Unixech obyčejné  /. Za to, že je to jinak, nenadávejte Unixům, ty tu byli dříve.

Argument mode v deklaraci mkdir() pro Unixy určuje přístupová práva. Přesněji řečeno, přístupová práva k souboru budou nastavena jako mode & ~umask.

Návratovou hodnotou je 0 v případě, že vše proběhlo bez chyby. Při chybě -1 a je nastavena globální proměnná errno na číslo chyby.

Přístupová práva

Přístupová práva k souborům a adresářům se nastavují pomocí funkce chmod() definované v hlavičkovém souboru <sys/stat.h>, <io.h>, nebo nějakém jiném (záleží na prostředí, ve kterém zdrojový kód překládáte).

int chmod(const char *path, mode_t mode);

První argument je cesta k souboru nebo adresáři, jehož práva měníte. Druhý argument nastavuje přístupová práva. Funkce vrací 0 v případě úspěchu, jinak -1 a nastavuje proměnnou errno.

Parametr mode můžete nastavit pomocí maker definovaných v <sys/stat.h>, ovšem musíte si dát pozor na to, která makra jsou pro váš systém dostupná. Ve Windows to můžete použít například S_IREAD | S_IWRITE pro právo čtení a zápisu. V Linuxu se podívejte do manuálových stránek, jaká jsou dostupná makra (man 2 chmod).

Když v programu vytvoříte soubor nebo adresář, nemáte jistotu, jaká jsou na něm nastavena přístupová práva. A to ani při použití argumentu mode ve funkci mkdir(), protože výsledná práva mohou být ovlivněna nastavením OS, například v Linuxu pomocí umask. Chcete-li mít jistotu, musíte použít po vytvoření souboru nebo adresáře funkci chmod().

Změna aktuálního adresáře

Aktuální adresář se změní pomocí funkce chdir(). Je dobré vědět, že změna aktuálního adresáře se projeví dozajista jen v programu, který tuto funkci spustil. Jestli v tomto adresáři zůstanete i po skončení onoho programu, nebo po skončení programu budete v adresáři, ze kterého jste program spustili, to už závisí na jiných věcech (napovím: v DOSu platí to první, v Unixech nejčastěji to druhé).

int chdir(const char *path);

Argumentem funkce je adresář, do kterého se chcete přesunout. Návratová hodnota je v případě úspěchu 0, jinak -1 a je nastavena proměnná errno.

Mazání souborů a adresářů

Dle normy ANSI C slouží k mazání souborů a adresářů funkce remove(). Leč většinou je tato funkce nahrazena dvěma jinými funkcemi. Funkcí unlink() pro mazání souborů a funkcí rmdir() pro mazání prázdných adresářů.
Funkce remove() volá funkci unlink() pro soubory a funkci rmdir() pro adresáře.

int remove(const char *pathname);
int unlink(const char *pathname);
int rmdir(const char *pathname);

Argument pathname je jméno souboru resp. adresáře, který chcete smazat. Návratové hodnoty jsou v případě úspěchu 0, jinak -1 a je nastavena proměnná errno.

Adresář lze smazat pouze pokud je prázdný.

Přejmenování a přesunutí souborů

K přejmenování souboru či adresáře slouží funkce rename(). Pokud bude nové jméno souboru v jiném adresáři než staré jméno, pak se soubor přesune. K tomu však dojde jedině v případě, že staré a nové jméno je na jednom disku (diskovém oddíle). Pokud bude nové jméno jméno již existujícího souboru, bude tento soubor přepsán! Deklarace funkce vypadá následovně:

int rename (const char *oldpath, const char *newpath);

Návratová hodnota v případě úspěchu je 0, jinak -1 a je nastavena proměnná errno.

Příklad

Tentokrát bez komentáře.

  1. /*------------------------------------------------*/
  2. /* c34/adresar.c                                  */
  3. #define _CRT_SECURE_NO_WARNINGS
  4.  
  5. #include <stdio.h>
  6. #include <errno.h>
  7. #ifdef __unix__
  8.       #include <unistd.h>
  9.       #include <sys/stat.h>
  10.       #include <sys/types.h>
  11. #elif defined _MSC_VER
  12.       #include <direct.h<<?php ?>
  13. #else
  14.       #include <dir.h>
  15. #endif
  16.  
  17. #define ADRESAR "DATADIR"
  18. #define SOUBOR  "ahoj.txt"
  19.  
  20. #ifdef __unix__
  21.        #define GETCWD(X, I) getcwd(X, I)
  22.        #define MKDIR(X) mkdir(X, 0777)
  23.        #define CHDIR(X) chdir(X)
  24.        #define UNLINK(X) unlink(X)
  25.        #define RMDIR(X) rmdir(X)
  26. #elif defined _MSC_VER
  27.        #define GETCWD(X, I) _getcwd(X, I)
  28.        #define MKDIR(X) _mkdir(X)
  29.        #define CHDIR(X) _chdir(X)
  30.        #define UNLINK(X) _unlink(X)
  31.        #define RMDIR(X) _rmdir(X)
  32.  #else
  33.        #define GETCWD(X, I) getcwd(X, I)
  34.        #define MKDIR(X) mkdir(X)
  35.        #define CHDIR(X) chdir(X)
  36.        #define UNLINK(X) unlink(X)
  37.        #define RMDIR(X) rmdir(X)
  38.  #endif
  39.  
  40. int errkonec(void)
  41. {
  42.     perror("CHYBA");
  43.     fprintf(stderr, "Stisknete ENTER pro ukonceni ...\n");
  44.     (void) getchar();
  45.     return errno;
  46. }
  47.  
  48. int main(void)
  49. {
  50.     char text[255];
  51.     FILE *soubor;
  52.     char c;
  53.  
  54.     GETCWD(text, sizeof(text) / sizeof(text[0]));
  55.     printf("Vytvarim v adresari %s podadresar %s\n", text, ADRESAR);
  56.  
  57.  
  58.     if (MKDIR(ADRESAR) != 0) {
  59.         return errkonec();
  60.     }
  61.  
  62.     printf("Vstupuji do adresare %s\n", ADRESAR);
  63.     if (CHDIR(ADRESAR) != 0) {
  64.         return errkonec();
  65.     }
  66.  
  67.     printf("Vytvarim soubor %s\n", SOUBOR);
  68.  
  69.     if (!(soubor = fopen(SOUBOR, "w+")))
  70.         return errkonec();
  71.  
  72.     fprintf(soubor, "Ahoj");
  73.     fclose(soubor);
  74.     printf("Mam zase vse smazat? [y/n] ");
  75.     c = getchar();
  76.     if (c == 'n') {
  77.         fputs("Koncim.", stdin);
  78.         return 0;
  79.     } else if (c != 'y') {
  80.         fputs("Nechapu, koncim.", stdin);
  81.         return 0;
  82.     }
  83.  
  84.     /* mazani souboru a adresare */
  85.     printf("Mazu soubor %s\n", SOUBOR);
  86.     if (UNLINK(SOUBOR) != 0) {
  87.         return errkonec();
  88.     }
  89.  
  90.     printf("Opoustim adresar %s\n", ADRESAR);
  91.     /* prechod v adresarove strukture o adresar vyse */
  92.     if (CHDIR("..") != 0) {
  93.         return errkonec();
  94.     }
  95.  
  96.     printf("Mazu adresar %s\n", ADRESAR);
  97.     if (RMDIR(ADRESAR) != 0) {
  98.         return errkonec();
  99.     }
  100.  
  101.     return 0;
  102. }
  103.  
  104. /*------------------------------------------------*/
Visual Studio

Funkce mkdir() a jí podobné nejsou součástí standardu C89, ani C99. Jsou součástí standardu POSIX. Standard C++ se rozhodl o něco později tyto funkce zahrnout, ale aby se nepletli s POSIX normou, pojmenoval je s podtržítkem na začátku: _mkdir() atp.

Visual Studio nepodporuje funkce bez podtržítka, ale můžete použít funkce z C++ standardu i v jazyku C.

Možný výstup:

Vytvarim v adresari /home/rimmer/public_html/rimmer/c podadresar DATADIR
Vstupuji do adresare DATADIR
Vytvarim soubor ahoj.txt
Mam zase vse smazat? [y/n] y
Mazu soubor ahoj.txt
Opoustim adresar DATADIR
Mazu adresar DATADIR

Za domácí úkol použijte v příkladu funkci chmod() na nově vytvořený adresář po volání funkce mkdir().

Komentář Hlášení chyby
Created: 29.8.2003
Last updated: 26.6.2014
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..