SPEAKER: Finora, è probabile che la maggior parte dei vostri programmi sono stati un po 'effimera. Si esegue un programma come Mario o Greedy. Si fa qualcosa, viene richiesto forse all'utente alcune informazioni, stampare alcune output sullo schermo, ma poi quando il programma è finito, non c'è davvero nessuna prova lì è stato mai eseguito in primo luogo. Voglio dire, certo, si potrebbe avere lasciato si apre nella finestra del terminale, ma se si cancella lo schermo, c'è davvero nessuna prova che esistesse. Non abbiamo un mezzo di memorizzazione informazioni persistente, informazioni che esiste dopo la nostra programma ha smesso di correre, o non abbiamo fino a questo punto. Fortunatamente, però, c fa ci forniscono la capacità per fare questo mediante l'attuazione di qualcosa chiamato un file, una struttura che fondamentalmente rappresenta un file che si desidera raddoppiare clicca sul vostro computer, se siete utilizzato per un ambiente grafico. Generalmente quando si lavora con c, siamo in realtà andando a lavorare con puntatori a files-- lima stars-- tranne per un po ' quando si parla di una coppia delle funzioni che lavorare con i puntatori di file. Non è necessario avere davvero scavato troppo in profondità per la comprensione dei puntatori loro stessi. C'è un po 'teeny dove parleremo di loro, ma in genere di file e puntatori puntatori, mentre interconnessi, non sono esattamente la stessa cosa. Ora che cosa voglio dire quando Dico dati persistenti? Cosa sono i dati persistenti? Perché ci preoccupiamo a questo proposito? Diciamo, per esempio, che si sta eseguendo un programma o hai riscritto un programma che è un gioco, e si desidera tenere traccia di tutte le mosse dell'utente in modo che forse se qualcosa va storto, è possibile esaminare il file dopo la partita. Questo è ciò che intendiamo quando parlare di dati persistenti. Nel corso di esecuzione il il programma, viene creato un file. E quando il programma ha smesso di correre, che file esiste ancora nel sistema. E possiamo guardare ed esaminarlo. E così che il programma sarà impostato hanno creato alcuni dati persistenti, Esistono dati dopo il programma ha terminato l'esecuzione. Ora tutte queste funzioni che funzionano con la creazione di file e la manipolazione in vari modi vivere in io.h norma, che è un file di intestazione che probabilmente hai stato libbra compreso in cima piuttosto gran parte tutti i programmi perché contiene uno dei la maggior parte delle funzioni utili per noi, printf, che lascia anche vive in io.h. norma Quindi non c'è bisogno di battere includere eventuali file aggiuntivi probabilmente per lavorare con i puntatori di file. Ora ogni singola funzione puntatore a file, o O, uscita di ogni singolo file di I / ingresso funzione accetta come uno dei suoi parametri o ingressi un pointer-- file se non per uno, fopen, che è quello che si utilizza per accedere al file puntatore in primo luogo. Ma dopo aver aperto il archiviare e si ottiene puntatori a file, si può quindi passare come argomenti alle varie funzioni stiamo andando a parlare oggi, così come molti altri in modo da poter lavorare con i file. Quindi ci sono sei abbastanza quelli di base comuni che stiamo andando a parlare oggi. fopen e la sua compagna la funzione fclose, fgetc e la sua funzione compagna fputc, e fread e la sua funzione compagna, fwrite. Quindi cerchiamo di ottenere a destra in esso. fopen-- che cosa fa? Beh, si apre un file e ti dà un puntatore a file ad esso, in modo da poter poi utilizzare tale presentare puntatore come argomento qualsiasi funzioni di I / O l'altro file. La cosa più importante da ricordare con fopen è che dopo aver aperto il file o fatto una chiamata come quella qui, è necessario controllare per essere sicuri che il puntatore che avete ottenuto indietro non è uguale a null. Se non avete visto il video su puntatori, questo potrebbe non avere senso. Ma se si cerca di risolvere il riferimento un richiamo puntatore nullo, il programma verrà probabilmente soffrirà una segmentazione [incomprensibile]. Vogliamo fare in modo che ha ottenuto un puntatore indietro legittima. La stragrande maggioranza del tempo ci sarà hanno ottenuto un puntatore legittima indietro e non sarà un problema. Quindi, come possiamo fare una chiamata a fopen? Sembra molto simile a questo. Stella File ptr-- PTR essendo un generico nome per il file pointer-- fopen e passiamo in due cose, un nome di file e un'operazione vogliamo intraprendere. Così potremmo avere una chiamata che assomiglia questo-- ptr file di stella 1 è uguale a fopen file1.txt. E l'operazione che ho scelto è r. Allora, cosa ne pensi r è qui? Quali sono i tipi di cose che abbiamo potrebbe essere in grado di fare per i file? Così r è l'operazione che abbiamo scegliere quando si vuole leggere un file. Quindi ci sarebbe fondamentalmente quando facciamo una chiamata come questo essere sempre noi stessi un puntatore a file in modo tale che si potrebbe quindi leggere informazioni da file1.txt. Allo stesso modo, abbiamo potuto aprire il file 2.txt per la scrittura e quindi possiamo passare ptr2, il puntatore del file che ho creato qui, come argomento a qualsiasi funzione che scrive le informazioni in un file. E simile alla scrittura, c'è anche la possibilità di aggiungere, a. La differenza tra scrittura e aggiungendo è che quando si scrive in un file, se si effettua una chiamata di fopen per la scrittura e tale file esiste già, è andando a sovrascrivere l'intero file. Sta per iniziare proprio all'inizio, eliminando tutte le informazioni che è già lì. Mentre se lo si apre per l'aggiunta, andrà alla fine del file se c'è già testo o le informazioni in esso, e sarà quindi avviare la scrittura da lì. In modo da non perdere nessuna delle informazioni che hai fatto prima. Se si desidera scrivere o aggiungere sorta di dipende dalla situazione. Ma probabilmente conoscerete ciò che il operazione destra è quando sarà il momento. Ecco, questo è fopen. Che dire fclose? Beh, abbastanza semplicemente, fclose solo accetta il puntatore del file. E come ci si potrebbe aspettare, si chiude il file. E una volta che abbiamo chiuso un file, non possiamo eseguire qualsiasi altro file di funzioni di I / O, lettura o la scrittura, su quel file. Dobbiamo riaprire il file di un altro tempo, al fine continuare a lavorare con utilizzando le funzioni di I / O. Mezzi così fclose abbiamo finito lavorare con questo file. E tutti abbiamo bisogno di passare in è il nome di un puntatore file. Così in un paio scorre fa, abbiamo fopened file di testo 1 punto per la lettura e abbiamo assegnato che il file puntatore ptr1. Ora abbiamo deciso che siamo fatto leggere da quel file. Non abbiamo bisogno di fare di più con esso. Possiamo ptr1 appena fclose. E allo stesso modo, potremmo fclose gli altri. Tutto ok. Ecco, questo è l'apertura e la chiusura. Questi sono i due di base le operazioni di partenza. Ora vogliamo realmente fare alcune cose interessanti, e la prima funzione che faremo vedere che farà questo è fgetc-- presentare ottenere un carattere. Questo è ciò che generalmente fgetc si tradurrebbe a. Il suo obiettivo nella vita è quello leggere il carattere successivo, o se questo è il vostro molto prima chiamata a fgetc per un file particolare, il primo carattere. Ma poi, dopo che, si ottiene il prossimo, il carattere molto prossimo di quel file, e lo memorizza in una variabile di carattere. Come abbiamo fatto qui, char ch uguale a fgetc, passare il nome di un puntatore file. Anche in questo caso, è molto importante da ricordare che per avere l'operazione riesce, il puntatore del file stesso deve aver aperto in scrittura. Non possiamo leggere un carattere da un file puntatore che abbiamo aperto per la scrittura. Ecco, questo è uno dei limitazioni di fopen, giusto? Dobbiamo limitare a noi stessi di eseguire solo una operazione con un puntatore al file. Se volessimo leggere e scrivere dallo stesso file, avremmo aperto due distinti puntatori file nella stessa file-- uno per la lettura, uno per la scrittura. Così ancora una volta, l'unica ragione Io porto che ora è perché se stiamo andando a fare una chiamata a fgetc, che puntatore al file deve aver aperto in scrittura. E poi abbastanza semplicemente, tutto quello che dobbiamo fare è passare nel nome del puntatore del file. Così ch char uguale ptr1 fgetc. Che sta per ottenere noi il prossimo character-- o ancora, se questa è la prima tempo abbiamo fatto questo appello, la prima character-- di qualsiasi file viene puntato da ptr1. Ricordiamo che quello era il file di testo 1 punto. Si otterrà il primo carattere di quella e noi memorizziamo nella variabile ch. Abbastanza semplice. Così abbiamo guardato solo alle tre funzioni e già siamo può fare qualcosa abbastanza carino. Quindi, se prendiamo questa capacità di ottenere un carattere e noi ciclo it-- quindi abbiamo continuare a ottenere caratteri da un file più e sopra e over-- ora siamo in grado di leggere ogni singola carattere di un file. E se stampiamo ogni personaggio subito dopo la leggiamo, ora abbiamo letto da un file e stampato il suo contenuto sullo schermo. Abbiamo effettivamente concatenati il file sullo schermo. Ed è quello che il Comando di Linux gatto fa. Se si digita gatto nel nome del file che, stamperà l'intero contenuto del file nella finestra del terminale. E così questo piccolo ciclo qui, solo tre linee di codice, ma duplica in modo efficace il comando cat Linux. Quindi questa sintassi potrebbe guardare un po 'strano, ma ecco cosa sta succedendo qui. Mentre ch uguale a fgetc, ptr non è pari a EOF-- è un intero boccone, ma cerchiamo di scomposizione solo quindi è chiaro sulla sintassi. Ho consolidati, essa per motivi di spazio, anche se è un po ' sintatticamente difficile. Quindi questa parte a destra verde Ora, che cosa sta facendo? Beh, questo è solo il nostro appello fgetc, giusto? Abbiamo visto che prima. E 'ottenere uno carattere dal file. Poi si confronta che carattere contro EOF. EOF è un valore speciale che è definito io.h standard, che è la fine del carattere file. Quindi, in pratica quello che sta per succedere è questo ciclo sarà letto un carattere, confrontarlo EOF, la carattere di fine file. Se non corrispondono, quindi non ci siamo raggiunta la fine del file, noi lo stamperemo quel personaggio fuori. Poi torneremo al all'inizio del ciclo di nuovo. Avremo un personaggio, controlliamo contro EOF, stamparlo, e così via e così via e così via, scorrendo in modo che fino a quando abbiamo raggiunto la fine del file. E poi da quel punto, avremo stampato l'intero contenuto del file. Così ancora una volta, abbiamo visto solo fopen, fclose, e fgetc e già possiamo duplicare un comando da terminale Linux. Come ho detto all'inizio, abbiamo avuto fgetc e fputc, e fputc era la compagna funzione fgetc. E così, come si potrebbe immaginare, è l'equivalente di scrittura. Esso ci permette di scrivere un singolo carattere in un file. Anche in questo caso, l'avvertenza di essere, semplicemente come è stato con fgetc, il file che stiamo scrivendo a Dev'essere stato aperto per la scrittura o per l'aggiunta. Se cerchiamo e usiamo fputc su un file che abbiamo aperto per la lettura, stiamo andando a soffrire un po 'di un errore. Ma la chiamata è piuttosto semplice. capitale fputc Un ptr2, tutto che sta per fare è che è intenzione di scrivere la lettera in A in file di 2 punti testo, che era il nome del file abbiamo aperto e assegnato il puntatore ptr2. Così stiamo andando a dare una A maiuscola in un file di testo 2 punti. E noi scriveremo un'esclamazione puntare al file 3 punti il testo, che è stato puntato da ptr3. Quindi, di nuovo, abbastanza semplice qui. Ma ora siamo in grado di fare un'altra cosa. Abbiamo questo esempio siamo stati solo andando oltre di essere in grado di replicare il gatto Comando di Linux, quello che stampa allo schermo. Bene, ora che abbiamo la capacità a leggere i caratteri da file e scrivere i caratteri di file, perché non solo che sostituiamo chiamare a printf con una chiamata a fputc. E ora abbiamo duplicato cp, un comando molto semplice Linux che abbiamo parlato di cammino lungo fa nel comandi Linux video. ABBIAMO efficacemente duplicato che proprio qui. Stiamo leggendo una lettera e poi siamo scrivendo che personaggio a un altro file. La lettura da un file, la scrittura ad un altro, più e più e più volte fino a quando ci ha colpito EOF. Dobbiamo alla fine del il file che stiamo cercando di copiare. E con questo avremo smorfie dei personaggi abbiamo bisogno di file che stiamo scrivendo a. Quindi questo è cp, il comando di copia di Linux. All'inizio di questo video, ho avuto l'avvertenza che avremmo parlato di un po 'di puntatori. Qui è in particolare dove siamo andando a parlare di puntatori oltre al file puntatori. Quindi, questa funzione sembra un po 'spaventoso. E 'ottenuto diversi parametri. Ci sono un sacco di cose qui. C'è un sacco di diverso colori e testi. Ma in realtà, è solo il versione generica di fgetc che ci permette di ottenere qualsiasi quantità di informazioni. Può essere un po 'inefficiente se siamo ottenendo caratteri uno alla volta, scorrendo il file un carattere alla volta. Non sarebbe bello per ottenere 100 alla volta o 500 alla volta? Beh, fread e la sua funzione compagna fwrite, che parleremo in un secondo, ci permettono di fare proprio questo. Possiamo leggere una quantità arbitraria di informazioni da un file e immagazziniamo da qualche parte temporaneamente. Invece di essere in grado di solo inserirla in una singola variabile, potremmo aver bisogno di conservarlo in un array. E così, passiamo in quattro argomenti per fread-- un puntatore alla posizione in cui siamo andando a memorizzare le informazioni, quanto grande ogni unità di informazioni sarà il numero di unità di informazioni vogliamo acquisire, e da quale file vogliamo ottenere loro. Probabilmente meglio illustrato con un esempio qui. Quindi diciamo che dichiariamo un array di 10 interi. Abbiamo appena dichiarato sul impilare arbitrariamente int arr 10. Ecco, questo è abbastanza semplice. Ora quello che stiamo facendo è però il frecall viene stiamo leggendo dimensioni di int volte 10 byte di informazioni. Dimensioni di int essere four-- che è le dimensioni di un intero c. Quindi quello che stiamo facendo è che stiamo leggendo 40 byte valore delle informazioni dal file puntato da ptr. E stiamo memorizzare quelle 40 byte da qualche parte dove abbiamo messo da parte 40 byte per un valore di memoria. Per fortuna, abbiamo già fatto che, dichiarando arr, tale matrice proprio lì. Che è capace di partecipazione 10 unità a quattro byte. Quindi, in totale, che può contenere 40 byte di valore di dati. Ed ora stiamo leggendo 40 byte delle informazioni dal file, e stiamo riporlo in arr. Ricordiamo dal video su puntatori che il nome di una matrice, come arr, è in realtà solo un puntatore al suo primo elemento. Così, quando si passa in arr lì, abbiamo sono, infatti, passando in un puntatore. Allo stesso modo possiamo fare questo-- non lo facciamo necessariamente necessità di salvare il nostro buffer sullo stack. Potremmo anche allocare dinamicamente un tampone come questa, usando malloc. Ricordate, quando si allocare dinamicamente la memoria, stiamo risparmiando sul mucchio, non lo stack. Ma è ancora un buffer. E ancora, in questo caso, è tenendo 640 byte di informazioni perché un doppio occupa otto byte. E stiamo chiedendo per 80 di loro. Vogliamo avere spazio per contenere 80 camere doppie. Così 80 volte 8 sono informazioni 640 byte. E che è chiamata a fread raccogliere 640 byte di informazioni dal file puntato da ptr e riporlo ora in arr2. Ora possiamo anche trattare fread proprio come una chiamata a fgetc. In questo caso, stiamo solo cercando di ottenere un carattere dal file. E non abbiamo bisogno di un array per contenere un carattere. Possiamo solo conservarla in una variabile di carattere. La cattura, però, è che quando non ci resta che una variabile, occorre passare in indirizzo di quella variabile perché ricordo che il primo argomento a fread è un puntatore alla posizione e alla memoria dove vogliamo memorizzare le informazioni. Anche in questo caso, il nome di un array è un puntatore. Quindi non abbiamo bisogno di fare di matrice commerciale. Ma c, il carattere c qui, non è un array. E 'solo una variabile. E così abbiamo bisogno di passare un commerciale c per indicare che questo è l'indirizzo dove si vuole memorizzare questa un byte di informazioni, questo personaggio che stiamo raccogliendo da ptr. Fwrite-- Andrò attraverso questo un po 'di più quickly-- è praticamente la esatto equivalente di fread tranne che è per la scrittura invece di leggere, appena come il other-- abbiamo avuto aperta e vicino, ottenere un carattere, scrivere un personaggio. Ora è ottenere arbitrario quantità di informazioni, giusta quantità arbitraria di dati. Quindi, proprio come prima, possiamo avere un array di 10 interi dove abbiamo già informazioni memorizzate, forse. E 'stato probabilmente alcune righe di codice che dovrebbe andare tra questi due dove riempio con arr qualcosa di significativo. Lo riempio con 10 diversi numeri interi. E invece, quello che sto facendo sta scrivendo da arr e la raccolta delle informazioni da arr. E sto prendendo questa informazione e metterlo nel file. Così, invece di essere da il file al buffer, ora stiamo passando da il buffer al file. Quindi è proprio il contrario. Quindi, di nuovo, come prima, possiamo hanno anche un pezzo di memoria heap che abbiamo dinamicamente assegnato e leggere da quella e scrivere che il file. E abbiamo anche una singola variabile in grado di contenere un byte di informazioni, come un carattere. Ma ancora una volta, abbiamo bisogno di passare a l'indirizzo di quella variabile quando vogliamo leggere da esso. Quindi possiamo scrivere le informazioni troviamo a quell'indirizzo per il puntatore del file, ptr. C'è un sacco di altri grande di file funzioni di I / O che fanno varie cose oltre quelli di cui abbiamo parlato oggi. Un paio di quelli potreste trovare utile sono fgets e fputs, che sono l'equivalente di fgetc e fputc ma per la lettura una singola stringa da un file. Invece di un singolo carattere, si leggerà un'intera stringa. fprintf, che permette in sostanza di utilizzare printf per scrivere sul file. Così come si può fare il sostituzione di variabile utilizzando il segnaposto per cento ie d cento, e così via, con printf Analogamente, è possibile prendere il stringa printf e stampare qualcosa come quella di un file. fseek-- se si dispone di un lettore DVD è l'analogia io di solito uso qui-- è un po 'come usare il riavvolgimento e avanzamento veloce per spostare intorno al film. Allo stesso modo, è possibile scorrere la lima. Una delle cose dentro che struttura dei file che c crea per voi è un indicatore di dove siete nel file. Sei al più inizio, a zero byte? Sei al byte 100, 1.000 byte, e così via? È possibile utilizzare fseek per spostare arbitrariamente che l'indicatore in avanti o indietro. E ftell, di nuovo simile ad un lettore DVD, è come un piccolo orologio che racconta voi quanti minuti e secondi sono in un particolare film. Allo stesso modo, come dice ftell molti byte che sono nel file. feof è una versione diversa di rilevare se hai raggiunta la fine del file. E ferror è una funzione che è possibile utilizzare per rilevare se qualcosa deve andato storto lavoro con un file. Ancora una volta, questo è solo graffiare la superficie. C'è ancora molto di più file di I / O funzioni nel io.h. norma Ma questo probabilmente porterà ha iniziato a lavorare con i puntatori di file. Sono Doug Lloyd. Questo è CS50.