Stromy, soubory. BI-PA1 Programování a Algoritmizace 1. Ladislav Vagner, Josef Vogel

Podobné dokumenty
Jazyk C práce se soubory. Jan Hnilica Počítačové modelování 16

Práce se soubory. Úvod do programování 2 Tomáš Kühr

Vstup a výstup datové proudy v C

Práce s binárními soubory. Základy programování 2 Tomáš Kühr

Práce se soubory. Úvod do programování 2 Tomáš Kühr

vstup a výstupv jazyce C

Základy programování (IZP)

- jak udělat konstantu long int: L long velka = 78L;

Práce se soubory. Základy programování 2 Tomáš Kühr

10 Práce s řetězci - pokračování

vstup a výstupy jazyce C

Ukazatele #1, struktury

Jazyk C++, některá rozšíření oproti C

2 Základní funkce a operátory V této kapitole se seznámíme s použitím funkce printf, probereme základní operátory a uvedeme nejdůležitější funkce.

Lekce 9 IMPLEMENTACE OPERAČNÍHO SYSTÉMU LINUX DO VÝUKY INFORMAČNÍCH TECHNOLOGIÍ JAZYK C

Úvod do jazyka C. Ing. Jan Fikejz (KST, FEI) Fakulta elektrotechniky a informatiky Katedra softwarových technologií

Program převod z desítkové na dvojkovou soustavu: /* Prevod desitkove na binarni */ #include <stdio.h>

BI-PA1 Programování a algoritmizace 1 Katedra teoretické informatiky

BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky

IUJCE 07/08 Přednáška č. 1

8. lekce Úvod do jazyka C 3. část Základní příkazy jazyka C Miroslav Jílek

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Spojové struktury. Spojová struktura (linked structure):

Stromy. Strom: souvislý graf bez kružnic využití: počítačová grafika seznam objektů efektivní vyhledávání výpočetní stromy rozhodovací stromy

Základy programování (IZP)

Standardní vstup a výstup

BI-PA1 Programování a Algoritmizace 1. Miroslav Baĺık, Ladislav Vagner a Josef Vogel. 10., 12. a 13. října 2017

Začínáme vážně programovat. Řídící struktury Přetypování Vstupně výstupní operace Vlastní tvorba programů

ZPRO v "C" Ing. Vít Hanousek. verze 0.3

VISUAL BASIC. Práce se soubory

Stromy. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta a kol.

Formátová specifikace má tvar (některé sekce nemají smysl pro načítání) %

Programování v jazyce C pro chemiky (C2160) 4. Textové řetězce, zápis dat do souboru

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Úvod do programovacích jazyků (Java)

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Správné vytvoření a otevření textového souboru pro čtení a zápis představuje

Operační systémy. Cvičení 3: Programování v C pod Unixem

Základní datové typy, proměnné - deklarujeme předem - C je case sensitive rozlišuje malá a velká písmena v názvech proměnných a funkcí

Ošetřování chyb v programech

Rekurzivní algoritmy

PB161 Programování v C++ Proudy pro standardní zařízení Souborové proudy Paměťové proudy Manipulátory

PB071 Programování v jazyce C

Zápis programu v jazyce C#

vstup a výstupy jazyce C

Struktura programu v době běhu

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

BI-PA1 Programování a algoritmizace 1 Katedra teoretické informatiky

BI-PA1 Programování a algoritmizace 1 Katedra teoretické informatiky

for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }

Textové soubory. alg9 1

Úvod do programování. Lekce 1

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Základy programování (IZP)

BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky

- znakové konstanty v apostrofech, např. a, +, (znak mezera) - proměnná zabírá 1 byte, obsahuje kód příslušného znaku

11b Další příklady operací vstupu a výstupu (úvod viz 10)

Algoritmizace a programování. Ak. rok 2012/2013 vbp 1. ze 44

PROGRAMOVÁNÍ V C++ CVIČENÍ

Funkce, procedury, složitost

Soubory. Hung Hoang Dieu. Department of Mathematics Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague 1 / 7

Programování v jazyce C a C++

Vstupní a vstupní proudy v C++

Základy programování (IZP)

Dekompozice problému, rekurze

printf - formatovany vystup

Formátové specifikace formátovací řetězce

Spojové struktury. x, y, a, b. X1 y1 X2 y2 X3 y3. Grafické objekty bod. kružnice. obdélník. lomenáčára

Základní datové struktury

Úvod do programovacích jazyků (Java)

Soubor jako posloupnost bytů

Motivace. Vstup a výstup. Minimální komunikace. Motivace. ÚDPJ - Vstup a výstup. Ing. Lumír Návrat katedra informatiky, A

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Abstraktní datové typy

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Základy programování (IZP)

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

Struktury a dynamická paměť

Preprocesor. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík, 2016

Operační systémy. Cvičení 4: Programování v C pod Unixem

Základy jazyka C. Základy programování 1 Martin Kauer (Tomáš Kühr)

Ukazatele #2, dynamická alokace paměti

Koncepce (větších) programů. Základy programování 2 Tomáš Kühr

Algoritmizace a programování

E+034 = ; = e E+034

Programovací jazyk C(++) C++ area->vm_mm->locked_vm -= len >> PAGE_SHIFT;

Abstraktní třídy, polymorfní struktury

Programování v jazyce C a C++

PROGRAMOVACÍ JAZYKY A PŘEKLADAČE LEXIKÁLNÍ ANALÝZA

Základní datové struktury III: Stromy, haldy

- tzv. standardní vstupní a výstupní proud (input / output stream)

Příkazy if, while, do-while, for, switch

PROGRAMOVACÍ JAZYKY A PŘEKLADAČE REALIZACE PŘEKLADAČE I

Druhy souborů. textové. binární. nestrukturované txt strukturované - ini, xml, csv. veřejné bmp, jpg, wav proprietární docx, cdr, psd

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Práce s řetězci. IUJCE Přednáška č. 10. string.h. vrací: délku řetězce str (bez '\0')

Programování v C++, 2. cvičení

int ii char [16] double dd název adresa / proměnná N = nevyužito xxx xxx xxx N xxx xxx N xxx N

BI-PA1 Programování a Algoritmizace 1. Miroslav Baĺık, Ladislav Vagner a Josef Vogel. 7., 9. a 10. listopadu 2017

Transkript:

Stromy, soubory BI-PA1 Programování a Algoritmizace 1 Ladislav Vagner, Josef Vogel Katedra teoretické informatiky a Katedra softwarového inženýrství Fakulta informačních technologíı České vysoké učení technické v Praze xvagner@fit.cvut.cz, vogeljos@fit.cvut.cz 2. ledna 2017 a 5. ledna 2017

Přehled Stromy a jejich aplikace. Soubory textové. Soubory binární. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 2/57

Stromy Strom: Nelineární spojová struktura. Prvky (uzly) ve stromě mohou mít více než jediného potomka: binární strom uzel může mít 0, 1, nebo 2 potomky, k-nární strom uzel může mít 0, 1,..., k potomků. Typy uzlů: listy uzly bez potomků, kořen uzel bez rodiče, vnitřní uzly uzly s rodičem a potomkem či potomky. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 3/57

Stromy A root B E C F G D left subtree H right subtree leaves internal nodes L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 4/57

Binární stromy implementace Uzly jsou reprezentovány strukturami: hodnota uzlu (užitečná data), spoje na dva potomky (dva ukazatele), spoj na rodiče (nepovinný). Spoje jsou reprezentovány ukazateli: platný spoj je reprezentován referencí na potomka, chybějící spoj (tzn. listy) obsahuje ukazatel NULL. typedef struct TNode { int data; struct TNode * left, *right; struct TNode * parent; /* nepovinný */ TNODE; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 5/57

Binární stromy příklad Dekodér Morseovy abecedy: e t i a n m s u r w d k g o h v f l p j b x c y z q L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 6/57

Binární stromy dekodér Morseovy abecedy typedef struct TNode { char ch; struct TNode *dot, *dash; TNODE; /* pomocné funkce */ TNODE *newnode ( char ch, TNODE *dot, TNODE * dash ) { TNODE *p = (TNODE*)malloc ( sizeof(*p) ); p->ch = ch; p->dot = dot; p->dash = dash; return p; TNODE *newleaf (char ch) { TNODE *p = (TNODE*)malloc ( sizeof(*p) ); p->ch = ch; p->dot = p->dash = NULL; return p; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 7/57

Binární stromy dekodér Morseovy abecedy TNODE *createtree ( void ) { return newnode (, newnode ( E, /*. */ newnode ( I, /*.. */ newnode ( S, /*... */ newleaf ( H, /*... */ newleaf ( V )), /*...- */ newnode ( U, /*..- */ newleaf ( F, /*..-. */ NULL ))), /*..-- nepoužito */ newnode( A, /*.- */...)), newnode ( T, /* - */...))); void freetree ( TNODE * n ) { /* rekurzivní uvolnění uzlů */ if (!n ) return; freetree ( n->left ); freetree ( n->right ); free ( n ); L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 8/57

Binární stromy dekodér Morseovy abecedy char * decodechar ( char * src, char * res ) { TNODE *node = g_root; /* kořen dekodéru morseovky */ while (*src) { char c = *src ++; if (node!= NULL ) { if (c ==. ) node = node->dot; else if (c == - ) node = node->dash; else { *res = node->ch; return src; else { *res =? ; while (*src ==. *src == - ) src++; return src; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 9/57

Binární stromy dekodér Morseovy abecedy TNODE *g_root; int main ( void ) { char text[100], ch, *ptr; g_root = createtree () ; while ( fgets ( text, sizeof(text), stdin ) ) { ptr = text; while ( *ptr ) { ptr = decodechar ( ptr, &ch ); putchar ( ch ); putchar ( \n ); freetree ( g_root ); /* uvolnění dynamické paměti */ return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 10/57

Hra uhodni zvíře Vyber si nějaké zvíře. Já ho uhodnu. Létá? člověk> ne Je to ryba? člověk> ne Neuhádl jsem. Prosím o doplnění mé báze znalostí: Jaké zvíře jsi myslel? člověk> pes Otázka vystihující rozdíl mezi pes a ryba? člověk> štěká? Jaká odpověd je pro psa? člověk> ano Děkuji za doplnění mých znalostí. Chceš pokračovat?... L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 11/57

Hra uhodni zvíře Báze znalostí rozhodovací strom. Strom před a po doplnění. Does it fly? Does it fly? bird fish bird Does it bark? dog fish L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 12/57

Hra uhodni zvíře Nástin řešení: úvodní dialog. inicializace počátečního stromu: létá - pták, ryba aktuální_uzel = kořen while aktuální_uzel není list polož otázku uvedenou v aktuálním_uzlu kladná odpověd -> jdi na levý podstrom záporná odpověd -> jdi na pravý podstrom polož závěrečnou otázku -- je to - název zvířete z listu? kladná odpověd -> úspěšné hledání záporná odpověd -> úprava stromu L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 13/57

Hra uhodni zvíře #define MAX 100 typedef struct TNode { char text[max]; struct TNode *yes, *no; TNODE; TNODE *createnode ( char *text, TNODE *yes, TNODE *no ) { TNODE *n = (TNODE*)malloc ( sizeof(*n) ); strncpy ( n->text, text, sizeof (n->text) ); n->yes = yes; n->no = no; return n; int isleaf ( TNODE * n ) { return n->yes == NULL && n->no == NULL; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 14/57

Hra uhodni zvíře int positiveans ( void ) { char ans[20]; scanf ( "%19s", ans ); /* porovnání řetězců, velká = malá písmena */ return!strcasecmp ( ans, "ano" ); TNODE *inittree ( void ) { return createnode ( "Leta?", createnode ( "pták", NULL, NULL ), createnode ( "ryba", NULL, NULL ) ); void deltree ( TNODE * n ) {/* rekurzivní uvolnění stromu */ if (!n ) return; deltree ( n->yes ); deltree ( n->no ); free ( n ); L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 15/57

Hra uhodni zvíře int main ( void ) { TNODE *root = inittree (); do { TNODE * node = root; printf ( "Vyber si nejake zvire. Ja ho uhodnu.\n" ); while (!isleaf ( node ) ) { printf ( "%s\n", node->text ); if ( positiveans () ) node = node->yes; else node = node->no; printf ( "Je to %s?\n", node->text ); if (! positiveans () ) updateknowledge ( node ); printf ( "Chces pokracovat?\n" ); while ( positiveans () ); deletetree ( root ); return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 16/57

Hra uhodni zvíře void updateknowledge ( TNODE *p ) { char newanim[max], newque[max]; printf ( "Neuhadl jsem. " "Prosim o doplneni me baze znalosti:\n" ); printf ( "Jake zvire jsi myslel?\n" ); scanf ( "%99s", newanim ); printf ( "Otazka vystihujici rozdil mezi %s a %s?\n", newanim, p->text ); scanf ( "%99s", newque ); printf ( "Jaka odpoved je pro %s?\n", newanim ); if ( positiveans () ) { p->yes = createnode ( newanim, NULL, NULL ); p->no = createnode ( p->text, NULL, NULL ); else { p->no = createnode ( newanim, NULL, NULL ); p->yes = createnode ( p->text, NULL, NULL ); strncpy( p->text, newque, sizeof ( p->text ) ); L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 17/57

Soubory Soubor je sekvence bajtů uložená na externí paměti počítače (obvykle na disku). Aplikace obvykle provádějí nad soubory tyto operace: otevření souboru, čtení ze souboru nebo zápis do souboru, uzavření souboru. Přístup k údajům: sekvenční údaje jsou zpracovány postupně, náhodný (libovolný, přímý) jakýkoli údaj může být zpracován (podobně jako v poli). Operační systém (obvykle) neurčuje přístup k údajům v souboru. Metoda přístupu bývá věcí aplikačního programu. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 18/57

Soubory příklad Čtení čísel z klávesnice. Konec je dán přečtením nulové hodnoty. Zápis těchto čísel do souboru. int main( void ) { int x, i = 0; char filename[] = "file1.txt"; FILE *fp; fp = fopen ( filename, "w" ); /* w - pouze zápis, přepsání existujícího souboru! */ printf ( "Napis cisla, konec nula\n" ); do { scanf ( "%d", &x ); fprintf ( fp, "%d", x ); i++; if ( i!= 10 && x!= 0 ) fprintf (" "); else { fprintf( fp, "\n" ); i = 0; while ( x ); if ( i!= 0 ) fprintf ( "\n" ); fclose ( fp ); return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 19/57

Soubory příklad Čtení čísel ze souboru, jejich výpis do řádku, sečtení a výpis součtu. int main( void ) { int x, sum = 0; char filename[] = "file1.txt"; FILE *fp; fp = fopen ( filename, "r" ); /* r - pouze čtení */ do { fscanf ( fp, "%d", &x ); printf ( "%d ", x ); sum += x; while ( x ); fclose ( fp ); printf ( "\nsoucet: %d\n", sum ); return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 20/57

Jména souborů Jméno souboru je řetězec. Je obvykle zadáno jako: pevně jako řetězcový literál v programu, uživatel je vyzván k zadání jména souboru z klávesnice, jméno souboru se získá jako argument z příkazového řádku. int main( void ) { char filename[] = "file1.txt"; FILE *fp; /* jméno souboru je pevné - řetězcová konstanta */ fp = fopen ( filename, "r" );... L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 21/57

Jména souborů Jméno souboru je řetězec. Je obvykle zadáno jako: pevně jako řetězcový literál v programu, uživatel je vyzván k zadání jména souboru z klávesnice, jméno souboru se získá jako argument z příkazového řádku. int main( void ) { char filename[] = "file1.txt"; FILE *fp; /* jméno souboru je pevné - řetězcová konstanta */ fp = fopen ( filename, "r" );... /* Nesprávné jméno souboru: */ FILE * fp = fopen("c:\program files\foo.txt", "r"); L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 21/57

Jména souborů Jméno souboru je řetězec. Je obvykle zadáno jako: pevně jako řetězcový literál v programu, uživatel je vyzván k zadání jména souboru z klávesnice, jméno souboru se získá jako argument z příkazového řádku. int main( void ) { char filename[] = "file1.txt"; FILE *fp; /* jméno souboru je pevné - řetězcová konstanta */ fp = fopen ( filename, "r" );... /* Nesprávné jméno souboru: */ FILE * fp = fopen("c:\program files\foo.txt", "r"); /* Oprava: */... = fopen("c:\\program files\\foo.txt", "r"); L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 21/57

Jména souborů FILE *openfile ( char * mode ) { FILE *fp; char filename[40]; printf ( "Napis jmeno souboru:\n" ); scanf ( "%39s", filename ); /* jméno souboru přečteno ze standardního vstupu */ fp = fopen ( filename, mode ); if (! fp ) { printf ( "Spatne jmeno souboru\n" ); exit ( 1 ); /* v produkčním kódu takto nikoli */ return fp; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 22/57

Jména souborů int main( int argc, char * argv []) { FILE *fp; if ( argc < 2 ) { printf ( "Chybi argument jmeno_souboru.\n" ); return 1; /* jméno souboru je dáno argumentem příkazového řádku */ fp = fopen ( argv[1], "r" ); /* argv[0] je jméno programu */ /* argv[1] je první argument programu */... L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 23/57

Chyby vstupu/výstupu Funkce pracující se soubory mohou selhat. Existuje mnoho důvodů proč: soubor neexistuje, uživatel nemá práva k přístupu nebo k zápisu souboru, soubor nemůže být zapsán (read-only medium, např. CD-ROM), HW chyba při přístupu k externímu zařízení, vstupní data jsou špatně formátovaná nebo zcela chybí, data nemohou být zapsána (disk full),... Aplikace musí testovat chybové kódy, aby chyby mohla zpracovat. Ignorování chyb je nehorší řešení: problém je skryt, uživatel není varován, data mohou být ztracena. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 24/57

Soubory zpracování chyb int main( void ) { int x; char filename[] = "file1.txt"; FILE *fp; if (! ( fp = fopen(filename, "w") ) ); { /* soubor se nepodařilo otevřít */ printf ( "Napis cisla, konec nula\n" ); do { if ( scanf ( "%d", &x )!= 1 ) { /* číslo se nepodařilo přečíst */ if ( fprintf(fp, "%d ", x) < 0 ) { /* chyba zápisu */ ; while ( x ); if ( fclose ( fp ) == EOF ) { /* chyba uzavření souboru - asi disk full */ return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 25/57

Konec souboru End-of-file End-of-file je příznakm který OS sleduje u každého otevřeného souboru. Funkce OS, jež je volána při zpracování souboru, nastaví příznak konce souboru, když už ve čteném souboru nejsou další data: aplikace přečetla všechna data ze souboru (z diskového souboru), uživatel se rozhodl zakončit standardní vstup (stiskem Ctrl-D nebo Ctrl-Z), druhá strana sít ového spojení spojení uzavřela (speciální soubor spojený se sít ovou linkou, např. spojení TCP),... Pokud bylo dosaženo konce souboru, žádná další data nebudou ze souboru čtena a další požadavky na čtení vrací chybu. Konec souboru je testován voláním funkce feof (). Aplikace musí použít funkci feof (), aby odlišila konec souboru od od chyby vstupu/výstupu, obě situace jsou signalizovány podobně. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 26/57

End-of-file int main( void ) { int x, sum = 0, err = 0; FILE *fp = fopen ( "in.txt", "r" ); if ( fp ) { while (fscanf ( fp, "%d", &x ) == 1) sum += x; if (! feof ( fp ) ) err = 1; fclose ( fp ); else err = 1; if ( err ) printf ( "chyba vstupu/vystupu\n" ); else printf ( "\nsoucet: %d\n", sum ); return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 27/57

Standardní soubory Program má k dispozici několik standardních souborů: stdout standardní výstup (konzolový výstup), stdin standardní vstup (vstup z klávesnice), stderr standardní chybový výstup (konzole). Používá se pro chybová a diagnostická hlášení. Standardní soubory jsou otevřeny operačním systémem při startu procesu. Standardní vstup a výstup má speciální funkce (zkráceně): printf (...) fprintf ( stdout,... ) puts (...) fputs (..., stdout ) putchar (...) fputc (..., stdout ) scanf (...) fscanf ( stdin,...) getchar () fgetc ( stdin ) L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 28/57

Kopie textového souboru int main( void ) { char c; FILE * in, * out; if ( (in = fopen ( "...", "r" ) ) == NULL ) {... if ( (out = fopen ( "...", "w" ) ) == NULL ) { fclose ( in );... while ( fscanf ( in, " %c", &c ) == 1 ) fprintf ( out, "%c", c ); if (! feof ( in ) ) {... fclose ( in ); if ( fclose ( out ) == EOF ) {...... L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 29/57

Kopie textového souboru int main( void ) { char c; FILE * in, * out; if ( (in = fopen ( "...", "r" ) ) == NULL ) {... if ( (out = fopen ( "...", "w" ) ) == NULL ) { fclose ( in );... while ( fscanf ( in, " %c", &c ) == 1 ) fprintf ( out, "%c", c ); if (! feof ( in ) ) {... fclose ( in ); if ( fclose ( out ) == EOF ) {...... Nefunguje: odstraňuje bílé znaky, nové řádky zmizí, může být pomalý. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 29/57

Kopie textového souboru int main( void ) { int c; /* záměrně int */ FILE * in, * out; if ( (in = fopen ( "...", "r" ) ) == NULL ) {... if ( (out = fopen ( "...", "w" ) ) == NULL ) { fclose ( in );... while ( ( c = fgetc ( in ) )!= EOF ) fputc ( c, out ); if (! feof ( in ) ) {... fclose ( in ); if ( fclose ( out ) == EOF ) {...... L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 30/57

Kopie textového souboru int main( void ) { int c; /* záměrně int */ FILE * in, * out; if ( (in = fopen ( "...", "r" ) ) == NULL ) {... if ( (out = fopen ( "...", "w" ) ) == NULL ) { fclose ( in );... while ( ( c = fgetc ( in ) )!= EOF ) fputc ( c, out ); if (! feof ( in ) ) {... fclose ( in ); if ( fclose ( out ) == EOF ) {...... Nefunguje: může zkazit nové řádky, může být pomalý. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 30/57

Kopie textového souboru int main( void ) { char buffer[100]; FILE * in, * out; if ( (in = fopen ( "...", "r" ) ) == NULL ) {... if ( (out = fopen ( "...", "w" ) ) == NULL ) { fclose ( in );... while ( fgets ( buffer, sizeof(buffer), in )!= NULL ) fputs ( buffer, out ); if (! feof ( in ) ) {... fclose ( in ); if ( fclose ( out ) == EOF ) {...... L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 31/57

Kopie textového souboru int main( void ) { char buffer[100]; FILE * in, * out; if ( (in = fopen ( "...", "r" ) ) == NULL ) {... if ( (out = fopen ( "...", "w" ) ) == NULL ) { fclose ( in );... while ( fgets ( buffer, sizeof(buffer), in )!= NULL ) fputs ( buffer, out ); if (! feof ( in ) ) {... fclose ( in ); if ( fclose ( out ) == EOF ) {...... Nefunguje: může zkazit nové řádky. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 31/57

Textové a binární soubory Operační systém nerozlišuje typy souborů. Soubory jsou prostě sekvence bajtů. Textové a binární soubory jsou kategorie zavedené lidmi: textové soubory jsou čitelné lidmi. Soubor je tvořen sekvencí rozumně dlouhých řádků (složených ze znaků), oddělených znakem nový řádek (nové řádky). Informace je poskytována v lidské formě (dekadické číslice... ). Bílé znaky (mezery, tabelátory, nové řádky) se mohou vyskytovat kdekoli v souboru a nemají vliv na význam informace v souboru obsažené. binární soubory nejsou lidem jednoduše srozumitelné. Informace je zakódována do vnitřní reprezentace (např. dvojkový doplněk) bez oddělovačů. Ztratí-li se bajt, je celá informace zkažená. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 32/57

Textové soubory Výhody: Jednoduše čitelné (lidem). Jednoduše manipulovatelné (textový editor). Dobře přenositelné mezi různými platformami. Redundance (když je kus textu zkažen, tak je zbytek stále použitelný). Nevýhody: Informace musí být zkonvertována z vnitřní formy (výstup) nebo do vnitřní formy (vstup). Obtížnější zpracování (SW složitost, časové požadavky). Obvykle delší než ekvivalentní binární reprezentace. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 33/57

Binární soubory Výhody: bez konverze na vstupu/výstupu (rychlé, snadno naprogramovatelné). Kompaktní (stejná informace zaujímá obvykle méně místa než ve vnější reprezentaci). Nevýhody: Obtížně srozumitelné lidem. Obtížná manipulace (specializované programy utility). Problematická portabilita mezi platformami (může vyžadovat konverzi). Snáze rozbitné (je-li soubor částečně poškozený, zbytek je často nepoužitelný). L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 34/57

Textové a binární soubory Textové soubory jsou portabilní mezi platformami. Jediný problém je nový řádek: DOS and Windows používají dva bajty (CR + LF 0x0d 0x0a) pro oddělení řádků, UNIX (Linux, Solaris,... ) k tomuto účelu používá jediný bajt (LF 0x0a), (starý) Mac používá jeden bajt (CR 0x0d). Standardní knihovna provádí automatickou konverzi. Zdrojový program zůstává stejný pro všechny platformy: zdrojový kód (programátor) používá LF (0x0d, \n) pro oddělení řádků, standardní knihovna je si vědoma konvencí operačního systemu pro nové řádky, standardní knihovna konvertuje oddělovače řádků z platformy vstupu na platformu výstupu. Tyto konverze musí být korektně povoleny (zpracování textových souborů) nebo zakázány (zpracování binárních souborů). L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 35/57

Kopie souboru (kopie 1:1, textový nebo binární) int main( void ) { int c; /* záměrně int */ FILE * in, * out; if ( (in = fopen ( "...", "rb" ) ) == NULL ) {... if ( (out = fopen ( "...", "wb" ) ) == NULL ) { fclose ( in );... while ( ( c = fgetc ( in ) )!= EOF ) fputc ( c, out ); if (! feof ( in ) ) {... fclose ( in ); if ( fclose ( out ) == EOF ) {...... Mód otevření souboru: wb / rb (binární bez konverze nových řádků). L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 36/57

Kopie souboru (kopie 1:1, textový nebo binární) int main( void ) { int c; /* záměrně int */ FILE * in, * out; if ( (in = fopen ( "...", "rb" ) ) == NULL ) {... if ( (out = fopen ( "...", "wb" ) ) == NULL ) { fclose ( in );... while ( ( c = fgetc ( in ) )!= EOF ) fputc ( c, out ); if (! feof ( in ) ) {... fclose ( in ); if ( fclose ( out ) == EOF ) {...... Mód otevření souboru: wb / rb (binární bez konverze nových řádků). Jen jeden bajt na jedno volání to může být pomalé. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 36/57

Kopie souboru (kopie 1:1, textový nebo binární) int main( void ) { char buffer[100]; int len; FILE * in, * out; if ( (in = fopen ( "...", "rb" ) ) == NULL ) {... if ( (out = fopen ( "...", "wb" ) ) == NULL ) { fclose ( in );... while ((len = fread (buffer, 1, sizeof(buffer), in ))!= 0 ) if ( fwrite ( buffer, 1, len, out )!= len ) { /* write error */ if (! feof ( in ) ) {... fclose ( in ); if ( fclose ( out ) == EOF ) {...... Mód otevření: wb / rb (binární bez konverze nových řádků). L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 37/57

Zpracování binárních souborů int main( void ) { int x; FILE *fp = fopen ( "...", "wb" ); if (! fp ) { /*... */ do { scanf ( "%d", &x ); if ( fwrite( &x, sizeof(x), 1, fp )!= 1 ) { /* zpracování chyby */ while ( x ); if ( fclose ( fp ) == EOF ) {... return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 38/57

Struktury a binární soubory Struktury reprezentují komplexní informace, tj. popisují vlastnosti nějaké entity (studenta v našem příkladu). Když mají být data uložena perzistentně, binární soubor obsahující struktury je zajímavou volbou. Přístup je rychlý (nejsou třeba žádné konverze), a navíc, je možný náhodný (přímý) přístup k datům. Struktury uložené v binárních souborech jsou základní ideou implementace databázové paměti. Tato idea má několik nedostatků: Reprezentace struktur je podstatně závislá na platformě, pro výpis a úpravu binárních souborů jsou třeba speciální programy. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 39/57

Struktury a binární soubory int main( void ) { TSTUDENT st[max]; int cnt = 0, i; FILE *fp;... /* naplnění pole st nějakým způsobem */... fp = fopen ( "students.bin", "wb" ); /* binární soubor s přístupem na zápis: wb */ if (! fp fwrite( st, sizeof(st[0]), cnt, fp)!= cnt ) fclose ( fp ) == EOF ) { /* chyba */ if ( fp ) fclose ( fp ); /* uvolnění zdrojů, také v případě chyby */ return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 40/57

Struktury a binární soubory Čtení binárního souboru struktur. Tento příklad čte obsah souboru po jednotlivých záznamech. int main( void ) { TSTUDENT s; FILE * fp; fp = fopen ( "students.bin", "rb" ); if (!fp ) { /* chyba */ while (fread ( &s, sizeof(s), 1, fp ) == 1 ) printstudent ( st ); fclose ( fp ); return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 41/57

Struktury a binární soubory Čtení binárního souboru struktur (celé pole). int main( void ) { TSTUDENT * s; int cnt; FILE * fp; fp = fopen ( "students.bin", "rb" ); if (!fp ) { /* chyba */ fseek ( fp, 0, SEEK_END ); /* nastavení na EOF */ cnt = ftell ( fp ) / sizeof(*s); fseek ( fp, 0, SEEK_SET ); /* nastavení na začátek */ s = (TSTUDENT *)malloc ( cnt * sizeof(*s) ); if ( fread ( s, sizeof (*s), cnt, fp )!= cnt ) { /* chyba */ fclose ( fp ); /*... použití pole */ free ( s ); return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 42/57

Struktury a binární soubory Jak přidat nového studenta na konec binárního souboru? int main( void ) { TSTUDENT s; FILE * fp; printf ( "Enter new student:\n" ); readstudent ( stdin, *s ); fp = fopen ( "students.bin", "ab"); /* mod souboru: ab = jen append (doplnění), binárně */ if (!fp ) { /* chyba */ if ( fwrite ( &s, sizeof (s), 1, fp )!= 1 fclose ( fp ) == EOF ) { /* chyba */ return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 43/57

Struktury a binární soubory Problém: zapsat nového studenta do binárního souboru. Předpokládáme, že soubor je seřazen (podle průměrného prospěchu, vzestupně). Nově vložený záznam musí zachovat toto pořadí. Je třeba nový pomocný soubor. Nástin řešení: přečíst data nového studenta z klávesnice, zkopírovat záznamy všech studentů majících lepší prospěch, než nový student, zkopírovat nový záznam do pomocného souboru, zkopírovat zbylé záznamy z původního souboru, zkopírovat obsah pomocného souboru zpět do původního souboru. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 44/57

Struktury a binární soubory int main( void ) { TSTUDENT x, st; FILE *orgfp, *tmpfp; int valid; printf( "Napis data noveho studenta:\n"); readstudent ( stdin, &st ); orgfp = fopen ( "students.bin", "rb" ); /* test chyby vynechán - málo místa na stránce */ tmpfp = fopen ( "students.tmp", "wb" ); /* kopie věch lepších studentů */ while ( (valid = fread ( &x,sizeof(x), 1, orgfp ) ) == 1 && x.avg <= st.avg ) fwrite( &x, sizeof(x), 1, tmpfp ); /* ted zápis záznamu nového studenta */ fwrite( &st, sizeof(st), 1, tmpfp ); /* pokračování dále... */ L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 45/57

Struktury a binární soubory /*... pokračování */ /* kopie zbytku původního souboru */ /* pozor: když valid == 0, tak není už nic ke zkopírování nezbývá */ if (valid) { fwrite ( &x, sizeof(x), 1, tmpfp ); while (fread( &x, sizeof(x), 1, orgfp ) == 1) fwrite ( &x, sizeof(x), 1, tmpfp ); /* uzavření obou souborů */ fclose ( orgfp ); fclose ( tmpfp ); movefile ( "students.tmp", "students.bin" ); return 0; L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 46/57

Struktury a binární soubory Jak zkopírovat obsah souboru? void movefile ( char * src, char * dst ) { FILE * srcfp, * dstfp; TSTUDENT x; srcfp = fopen ( src, "rb" ); dstfp = fopen ( dst, "wb" ); while ( fread ( &x, sizeof(x), 1, srcfp ) == 1) fwrite ( &x, sizeof(x), 1, dstfp ); fclose ( srcfp ); fclose ( dstfp ); L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 47/57

Struktury a binární soubory Alternativně použitím OS funkcí pro manipulaci se soubory (rychlejší, ale ne na 100% portabilní). void movefile ( char * src, char * dst ) { unlink ( dst ); rename ( src, dst ); L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 48/57

Přehled standardního vstupu/výstupu (I/O) Standardní I/O (stdio.h): textový I/O (formátovaný), binární I/O (surový). Textový vstup/výstup: standardní I/O printf, scanf, putchar, getchar souborový I/O fprintf, fscanf, fputc, fgetc pamět ový I/O snprintf, sscanf Binární input/output: I/O fread, fwrite řízení fseek, ftell Standardní soubory: stdout konzolový výstup, stdin konzolový vstup (klávesnice), stderr konzolový výstup, diagnostika chyb a hlášení (error log). Standardní soubory mohou být přesměrovány (na úrovni OS). L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 49/57

Přehled textového výstupu int putchar ( int ch ) výstup znaku ch. int fputc ( int ch, FILE * fp ) výstup znaku ch do souboru fp. int puts ( char * str ) výstup řetězce str, s doplněním nového řádku. int fputs ( char * str, FILE * fp ) výstup řetězce str do souboru fp, bez doplnění nového řádku. int printf ( char * fmt,... ) výstup formátovaného řetězce, fmt je řetězec obsahující konverze. int fprintf ( FILE * fp, char * fmt,... ) výstup formátovaného řetězce do souboru fp, fmt je řetězec obsahující konverze. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 50/57

Přehled textového výstupu Výstupní formátový řetězec (specifikace konverze): %[značky][šířka][.přesnost][modifikace_délky]znak_konverze Exaktní popis je v manuálových stránkách viz man 3 printf. Příklady výstupního formátu: konverze argument výstup %d -300-300 %-5i -5-5 %5x 0xABC abc %#09X 0x12AB 0X00012AB %6.2f 4.352 4.35 %+6.0f 100.44 +100 %10.3E 100.44 _1.004E+02 %*.*f 7, 2, 100.123 _100.12 %c a a %4s "hello" hello %.4s "hello" hell %-10.4s "hello" hello L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 51/57

Přehled textového vstupu int getchar ( void ) čte znak. Návratová hodnota je typu int, aby se odlišil skutečný znak od hodnoty EOF (chyba nebo end-of-file). int fgetc ( FILE * fp ) čte znak ze souboru fp. char * gets ( char * str ) NIKDY nepoužívejte tuto funkci! Nelze ji použít bezpečně. Místo ní použijte funkci fgets (). char * fgets ( char * str, int max, FILE * fp ) čte řádek ze souboru fp (nejvýše však (max - 1) znaků) a uloží je do bufferu str. int scanf ( char * fmt,... ) vstup formátovaných dat. fmt je řetězec obsahující konverze. int fscanf ( FILE * fp, char * fmt,... ) vstup formátovaných dat ze souboru fp. fmt je řetězec obsahující konverze. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 52/57

Přehled textového vstupu vstupní formátový řetězec (specifikace konverze): %[*][šířka][modifikátor délky]znak_konverze Exaktní popis je v manuálových stránkách viz man 3 scanf. Příklady vstupního formátu: konverze typ argumentu poznámka %d int * %*i none číslo je přečteno, ale není uloženo %x int * vstup je hexadecimální %f float * %e float * %g float * %lf double * %s char * buffer musí být dostatečně dlouhý (je skoro nemožné to garantovat) %23s char * řetězec, max. 23 znaků L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 53/57

Přehled pamět ového I/O snprintf ( char * dst, int max, char * fmt,... ) fmt a argumenty se použijí k přípravě textové reprezentace (podobně jako printf nebo fprintf). Výsledný řetězec je uložen do pamět ového bufferu dst o délce max znaků. int sscanf ( char * src, char * fmt,... ) čte řetězec src. Podle konverzí ve fmt, extrahuje argumenty ze src. Pracuje jako funkce scanf nebo fscanf, ale čte vstup z pamět ového bufferu. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 54/57

Souborový I/O FILE * fopen ( char * filename, char * mode ) otevře soubor filename v módu mode. Vrací NULL při chybě. Mód je kombinace: r čtení (read-only), w zápis (write-only), obsah původního souboru je přepsán, a připsání (append) za konec pův. souboru, b binární mód (konverze nových řádků neaktivní), t textový mód (konverze nových řádků aktivní, implicitní hodnota), + mód úprav (update) ( r+ - čtení + zápis, w+ - zápis bez počátečního přepsání). int fclose ( FILE * fp ) zapíše diskové buffery fyzicky do souboru na disku, zavře otevřený soubor, uvolní zdroje OS. Vrací EOF při chybě (chyba při fyzickém zápisu bufferů). L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 55/57

Binární souborový I/O int fread ( void * dst, size t size, size t n, FILE * fp ) čte n bloků o délce size bajtů do bufferu dst. Vrací počet skutečně přečtených bloků. int fwrite ( void * src, size t size, size t n, FILE * fp ) zapisuje n bloků o délce size bajtů z bufferu src. Vrací počet bloků skutečně zapsaných. int fseek ( FILE * fp, long offset, int how ) přesune souborový ukazatel (náhodný přístup) o offset bajtů vzhledem k pozici dané argumentem how: SEEK SET od počátku, SEEK CUR od současné pozice, SEEK END od konce. long ftell ( FILE * fp ) vrací aktuální pozici v otevřeném souboru. L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 56/57

Otázky a odpovědi Otázky... L. Vagner, J. Vogel, ČVUT FIT Stromy, soubory, BI-PA1 57/57