COLUNA: Até o momento, é provável que a maioria dos seus programas ter sido um pouco efémera. Você executar um programa como Mario ou ávido. Ele faz algo, talvez solicitará o usuário para algumas informações, imprimir alguma saída para a tela, mas, em seguida, quando o programa acabou, não há realmente nenhuma evidência lá ele nunca foi executado em primeiro lugar. Quero dizer, claro, que você pode ter deixado ele abrir na janela do terminal, mas se você limpar sua tela, não há realmente nenhuma evidência de que ele existia. Nós não temos um meio de armazenamento informações persistente, informações que existe após o nosso programa parou de funcionar, ou que não tem, até este ponto. Felizmente, porém, faz c fornecer-nos com a capacidade fazer isso através da implementação algo chamado um arquivo, uma estrutura que, basicamente, representa um arquivo que você dobraria clique em seu computador, se você estiver usado para um ambiente de usuário gráfica. De um modo geral quando se trabalha com c, estamos, na verdade, vai estar trabalhando com ponteiros para files-- arquivo stars-- com exceção de um pouco quando falamos de um casal de que as funções trabalhar com ponteiros de arquivo. Você não precisa ter realmente cavou muito profundo entendimento ponteiros si mesmos. Há um pouco de hippies onde iremos falar sobre eles, mas geralmente o arquivo e ponteiros ponteiros, enquanto inter-relacionados, não são exatamente a mesma coisa. Agora o que eu quero dizer quando Eu digo dados persistentes? O que são dados persistentes? Por que nos preocupamos com isso? Digamos que, por exemplo, que você está executando um programa ou que você tenha reescrito um programa que é um jogo, e você quer manter o controle de todos os movimentos do usuário de modo que talvez, se algo der errado, você pode rever o arquivo após o jogo. Isso é o que queremos dizer quando falar sobre dados persistentes. No decurso da execução de seu programa, um arquivo é criado. E quando o seu programa parou de funcionar, esse arquivo ainda existe no seu sistema. E nós podemos olhar para ele e examiná-lo. E assim que o programa seria definida como criaram alguns dados persistentes, existem dados após o programa terminar a execução. Agora todas estas funções que funcionam com a criação de arquivos e manipulação los de diversas maneiras viver em io.h padrão, que é um ficheiro de cabeçalho que você provavelmente sido libra incluindo na parte superior da consideravelmente muito todos os seus programas porque contém um dos a maioria das funções úteis para nós, printf, que também permite vive em io.h. padrão Então você não precisa bater incluem quaisquer arquivos adicionais provavelmente a fim de trabalhar com ponteiros de arquivo. Agora, cada função de ponteiro de arquivo único, ou cada arquivo I / O, de entrada e saída função, aceita como um de seus parâmetros ou insumos pointer-- um arquivo salvo por exemplo, fopen, que é o que você usa para obter o arquivo ponteiro em primeiro lugar. Mas depois que você abriu a arquivo e você começa ponteiros de arquivo, você pode, em seguida, passá-los como argumentos para as várias funções vamos falar sobre Hoje em dia, bem como muitos outros de modo que você pode trabalhar com arquivos. Portanto, há seis bonita os básicos comuns que vamos falar hoje. fopen e seu companheiro função fclose, fgetc e sua função fputc companheiro, e fread e sua função companheiro, fwrite. Então vamos direto ao assunto. fopen-- o que ele faz? Bem, ele abre um arquivo e ele dá-lhe um ponteiro de arquivo a ele, de modo que você pode usar esse arquivo ponteiro como um argumento para qualquer uma das outras funções de E / S de arquivo. A coisa mais importante para se lembrar com fopen é que, depois de ter aberto o arquivo ou fez uma ligação como a que aqui, você precisa verificar para certificar-se que o ponteiro que você tem de volta não é igual a nulo. Se você ainda não assistiu o vídeo em ponteiros, isso pode não fazer sentido. Mas se você tentar e dereference um recall ponteiro nulo, seu programa provavelmente sofrerão uma segmentação [inaudível]. Nós queremos ter certeza de que nós tem um ponteiro de volta legítimo. A grande maioria do tempo nós vamos ter obtido um ponteiro legítimo de volta e não será um problema. Então, como vamos fazer uma chamada para fopen? Parece muito bonito como este. Estrela arquivo ptr-- ptr sendo um genérico nome para o arquivo pointer-- fopen e nós passamos em duas coisas, um nome de arquivo e uma operação que queremos empreender. Assim, poderíamos ter uma chamada que se parece com isto-- estrela arquivo ptr 1 é igual a fopen file1.txt. E a operação que eu escolhi é r. Então, o que você acha r é aqui? Quais são os tipos de coisas que pode ser capaz de fazer para arquivos? Assim, R é a operação que nós escolher quando queremos ler um arquivo. Por isso, seria, basicamente, quando fazemos uma chamada como este estar recebendo nós um ponteiro de arquivo de tal forma que nós poderia então ler informações de file1.txt. Da mesma forma, poderíamos abrir o arquivo 2.txt para escrever e para que possamos passar ptr2, o ponteiro do arquivo que eu criei aqui, como um argumento para qualquer função que grava informações em um arquivo. E semelhante à escrita, há também a opção de acrescentar, a. A diferença entre escrevendo e anexando sendo que quando você gravar em um arquivo, se você fizer uma chamada para fopen para a escrita e esse arquivo já existe, é vai substituir o arquivo inteiro. Vai começar no início, apagar todas as informações que já está lá. Considerando que, se você abri-lo para acrescentar, ele vai para o final do arquivo se já existe texto em ou informações nele contidas, e vai então começar escrita de lá. Então você não vai perder qualquer um dos informações que você fez antes. Se você quer escrever ou anexar tipo de depende da situação. Mas você provavelmente vai saber o que o operação certa é quando chega a hora. Então, isso é fopen. E sobre fclose? Bem, muito simplesmente, fclose apenas aceita o ponteiro do arquivo. E como você poderia esperar, ele fecha o arquivo. E uma vez que você fechou um arquivo, não podemos realizar mais qualquer arquivo de funções de E / S, lendo ou escrevendo, naquele arquivo. Temos de voltar a abrir a apresentar outra vez, a fim continuar a trabalhar com -lo usando as funções de I / O. Então meios fclose estamos a fazer trabalhar com este arquivo. E todos nós precisamos é passar em o nome de um ficheiro de ponteiro. Então, em um par desliza atrás, fopened arquivo de texto 1 ponto para a leitura e nós atribuído que arquivo ponteiro para ptr1. Agora nós decidimos que somos leitura feita a partir desse arquivo. Nós não precisam fazer mais nada com ele. Podemos ptr1 apenas fclose. E da mesma forma, poderíamos usar fclose os outros. Tudo certo. De modo que está abrindo e fechando. Esses são os dois básico operações de partida. Agora queremos realmente fazer algumas coisas interessantes, e a primeira função que vamos ver que vai fazer isso é fgetc-- arquivar obter um personagem. Isso é o que geralmente fgetc se traduziria em. Seu objetivo na vida é leia o próximo caractere, ou se esta é a sua muito primeira chamada para fgetc para um determinado arquivo, o primeiro caractere. Mas, então, depois disso, você começa a próxima, o muito próximo caractere desse arquivo, e as armazena em uma variável de caractere. Como nós fizemos aqui, caractere ch igual fgetc, passar o nome de um ficheiro de ponteiro. Novamente, é muito importante aqui para lembrar que, a fim de ter esta operação foi bem sucedida, o próprio ponteiro de arquivo devo ter foi aberto para leitura. Não podemos ler um personagem de um arquivo ponteiro que abrimos para a escrita. Então essa é uma das limitações de fopen, certo? Temos para restringir nós apenas para realizar uma operação com um ponteiro de arquivo. Se quiséssemos ler e escrever a partir do mesmo arquivo, teríamos aberto dois separados ponteiros de arquivos para o mesmo file-- uma para leitura, uma para a escrita. Então, novamente, a única razão Eu trago que até agora é porque se nós estamos indo para fazer uma chamada para fgetc, que deve ter um ponteiro de arquivo foi aberto para leitura. E, em seguida, muito simplesmente, tudo o que precisamos fazer é passar o nome do ponteiro do arquivo. Então ch carvão equivale a ptr1 fgetc. Isso vai levar-nos a próxima character-- ou ainda, se este for o primeiro vez que já se fez esta chamada, o primeiro character-- de qualquer arquivo é apontada por ptr1. Lembre-se que isso era um arquivo de texto de ponto. Ele vai ter o primeiro caractere dessa e vamos armazená-lo no ch variável. Bastante simples. Então, temos apenas olhou para três funções e já nós pode fazer algo muito arrumado. Então, se tomarmos essa capacidade de obtenção de um personagem e nós laço ele-- portanto, continuar a receber personagens a partir de um arquivo de mais e mais e agora nós over-- pode ler cada personagem de um arquivo. E se nós imprimir cada personagem imediatamente depois de lê-lo, temos agora lidos de um arquivo e seu conteúdo impresso para a tela. Temos efetivamente concatenado esse arquivo na tela. E é isso que o Comando cat Linux faz. Se você digitar gato no nome do arquivo, ele imprimirá todo o conteúdo do arquivo na janela do seu terminal. E assim este pequeno laço aqui, apenas três linhas de código, mas ele duplica efetivamente o gato de comando do Linux. Portanto, esta sintaxe pode Parece um pouco estranho, mas aqui está o que está acontecendo aqui. Enquanto ch igual fgetc, ptr não é igual a EOF-- é um bocado todo, mas vamos dividi-la apenas por isso é claro sobre a sintaxe. Eu consolidou-lo por uma questão de espaço, embora seja um pouco sintaticamente complicado. Portanto, esta parte no direito verde agora, o que ele está fazendo? Bem, isso é apenas o nosso apelo fgetc, certo? Temos visto isso antes. É obtenção de um personagem a partir do arquivo. Em seguida, comparar esse caráter contra EOF. EOF é um valor especial que é definido em io.h padrão, que é o fim do personagem de arquivo. Então, basicamente o que vai acontecer é este ciclo vai ler um personagem, comparar a EOF, o fim do personagem de arquivo. Se eles não corresponderem, por isso, não tem chegou ao fim do ficheiro, vamos imprimir esse personagem para fora. Então vamos voltar para o início do ciclo novamente. Nós vamos chegar um personagem, verifique contra EOF, imprimi-lo, e assim por diante e assim por diante e assim por diante, loop através dessa forma até que chegamos ao final do arquivo. E, em seguida, por esse ponto, vamos ter impresso para fora todo o conteúdo do ficheiro. Então, novamente, nós só vi fopen, fclose, e fgetc e já podemos duplicar um comando de terminal do Linux. Como eu disse no início, tivemos fgetc e fputc, e fputc foi o companheiro função de fgetc. E assim, como você pode imaginar, é o equivalente escrito. Ela nos permite escrever uma único caractere em um arquivo. Mais uma vez, sendo a ressalva, apenas como se fosse com fgetc, o arquivo que estamos escrevendo para deve ter sido aberto para gravação ou para acrescentar. Se tentarmos e usar fputc em um arquivo que temos aberto para leitura, vamos sofrer um pouco de um erro. Mas a chamada é bem simples. A capital de fputc ptr2, todos que vai fazer é que é vai escrever a letra em A em arquivo de 2 ponto o texto, que foi o nome do arquivo que nós aberto e atribuído o ponteiro para ptr2. Então, nós estamos indo para escrever um maiúsculo para arquivo 2 texto de ponto. E nós vamos escrever uma exclamação apontar para o arquivo 3 dot texto, que foi apontado por ptr3. Então, novamente, bastante simples aqui. Mas agora podemos fazer outra coisa. Temos este exemplo estávamos apenas passando por cima sobre a possibilidade de replicar o gato De comando do Linux, o que imprime para a tela. Bem, agora que temos a capacidade para ler caracteres de arquivos e escrever caracteres para arquivos, por que não podemos simplesmente substituir esse chamar para printf com uma chamada para fputc. E agora temos duplicado cp, um comando muito básico Linux que falamos caminho longo atrás no Linux comandos vídeo. Temos efectivamente duplicados que aqui. Estamos lendo um personagem e então nós estamos escrevendo esse personagem para outro arquivo. Leitura de um arquivo, escrita para outro, mais e mais e outra vez até chegarmos EOF. Temos até o fim do arquivar estamos tentando copiar. E por que nós vamos ter escrito tudo dos personagens que precisamos para o arquivo que nós estamos escrevendo. Portanto, este é cp, o comando de cópia do Linux. No início de Neste vídeo, eu tinha a ressalva que gostaríamos de falar um pouco sobre ponteiros. Aqui está especificamente onde estamos vai falar sobre ponteiros além de apresentar ponteiros. Portanto, esta função parece meio assustador. Ele tem vários parâmetros. Há muita coisa acontecendo aqui. Há um monte de diferente cores e textos. Mas, realmente, é apenas o versão genérica do fgetc que nos permite obter qualquer quantidade de informação. Ele pode ser um pouco ineficiente se estamos caracteres ficando uma de cada vez, iteração através do arquivo um carácter de cada vez. Não seria mais agradável para ficar 100 de cada vez 500 ou ao mesmo tempo? Bem, fread e sua função companheiro fwrite, que nós vamos falar sobre em um segundo, permitir-nos para fazer exatamente isso. Podemos ler uma quantidade arbitrária de informações de um arquivo e armazená-lo em algum lugar temporariamente. Em vez de ser capaz de apenas ajustá-lo em uma única variável, que poderá ser necessário para armazená-lo em uma matriz. E assim, passamos em quatro argumentos para fread-- um ponteiro até o local onde estamos indo para armazenar informações, quão grande cada unidade de informação será, quantas unidades de informação queremos adquirir, e de qual arquivo queremos obtê-los. Provavelmente melhor ilustrado com um exemplo aqui. Então, vamos dizer que nós declaramos um conjunto de 10 números inteiros. Acabamos declarado no empilhar arbitrariamente int arr 10. Então, isso é bastante simples. Agora, o que nós estamos fazendo, porém, é o frecall é que estamos tamanho do int lendo vezes 10 bytes de informação. Tamanho do int estar four-- que é o tamanho de um número inteiro no c. Então, o que nós estamos fazendo é que estamos lendo 40 bytes no valor de informações a partir do arquivo apontado por ptr. E nós estamos armazenando os 40 bytes em algum lugar onde nós reservamos 40 bytes no valor da memória. Felizmente, nós já fizemos isso por declarando arr, essa matriz à direita. Que é capaz de manter 10 unidades de quatro bytes. Assim, no total, ele pode armazenar 40 bytes pena de informação. E agora estamos lendo 40 bytes de informações do arquivo, e nós estamos armazenando-o em arr. Lembre-se do vídeo em que os ponteiros o nome de uma matriz, tal como arr, é realmente apenas um ponteiro para o seu primeiro elemento. Então, quando nós passamos em arr lá, nós são, na verdade, passando um apontador. Da mesma forma que podemos fazer isto-- Nós não necessariamente precisamos de salvar nossa tampão na pilha. Nós também poderíamos alocar dinamicamente Um buffer como este, usando malloc. Lembre-se, quando alocar dinamicamente a memória, estamos salvando-o no heap, não a pilha. Mas ainda é um buffer. Ainda, neste caso, é segurando 640 bytes de informação porque um casal ocupa oito bytes. E nós estamos pedindo 80 deles. Queremos ter espaço para prender 80 quartos duplos. Então 80 vezes 8 é de 640 bytes de informação. E isso é chamada para fread coleta de 640 bytes de informação a partir do arquivo apontado por ptr e armazená-lo agora em arr2. Agora também podemos tratar fread assim como uma chamada para fgetc. Neste caso, nós estamos apenas tentando obter um personagem a partir do arquivo. E nós não precisamos de um array para conter um personagem. Podemos simplesmente armazená-lo em uma variável de caractere. O problema, porém, é que quando só temos uma variável, precisamos passar na endereço dessa variável pois lembre-se que o primeiro argumento para fread é um ponteiro para a localização e memória onde queremos armazenar as informações. Mais uma vez, o nome de um array é um ponteiro. Então, nós não precisamos fazer matriz e comercial. Mas c, o personagem c aqui, não é uma matriz. É apenas uma variável. E por isso precisamos passar um c comercial para indicar que esse é o endereço de onde queremos para armazenar este um byte de informação, este personagem que estamos coletando de ptr. Fwrite-- eu vou passar por este um pouco mais quickly-- é praticamente o equivalente exato de fread exceto que é para a escrita em vez de ler, apenas como o outro-- tivemos aberto e próximo, obter um personagem, escrever um personagem. Agora é obter arbitrária quantidade de informação, quantidade arbitrária direito de informação. Assim como antes, nós podemos ter um array de 10 inteiros onde já temos informação armazenada, talvez. Foi, provavelmente, algumas linhas de código que deve ir entre estes dois onde eu preencher com arr algo significativo. Eu preenchê-lo com 10 inteiros diferentes. E em vez disso, o que eu sou fazendo está escrevendo a partir de arr e coletando as informações do arr. E eu estou tomando essa informação e colocá-lo para o arquivo. Então, em vez de ser a partir de o arquivo para o buffer, agora estamos indo de o buffer para o arquivo. Então, é exatamente o contrário. Então, novamente, como antes, nós podemos também têm um pedaço montão de memória que nós temos dinamicamente alocados e lidos a partir desse e escrever que para o arquivo. E também temos uma única variável capaz de manter um byte de informações, como um personagem. Mas, novamente, precisamos passar em o endereço dessa variável quando queremos ler a partir dele. Assim, podemos escrever a informação encontramos nesse endereço para o ponteiro de arquivo, ptr. Há muitas outras grande arquivo I / O funções que fazer várias coisas além de os que nós já conversamos sobre hoje. Um par de os você pode achar útil são fgets e fputs, que são o equivalente de fgetc e fputc mas para a leitura uma única cadeia de caracteres de um arquivo. Em vez de um único personagem, ele irá ler uma string inteira. fprintf, que basicamente permite você usar printf para escrever no arquivo. Então, assim como você pode fazer o a substituição de variáveis ​​usando a espaços reservados por cento i e por cento d, e assim por diante, com printf você pode tomar de forma semelhante a seqüência de printf e imprimir algo como que para um arquivo. fseek-- se você tiver um leitor de DVD é a analogia que eu costumo usar aqui-- é uma espécie de como usar o seu rebobinar e avançar rapidamente botões para movimentar o filme. Da mesma forma, você pode mover o arquivo. Uma das coisas dentro que a estrutura de arquivo c que cria para você é um indicador de onde você está no arquivo. Você está no muito começando, no byte de zero? Você está em byte 100, 1000 bytes, e assim por diante? Pode utilizar fseek para mover arbitrariamente esse indicador para a frente ou para trás. E ftell, novamente semelhante a um leitor de DVD, é como um pequeno relógio que diz quantos minutos e segundos você estão em um filme particular. Da mesma forma, ftell diz-lhe como muitos bytes você está no arquivo. feof é uma versão diferente de detectar se você tem chegou ao fim do ficheiro. E é uma função ferror que você pode usar para detectar se alguma coisa tem ido trabalho errado com um arquivo. Novamente, isso é apenas arranhando a superfície. Ainda há muito mais arquivo I / O funções do padrão io.h. Mas isso provavelmente vai te começou a trabalhar com ponteiros de arquivo. Eu sou Doug Lloyd. Este é CS50.