This shows you the differences between two versions of the page.
so:laboratoare:laborator-02 [2019/03/11 15:16] razvan.nitu1305 [EXTRA] |
so:laboratoare:laborator-02 [2022/03/11 16:38] (current) aapostolescu [Trunchierea fișierelor] typo |
||
---|---|---|---|
Line 2: | Line 2: | ||
===== Materiale ajutătoare ===== | ===== Materiale ajutătoare ===== | ||
- | * [[http://elf.cs.pub.ro/so/res/laboratoare/lab02-slides.pdf | lab02-slides.pdf]] | ||
- | * [[http://elf.cs.pub.ro/so/res/laboratoare/lab02-refcard.pdf | lab02-refcard.pdf]] | ||
* [[http://elf.cs.pub.ro/so/res/tutorial/lab-02-operatii-io/ | Video Operații IO]] | * [[http://elf.cs.pub.ro/so/res/tutorial/lab-02-operatii-io/ | Video Operații IO]] | ||
Line 41: | Line 39: | ||
Un fișier are asociat cursorul de fișier (file pointer) care indică poziția curentă în cadrul fișierului. Cursorul de fișier este un întreg care reprezintă deplasamentul (offset-ul) față de începutul fișierului. | Un fișier are asociat cursorul de fișier (file pointer) care indică poziția curentă în cadrul fișierului. Cursorul de fișier este un întreg care reprezintă deplasamentul (offset-ul) față de începutul fișierului. | ||
- | Operațiile specifice pentru lucrul cu fișiere: | + | Pentru a crea o paralelă între operațiile cu fișiere de pe Linux și Windows, vă punem la dispoziție tabelul de mai jos unde sunt descrise diverse funcționalități împreună cu apelurile de sistem care le implementează. |
- | * **deschiderea/crearea unui fișier** - înseamnă asocierea unui descriptor de fișier sau a unui handle cu un fișier identificat prin numele său (( ''fopen'' (ISO C), ''open'', ''creat'' (POSIX), ''CreateFile'' (Win32 API) )). ( [[#crearea deschiderea si inchiderea fisierelor|Linux]], [[#crearea deschiderea si inchiderea|Windows]] ) | + | |
- | * **închiderea unui fișier** - înseamnă eliberarea structurilor de fișier asociate procesului și a descriptorului (handle-ului) acelui fișier - doar dacă nu mai există nici o intrare în tabela file descriptorilor care să puncteze spre acea structură (( ''fclose'' (ISO C), ''close'' (POSIX), ''CloseHandle'' (Win32 API) )). ( [[#crearea deschiderea si inchiderea fisierelor|Linux]], [[#crearea deschiderea si inchiderea|Windows]] ) | + | ^ Descriere ^ ISO C ^ Linux ^ Windows ^ |
- | * **citirea dintr-un fișier** - înseamnă copierea unui bloc de date într-un buffer; după ce se realizează citirea se actualizează cursorul de fișier (( ''fread'' (ISO C), ''read'' (POSIX), ''ReadFile'' (Win32 API) )). ( [[#scrierea si citirea|Linux]], [[#citirea si scrierea|Windows]] ) | + | | **Deschiderea/crearea unui fișier** - înseamnă asocierea unui descriptor de fișier sau a unui handle cu un fișier identificat prin numele său. | ''fopen'' | [[#open|open]] | [[#createfile|CreateFile]] | |
- | * **scrierea într-un fișier** - înseamnă copierea unui bloc de date dintr-un buffer în fișier; efectuarea scrierii înseamnă și actualizarea cursorului de fișier (( ''fwrite'' (ISO C), ''write'' (POSIX), ''WriteFile'' (Win32 API) )). ( [[#scrierea si citirea|Linux]], [[#citirea si scrierea|Windows]] ) | + | | **Închiderea unui fișier** - înseamnă eliberarea structurilor de fișier asociate procesului și a descriptorului (handle-ului) acelui fișier - doar dacă nu mai există nici o intrare în tabela file descriptorilor care să puncteze spre acea structură. | ''fclose'' | [[#close|close]] | [[#closehandle|CloseHandle]] | |
- | * **poziționarea într-un fișier** - înseamnă schimbarea valorii cursorului de fișier; citirile sau scrierile ulterioare vor porni din locul indicat de acest cursor de fișier ((''fseek'' (ISO C), ''lseek'' (POSIX), ''SetFilePointer'' (Win32 API) )). ( [[#pozitionarea in fisier lseek|Linux]], [[#pozitionarea in fisier|Windows]] ) | + | | **Citirea dintr-un fișier** - înseamnă copierea unui bloc de date într-un buffer; după ce se realizează citirea, se actualizează cursorul de fișier. | ''fread'' | [[#read|read]] | [[#readfile|ReadFile]] | |
- | * **schimbarea atributelor unui fișier** - înseamnă stabilirea unor parametri pentru fișier (( ''fcntl'' (POSIX), SetFileAttributes (Win32 API) )). ( [[#operatii speciale|Linux]]) | + | | **Scrierea într-un fișier** - înseamnă copierea unui bloc de date dintr-un buffer în fișier; efectuarea scrierii înseamnă și actualizarea cursorului de fișier. | ''fwrite'' | [[#write|write]] | [[#writefile|WriteFile]] | |
+ | | **Poziționarea într-un fișier** - înseamnă schimbarea valorii cursorului de fișier; citirile sau scrierile ulterioare vor porni din locul indicat de acest cursor de fișier. | ''fseek'' | [[#pozitionarea in fisier lseek|lseek]] | [[#pozitionarea in fisier|SetFilePointer]] | | ||
+ | | **Schimbarea atributelor unui fișier** - înseamnă stabilirea unor parametri pentru fișier. | - | [[#operatii speciale|fcntl]] | [[https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesa|SetFileAttributes]] | | ||
+ | | **Trunchierea fișierelor** - înseamnă modificarea dimensiunii unui fișier. | - | [[#trunchierea_fisierelor|ftruncate]] | [[#trunchierea_fisierelor1|SetEndOfFile]] | | ||
+ | | **Redirectarea** - înseamnă modificarea unui descriptor de fișier al unui proces (de obicei intrarea, ieșirea sau eroarea standard) către alt descriptor de fișier, de obicei cu scopul de a opera cu un fișier in același mod cu care operam cu intrarea, ieșirea sau eroarea standard. | - | [[#redirectari|dup]], [[#redirectari|dup2]] | Modificarea structurii [[https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa?redirectedfrom=MSDN | StartupInfo]] dată ca argument pentru [[https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa?redirectedfrom=MSDN|CreateProcess]] | | ||
===== Operații pe fișiere în Linux ===== | ===== Operații pe fișiere în Linux ===== | ||
Line 57: | Line 59: | ||
<code c> | <code c> | ||
- | int open(const char *pathname, int flag); /* deschidere */ | + | int open(const char *pathname, int flags); /* deschidere */ |
int open(const char *pathname, int flags, mode_t mode); /* creare */ | int open(const char *pathname, int flags, mode_t mode); /* creare */ | ||
</code> | </code> | ||
Line 139: | Line 141: | ||
</code> | </code> | ||
- | Funcția [[http://linux.die.net/man/2/read|read]] întoarce numărul de octeți efectiv citiți, cel mult ''count''. Valoarea minimă este de ''1'' octet, iar când se ajunge la sfârșitul de fișier se va întoarce ''0''. | + | Funcția [[http://linux.die.net/man/2/read|read]] întoarce numărul de octeți efectiv citiți, **cel mult** ''count''. Valoarea minimă este de ''1'' octet, iar când se ajunge la sfârșitul de fișier se va întoarce ''0''. |
=== write === | === write === | ||
Line 149: | Line 151: | ||
</code> | </code> | ||
- | Valoarea întoarsă este numărul de octeți ce au fost efectiv scriși, cel mult ''count''. În mod implicit nu se garantează că la revenirea din [[http://linux.die.net/man/2/write|write]] scrierea în fișier s-a terminat. Pentru a forța actualizarea se poate folosi [[http://linux.die.net/man/2/fsync|fsync]] sau fișierul se poate deschide folosind flagul ''O_FSYNC'', caz în care se garantează că după fiecare write fișierul a fost actualizat. | + | Valoarea întoarsă este numărul de octeți ce au fost efectiv scriși, **cel mult** ''count''. În mod implicit nu se garantează că la revenirea din [[http://linux.die.net/man/2/write|write]] scrierea în fișier s-a terminat. Pentru a forța actualizarea se poate folosi [[http://linux.die.net/man/2/fsync|fsync]] sau fișierul se poate deschide folosind flagul ''O_FSYNC'', caz în care se garantează că după fiecare write fișierul a fost actualizat. |
**Observație 1**: | **Observație 1**: | ||
Line 190: | Line 192: | ||
</code> | </code> | ||
- | În cazul [[http://linux.die.net/man/2/ftruncate|ftruncate]], parametrul ''fd'' este file descriptorul obținut cu un apel open, care a asigurat drept de scriere. În cazul [[http://linux.die.net/man/2/ftruncate|truncate]], fișierul reprezentat prin ''path'' trebuie să aibe drept de scriere. | + | În cazul [[http://linux.die.net/man/2/ftruncate|ftruncate]], parametrul ''fd'' este file descriptorul obținut cu un apel open, care a asigurat drept de scriere. În cazul [[http://linux.die.net/man/2/ftruncate|truncate]], fișierul reprezentat prin ''path'' trebuie să aibă drept de scriere. |
==== Exemplu utilizare operații I/O === | ==== Exemplu utilizare operații I/O === | ||
Line 663: | Line 665: | ||
</spoiler> | </spoiler> | ||
===== Exerciții ===== | ===== Exerciții ===== | ||
+ | <note important> | ||
+ | În cadrul laboratoarelor vom folosi repository-ul de git al materiei SO - https://github.com/systems-cs-pub-ro/so. Va trebui sa clonați repository-ul pe masinile virtuale folosind comanda: ''git clone https://github.com/systems-cs-pub-ro/so''. Dacă doriți să descărcați repositoryul în altă locație, folosiți comanda ''git clone https://github.com/systems-cs-pub-ro/so ${target}''. | ||
- | În rezolvarea laboratorului folosiți arhiva de sarcini [[http://elf.cs.pub.ro/so/res/laboratoare/lab02-tasks.zip | lab02-tasks.zip]]. | + | Pentru a actualiza repository-ul, folosiți comanda ''git pull origin master'' din interiorul directorului în care se află repository-ul. Recomandarea este să îl actualizați cât mai frecvent, înainte să începeți lucrul, pentru a vă asigura că aveți versiunea cea mai recentă. În cazul în care gitul detectează conflicte la nivelul vreunui fişier, folosiți următoarele comenzi pentru a vă păstra modificările: |
+ | <code> | ||
+ | git stash | ||
+ | git pull origin master | ||
+ | git stash pop | ||
+ | </code> | ||
+ | |||
+ | Pentru mai multe informații despre folosirea utilitarului git, urmați ghidul de la https://gitimmersion.com. | ||
+ | </note> | ||
**Observații**: Pentru a vă ajuta la implementarea exercițiilor din laborator, în directorul ''utils'' din arhivă există un fișier ''utils.h'' cu funcții utile. | **Observații**: Pentru a vă ajuta la implementarea exercițiilor din laborator, în directorul ''utils'' din arhivă există un fișier ''utils.h'' cu funcții utile. | ||
Line 673: | Line 685: | ||
</note> | </note> | ||
- | ==== Exercițiul -1 - GSOC ==== | + | ==== Exercițiul 0 - Stagii pe bune ==== |
- | Google Summer of Code este un program de vară în care studenții | + | [[https://stagiipebune.ro/students/jobs/|Stagii pe bune]] este o platformă de internshipuri care vrea să ușureze și să uniformizeze procesul prin care puteți aplica la companii din România (București, Iași, Cluj și Timișoara). Facultatea de Automatică și Calculatoare are un parteneriat cu Stagii pe bune și vă încurajăm să le folosiți platforma pentru a aplica la internshipuri! |
- | (indiferent de anul de studiu) sunt implicați în proiecte Open Source | + | |
- | pentru a își dezvolta skill-urile de programare, fiind răsplătiți cu o | + | |
- | bursă a cărei valoare [[https://developers.google.com/open-source/gsoc/help/student-stipends|depinde de țară]] | + | |
- | ([[https://developers.google.com/open-source/gsoc|pagină principală GSOC]]). | + | |
- | + | ||
- | UPB se află în top ca număr de studenți acceptați; în fiecare an fiind | + | |
- | undeva la aprox. 30-40 de studenți acceptați. | + | |
- | Vă încurajăm să aplicați! Există și un grup de fb cu foști | + | |
- | participanți unde puteti să îi contactați pentru sfaturi | + | |
- | [[https://www.facebook.com/groups/240794072931431/|facebook page]] | + | |
- | + | ||
- | ==== Exercițiul 0 - Joc interactiv ==== | + | |
- | * Detalii desfășurare [[http://ocw.cs.pub.ro/courses/so/meta/notare#joc_interactiv|joc]]. | + | Stagii pe bune organizează și evenimente de prezentare a celor mai mari companii din România. Pentru a fi la curent cu acestea, urmăriți și anunțurile postate de Stagii pe bune pe [[https://www.facebook.com/stagiipebune|Facebook]]. |
===== Linux ===== | ===== Linux ===== | ||
Line 768: | Line 768: | ||
Deschideți folderul ''win'' din arhiva laboratorului 2 și intrați în proiectul ''1-cat'', iar apoi urmăriți sursa ''cat.c'' | Deschideți folderul ''win'' din arhiva laboratorului 2 și intrați în proiectul ''1-cat'', iar apoi urmăriți sursa ''cat.c'' | ||
- | Compilați și testați executabilul ''cat.exe'' folosind command prompt-ul de Visual Studio: Tools -> Visual Studio Command Prompt | + | Compilați și testați executabilul ''cat.exe'' folosind command prompt-ul de Visual Studio: Tools -> Visual Studio Command Prompt, sau folosind Makefile-ul. |
+ | |||
+ | <note> | ||
+ | Observați că cei ''bytesRead'' octeți prin apelul ''ReadFile'' sunt scriși la ''stdout'' **intr-o buclă**, deoarece nu avem garanția că ''WriteFile'' va scrie întotdeauna atâția octeți cât îi specificăm prin al treilea parametru (''dwBytesToWrite''). | ||
+ | |||
+ | Folosiți această tehnică și la exercițiile următoare! | ||
+ | </note> | ||
==== Exercițiul 2 - CRC ==== | ==== Exercițiul 2 - CRC ==== | ||
Line 784: | Line 791: | ||
Revedeți secțiunile [[#crearea deschiderea si inchiderea|Crearea, deschiderea și închiderea fișierelor]], cât și [[#citirea si scrierea|Citirea și scrierea fișierelor]]. | Revedeți secțiunile [[#crearea deschiderea si inchiderea|Crearea, deschiderea și închiderea fișierelor]], cât și [[#citirea si scrierea|Citirea și scrierea fișierelor]]. | ||
- | Urmăriți comentariile cu ''TODO 1''. | + | Urmăriți comentariile cu ''TODO 1''. Pentru testare folosiți-vă de fișierele din directorul ''tests''. Pentru a compara două fișiere, puteți folosi utilitarul ''comp'' astfel: |
+ | <code> | ||
+ | PS C:...> .\crc.exe -g tests\test_in\test1.in crc1.out | ||
+ | PS C:...> comp.exe crc1.out tests\test_out\test1.out | ||
+ | </code> | ||
=== 2b. Comparare === | === 2b. Comparare === | ||
Line 794: | Line 805: | ||
* Folosiți doar funcția ''[[http://msdn.microsoft.com/en-us/library/aa365541%28VS.85%29.aspx|SetFilePointer]]'' | * Folosiți doar funcția ''[[http://msdn.microsoft.com/en-us/library/aa365541%28VS.85%29.aspx|SetFilePointer]]'' | ||
- | Dacă dimensiunile sunt egale, comparați cele 2 fișiere bucată cu bucată. Deși în acest caz particular fișierele de comparat conțin doar câte un CRC de 4 octeți, funcția trebuie să trateze și cazul în care fișierele sunt mai mari. Nu citiți tot fișierul în memorie, ci câte ''CHUNKSIZE = 32'' bytes o dată. Urmăriți comentariile marcate cu ''TODO 3''. | + | Dacă dimensiunile sunt egale, comparați cele 2 fișiere bucată cu bucată. Funcția trebuie să compare corect cele două fișiere, indiferent de dimensiunea acestora. Nu citiți tot fișierul în memorie, ci câte ''CHUNKSIZE = 32'' bytes o dată. Pentru aceasta, va trebui să implementați funcția ''ReadChunk'', urmand indicațiile de la ''TODO 3''. Apoi, urmăriți comentariile marcate cu ''TODO 4''. |
+ | |||
+ | <note important> | ||
+ | Pentru a putea compara un fișier cu el însuși, va trebui ca în cadrul funcției ''CompareFiles'' să deschideți ambele fișiere folosind ''FILE_SHARE_READ''. | ||
+ | </note> | ||
==== BONUS - Linux ==== | ==== BONUS - Linux ==== | ||
Line 820: | Line 835: | ||
Utilitar echivalent cu ''ls -a -R''. | Utilitar echivalent cu ''ls -a -R''. | ||
- | == Creare utilitar ls == | + | === Creare utilitar ls === |
- | Deschideți din arhiva laboratorului 2 proiectul ''3-ls''. Completați fișierul ''ls.c'' pentru ca programul ''3-ls.exe'' să se comporte ca utilitarul ''ls''. | + | Deschideți din arhiva laboratorului 2 proiectul ''3-ls''. Completați fișierul ''ls.c'' pentru ca programul ''ls.exe'' să se comporte ca utilitarul ''ls''. |
Afișarea fișierelor dintr-un director se face în doi pași: | Afișarea fișierelor dintr-un director se face în doi pași: | ||
Line 828: | Line 843: | ||
* se iterează această listă folosind funcția: [[http://msdn.microsoft.com/en-us/library/aa364428%28VS.85%29.aspx|FindNextFile]] | * se iterează această listă folosind funcția: [[http://msdn.microsoft.com/en-us/library/aa364428%28VS.85%29.aspx|FindNextFile]] | ||
- | Pentru rezolvare, urmăriți comentariile marcate cu ''TODO 1''. | + | Pentru rezolvare, urmăriți comentariile marcate cu ''TODO 1''. Ca să afișați detaliile cu o spațiere consecventă, folosiți funcția ''PrintPadding'' definită în schelet, iar pentru testare, folosiți dintr-un prompt Visual Studio: <code bash>ls.exe ..</code> |
- | Pentru testare folosiți dintr-un prompt Visual Studio: <code bash>ls.exe ..</code> | + | |
== Afișare detalii pentru parametrul -a == | == Afișare detalii pentru parametrul -a == | ||
Line 837: | Line 851: | ||
Atributele unui fișier sunt definite într-o structură de forma: [[http://msdn.microsoft.com/en-us/library/aa365740%28VS.85%29.aspx|WIN32_FIND_DATA]]. Pentru a verifica dacă un fișier e director, trebuie să aibă bitul "FILE_ATTRIBUTE_DIRECTORY" din câmpul "dwFileAttributes" ( vezi [[http://msdn.microsoft.com/en-us/library/ee332330%28v=VS.85%29.aspx|File Attributes]]). | Atributele unui fișier sunt definite într-o structură de forma: [[http://msdn.microsoft.com/en-us/library/aa365740%28VS.85%29.aspx|WIN32_FIND_DATA]]. Pentru a verifica dacă un fișier e director, trebuie să aibă bitul "FILE_ATTRIBUTE_DIRECTORY" din câmpul "dwFileAttributes" ( vezi [[http://msdn.microsoft.com/en-us/library/ee332330%28v=VS.85%29.aspx|File Attributes]]). | ||
- | * Urmăriți comentariile marcate cu ''TODO 2'' | + | * Urmăriți comentariile marcate cu ''TODO 2''. |
+ | * Pentru a afișa detaliile cu o spațiere consecventă, folosiți funcția ''PrintPadding'' definită în schelet. | ||
== Afișare detalii pentru parametrul -R == | == Afișare detalii pentru parametrul -R == | ||
Line 845: | Line 860: | ||
Pentru rezolvare, urmăriți comentariile marcate cu ''TODO 3''. Aveți grijă să concatenați numele noului director la calea deja existentă. | Pentru rezolvare, urmăriți comentariile marcate cu ''TODO 3''. Aveți grijă să concatenați numele noului director la calea deja existentă. | ||
- | == Troubleshooting == | + | === Troubleshooting === |
Deschideți din arhiva laboratorului 2 proiectul ''4-trouble''. Programul ar trebui să creeze un fișier cu mesajul "Testing 123". | Deschideți din arhiva laboratorului 2 proiectul ''4-trouble''. Programul ar trebui să creeze un fișier cu mesajul "Testing 123". | ||
Line 855: | Line 870: | ||
*Operații cu fișiere în Python | *Operații cu fișiere în Python | ||
*Studiați exemplele din {{so:laboratoare:pyfileoperations.zip|arhivă}}, citiți documentația și observați diferențele între API-uri | *Studiați exemplele din {{so:laboratoare:pyfileoperations.zip|arhivă}}, citiți documentația și observați diferențele între API-uri | ||
- | |||
- | |||
- | ===== Soluții ===== | ||
- | |||
- | [[http://elf.cs.pub.ro/so/res/laboratoare/lab02-sol.zip | lab02-sol.zip]] | ||