Entrada e saída de arquivos em C

Aprenda como programas em C leem e gravam arquivos com a biblioteca padrão de entrada e saída. Abra arquivos como fluxos no modo adequado e conecte programas à entrada, à saída e à saída de erro padrão. Processe texto um caractere por vez, com leituras e escritas formatadas e linha por linha com fgets. Armazene arranjos e registros em arquivos binários com fread e fwrite, projete formatos de arquivo que sejam lidos corretamente em outras máquinas e acesse qualquer registro com fseek. Ao longo da unidade, você verifica cada resultado, explica falhas com errno e libera recursos para que seus programas falhem com segurança e informem seu resultado com precisão.

BásicoAula 7 de 8 do curso Curso de Programação em C

O que você vai aprender

  1. Explique como programas em C acessam arquivos por fluxos armazenados em buffer, abra e feche arquivos no modo adequado e use os três fluxos padrão com redirecionamento pela linha de comando.
    • Explique fluxos, armazenamento em buffer e as diferenças entre modo texto e modo binário
      Descreva o que são um fluxo e um FILE *, como funcionam o armazenamento em buffer e a posição no arquivo e como o modo texto difere do modo binário no Windows e em sistemas semelhantes ao Unix.
    • Abra e feche arquivos com fopen e fclose
      Abra um arquivo no modo adequado à tarefa, verifique se ele foi aberto, encontre arquivos pelo caminho e feche cada fluxo ao terminar o trabalho.
    • Use stdin, stdout e stderr com redirecionamento e canais entre processos
      Use os três fluxos com os quais todo programa em C começa, envie resultados e mensagens de erro ao lugar adequado e permita que usuários os redirecionem pela linha de comando.
  2. Processe arquivos de texto um caractere por vez, com leituras e escritas formatadas e linha por linha, escolhendo o padrão seguro para cada caso e verificando cada resultado.
    • Leia e escreva um caractere por vez
      Use fgetc e fputc com uma variável int, pare corretamente no fim do arquivo e conte, copie e transforme texto caractere por caractere.
    • Escreva e leia texto formatado com fprintf e fscanf
      Grave números e cadeias de caracteres em arquivos em um formato escolhido, construa nomes de arquivos com sprintf e leia dados formatados com fscanf, verificando quantos itens foram convertidos.
    • Leia linhas com segurança usando fgets
      Leia texto uma linha por vez com fgets, trate novas linhas, linhas longas e finais de linha do Windows e analise cada linha após a leitura.
  3. Grave e leia bytes brutos, arranjos e estruturas com fwrite e fread e projete formatos de arquivo binário que sejam lidos corretamente em outras máquinas.
    • Leia e grave dados binários com fread e fwrite
      Use fread e fwrite com o tamanho e a quantidade corretos de elementos, copie arquivos em blocos, reconheça tipos de arquivo pelos primeiros bytes e armazene arranjos e estruturas.
    • Projete formatos binários que funcionem em máquinas diferentes
      Explique como tamanhos de tipos, ordem dos bytes e preenchimento de alinhamento de estruturas tornam arquivos binários brutos dependentes da máquina e leia e grave campos de vários bytes em um formato definido.
  4. Consulte e defina a posição no arquivo para acessar diretamente os dados necessários e atualize registros de tamanho fixo no próprio local sem regravar o arquivo inteiro.
    • Consulte e defina a posição no arquivo com ftell, fseek e rewind
      Informe a posição atual, mova-se para posições relativas ao início, à posição atual ou ao fim, calcule deslocamentos de registros e tamanhos de arquivos e conheça os limites dos fluxos de texto.
    • Atualize registros de tamanho fixo no próprio local
      Abra um arquivo para leitura e escrita, siga a regra para alternar entre elas e altere, acrescente ou remova registros sem corromper o arquivo.
  5. Verifique o resultado de cada operação de arquivo, explique falhas ao usuário com errno e libere todos os recursos para que os programas falhem com segurança e informem o sucesso com precisão.
    • Verifique cada resultado e diferencie fim de arquivo de erros
      Saiba como cada função de stdio sinaliza falha, use feof e ferror após o término de um laço de leitura e detecte erros de escrita que aparecem somente quando o buffer é gravado.
    • Explique falhas com errno, perror e strerror
      Use errno para descobrir por que uma chamada de biblioteca falhou e exiba mensagens de erro claras que indiquem o programa, o arquivo e o motivo.
    • Libere recursos e informe o resultado
      Feche cada fluxo em todos os caminhos, não deixe arquivos de saída parcialmente gravados e retorne um código de saída que informe o resultado com precisão.

Guia de estudo de Entrada e saída de arquivos em C

5 capítulos

1

Abra arquivos como fluxos e conecte programas às suas entradas e saídas

Arquivos chegam a um programa por meio de fluxos, que controlam o acesso, o armazenamento em buffer e a posição. A escolha de um modo pode preservar dados antigos, apagá-los ou forçar cada escrita a ocorrer no fim, portanto a abertura faz parte do projeto do programa. Os três fluxos padrão estendem a mesma interface a terminais, arquivos redirecionados e canais entre processos. Entender suas conexões permite escrever uma rotina de processamento que funcione em vários cenários e mantenha diagnósticos separados dos resultados úteis.

1.1 Explique fluxos, armazenamento em buffer e as diferenças entre modo texto e modo binário

Um arquivo é um conjunto de dados armazenados; um fluxo é o canal que um programa em execução usa para acessá-lo. As mesmas funções de fluxo também podem funcionar com um terminal ou um canal entre processos. Inclua <stdio.h> e mantenha o ponteiro do fluxo em uma variável do tipo FILE *.

O que o fluxo mantém

O objeto FILE da biblioteca acompanha um buffer, a posição atual no arquivo e os indicadores de fim de arquivo e de erro. Passe seu ponteiro a funções como fgetc e fprintf; não examine nem altere seus campos. Uma leitura ou escrita avança a posição para depois dos dados processados. Em um arquivo binário que começa com "hello\nworld\n", ler os primeiros seis bytes deixa a próxima leitura no w.

O armazenamento em buffer agrupa pequenas operações em transferências maiores. Uma escrita bem-sucedida pode significar que os dados chegaram a um buffer na memória, com a transferência para o sistema operacional ainda pendente. fflush(fp) envia a saída pendente ao sistema operacional. fclose(fp) faz isso antes de liberar o fluxo. Nenhuma das duas garante que os dados sobreviverão a uma queda repentina de energia.

Modo de armazenamento em bufferQuando a saída é transferida
Totalmente armazenado em bufferQuando o buffer enche, é descarregado explicitamente ou é fechado
Armazenado em buffer por linhaTambém quando uma nova linha é gravada
Sem armazenamento em bufferAssim que possível

Arquivos comuns abertos com fopen são totalmente armazenados em buffer. Dispositivos interativos podem usar um armazenamento em buffer diferente. Um terminal ou canal entre processos não fornece posições comuns de arquivo para avançar e retroceder.

Escolha o modo texto ou binário

O modo texto trata linhas legíveis por pessoas. O modo binário preserva os valores dos bytes sem conversões de texto. Acrescente b ao modo de abertura para dados binários: "rb" lê e "wb" grava esses dados. Imagens, dados compactados e registros brutos precisam do modo binário, mesmo que uma versão em modo texto pareça funcionar em seu computador.

No Linux e no macOS, uma nova linha é um byte LF, 0x0A, e os dois modos normalmente se comportam da mesma forma. No Windows, a saída em modo texto converte '\n' nos dois bytes CR LF, 0x0D 0x0A. A entrada em modo texto converte CR LF de volta em um '\n'. A entrada em modo texto da Microsoft também reconhece 0x1A, Ctrl+Z, como fim de arquivo.

Por exemplo, gravar "a\nb\nc\n" em modo texto produz seis bytes no Linux ou no macOS e nove no Windows. Três letras contribuem com três bytes; três finais de linha do Windows contribuem com seis. Ler o arquivo do Windows em modo texto no Windows fornece seis caracteres, enquanto o modo binário expõe todos os nove bytes.

Separe os bytes do arquivo de seu texto

Uma linha criada no Windows e lida no Linux pode manter "\r\n". Remover apenas '\n' deixa '\r', o que pode fazer uma comparação com "yes" falhar. Uma posição em um fluxo de texto também pode refletir o estado da conversão, portanto salve e restaure posições em texto em vez de calcular deslocamentos de bytes.

A garantia de que o texto retornará exatamente como foi gravado em C aplica-se a caracteres imprimíveis, tabulações e novas linhas, sem espaço imediatamente antes de uma nova linha e com uma nova linha ao final da última linha. Outras sequências de bytes devem ser colocadas em fluxos binários. Bytes em C têm pelo menos oito bits; exemplos que envolvem valores de byte de 0 a 255 e formatos de arquivo comuns usam bytes de oito bits.

Principais conclusões

  • Um FILE * dá às funções da biblioteca acesso a um fluxo e a seu estado.
  • A saída armazenada em buffer pode falhar ao ser descarregada ou fechada; verifique esses resultados.
  • O modo texto do Windows converte finais de linha; o modo binário preserva os bytes.
  • Salve posições em texto; calcule deslocamentos em arquivos binários.
  • Explicite a suposição de bytes de oito bits ao interpretar formatos binários comuns.

1.2 Abra e feche arquivos com fopen e fclose

Escolha um modo de abertura antes de escrever qualquer código de processamento. O modo controla se o arquivo deve existir, se seu conteúdo será preservado e para onde vão as escritas. fopen age imediatamente sobre o arquivo: uma abertura bem-sucedida com "w" apaga um arquivo existente mesmo que nenhuma escrita posterior ocorra.

Escolha o modo adequado à tarefa
ModoArquivo existenteArquivo ausenteAcesso
"r"Mantém o conteúdoFalhaLê desde o início
"w"Apaga o conteúdoCriaGrava desde o início
"a"Mantém o conteúdoCriaGrava no fim
"r+"Mantém o conteúdoFalhaLê e grava
"w+"Apaga o conteúdoCriaLê e grava
"a+"Mantém o conteúdoCriaLê em qualquer posição; grava no fim

Acrescente b para o modo binário; "r+b" e "rb+" significam a mesma coisa. O C11 acrescenta a criação exclusiva com x em modos de escrita, como "wx" e "wbx": a abertura falha se o arquivo existir. Use uma cadeia de modo documentada; letras adicionais de modo não são portáveis.

Verifique antes de usar o ponteiro

fopen retorna um novo ponteiro de fluxo em caso de sucesso e NULL em caso de falha. Arquivos ausentes, caminhos inacessíveis e diretórios ausentes podem causar falha.

FILE *fp = fopen("scores.txt", "r");
if (fp == NULL) {
    fprintf(stderr, "Cannot open scores.txt\n");
    return EXIT_FAILURE;
}
/* Read through fp here. */
if (fclose(fp) == EOF) {
    fprintf(stderr, "Cannot close scores.txt\n");
    return EXIT_FAILURE;
}

O trecho usa <stdio.h> e <stdlib.h>. Funções como fgetc, fprintf e fclose precisam de um fluxo válido; passar NULL causa comportamento indefinido. fflush(NULL) é uma exceção deliberada que descarrega todos os fluxos de saída.

fclose retorna 0 em caso de sucesso e EOF em caso de falha. Depois de chamada, o fluxo está encerrado, inclusive quando o fechamento informa um erro. Não tente novamente fclose no mesmo ponteiro nem o use para mais operações de entrada e saída. Feche os arquivos assim que possível: os fluxos disponíveis são limitados, e C garante suporte a pelo menos oito fluxos abertos, incluindo os três padrão.

Resolva caminhos a partir do programa em execução

Um caminho relativo, como "data/input.txt", começa no diretório de trabalho atual, não na pasta do arquivo-fonte. Iniciar o programa em outro lugar muda o que esse caminho identifica. Barras normais também funcionam com a biblioteca C da Microsoft. Uma barra invertida em uma cadeia de caracteres em C deve ser duplicada, como em "C:\\data\\in.txt"; caso contrário, uma sequência de escape como \n pode alterar a cadeia.

Para nomes fornecidos na linha de comando, use int main(int argc, char *argv[]). Em um comando de cópia com dois nomes, argc deve ser 3, argv[1] é o nome da entrada e argv[2] é o nome da saída. Abra primeiro a entrada para que um nome de entrada digitado incorretamente não crie nem apague a saída. Se a abertura da saída falhar, feche a entrada já aberta. Use arquivos distintos para entrada e saída: abrir primeiro a entrada não a protege se o nome da saída identificar o mesmo arquivo.

Um retorno normal de main ou exit fecha os fluxos, mas fechamentos explícitos permitem que o programa detecte erros de saída tardios. Um encerramento inesperado pode causar perda de dados armazenados em buffer; abort não oferece a garantia de liberação de recursos de uma saída normal.

Principais conclusões

  • Abrir com "w" apaga imediatamente um arquivo existente.
  • Verifique se fopen retornou NULL antes de usar o fluxo.
  • Caminhos relativos começam no diretório de trabalho atual.
  • Feche cada fluxo aberto uma vez e nunca o reutilize após fclose.
  • Abra a entrada da cópia antes da saída e use arquivos distintos.
  • Os modos de escrita exclusiva do C11 falham quando o destino existe.

1.3 Use stdin, stdout e stderr com redirecionamento e canais entre processos

Um programa em C começa com três fluxos abertos: entrada padrão stdin, saída padrão stdout e saída de erro padrão stderr. Eles geralmente se conectam ao terminal, mas o shell pode conectá-los a arquivos ou outros programas. Você pode passá-los diretamente às funções de fluxo.

Mantenha resultados separados de diagnósticos

printf escreve em stdout; scanf lê de stdin. getchar() lê um caractere de stdin, e putchar(c) escreve um em stdout. puts(s) escreve uma cadeia de caracteres em stdout e acrescenta uma nova linha. Suas formas com fluxo permitem que o mesmo código funcione com um arquivo:

void print_total(FILE *out, int total)
{
    fprintf(out, "Total: %d\n", total);
}

Chamar print_total(stdout, 12) exibe um resultado; passar um ponteiro de arquivo aberto direciona o mesmo formato a um arquivo. Em código de produção, faça a função auxiliar informar uma falha de escrita à função chamadora.

Escreva diagnósticos com fprintf(stderr, ...). Assim, um programa de processamento de dados pode produzir um arquivo de resultados sem mensagens misturadas e explicar falhas separadamente. Um erro exibido em stdout pode corromper os dados que outro programa espera ler.

Deixe o shell escolher as conexões

Em um shell semelhante ao Unix, este comando separa os três fluxos:

./sortnums < numbers.txt > sorted.txt 2> errors.txt

< fornece a entrada, > cria ou substitui a saída, >> acrescenta à saída e 2> redireciona erros. Os operadores de redirecionamento também funcionam no Prompt de Comando do Windows, onde o nome do programa costuma ser escrito como sortnums.exe. Um canal entre processos, como em generate | sortnums, envia a saída padrão do primeiro programa para a entrada padrão do segundo. Por padrão, ele não transporta stderr.

Um filtro pode aceitar um nome de entrada opcional e, caso contrário, ler stdin. Acompanhe a responsabilidade pela liberação: feche um fluxo que sua função abriu, mas deixe um fluxo emprestado para quem é responsável por ele. Para um filtro simples de linha de comando, if (in != stdin) identifica o arquivo que ele próprio abriu.

Descarregue mensagens antes de esperar pela entrada

Um terminal geralmente faz stdout ser armazenado em buffer por linha. Um arquivo redirecionado ou canal entre processos geralmente faz com que seja totalmente armazenado em buffer. stderr não é totalmente armazenado em buffer. Isso explica por que a ordem da saída pode mudar quando ambos os fluxos são enviados ao mesmo destino.

Após printf("Saving..."), o texto pode permanecer no buffer porque não há nova linha. Use fflush(stdout) e verifique se houve EOF quando ele precisar aparecer antes da próxima operação. Descarregar envia a saída pendente; não lê nem descarta entrada. O padrão C não define fflush(stdin) como uma operação de limpeza de entrada. Para descartar uma linha, leia caracteres até '\n' ou EOF.

Se um programa exibir duas linhas em stdout e um aviso em stderr entre elas, um terminal geralmente mostrará a ordem do programa. Com > out.txt 2>&1, o aviso pode chegar ao arquivo antes da saída padrão armazenada em buffer. Não use a ordem de exibição de fluxos misturados como registro da ordem de execução.

Retorne um resultado utilizável por scripts

Retorne EXIT_SUCCESS ou 0 quando o trabalho completo for bem-sucedido e EXIT_FAILURE quando falhar. Ambas as macros são declaradas em <stdlib.h>. Um comando de shell como convert in.csv out.txt && echo done executa o segundo comando somente após o sucesso. Um código de saída fiel ao resultado é tão importante quanto um diagnóstico útil.

Principais conclusões

  • Use stdin, stdout e stderr sem abri-los.
  • Envie resultados do programa para stdout e diagnósticos para stderr.
  • O redirecionamento altera conexões; um canal entre processos leva a saída padrão à entrada padrão.
  • Descarregue a saída quando uma mensagem precisar ficar visível imediatamente.
  • Retorne um código de saída de falha quando o trabalho solicitado falhar.
2

Leia e grave arquivos de texto

O processamento de texto tem três escalas úteis: caracteres individuais, valores formatados e linhas inteiras. A escolha altera o que o programa pode validar e como ele se recupera de entradas inválidas. Um laço de caracteres deve distinguir bytes do fim de arquivo; uma leitura formatada deve verificar sua contagem de atribuições; um leitor de linhas deve lidar com a capacidade e registros incompletos. Exemplos resolvidos mostram como preservar os dados efetivamente lidos e manter sob controle a análise e a geração de mensagens posteriores.

2.1 Leia e escreva um caractere por vez

A entrada e saída de caracteres é útil quando cada caractere determina o que acontece em seguida: contar separadores, mudar entre maiúsculas e minúsculas ou reconhecer um formato de texto simples. fgetc lê um caractere, e fputc grava um. Ambas são declaradas em <stdio.h>.

Mantenha o valor de retorno em um int

fgetc(fp) retorna o caractere como um unsigned char convertido para int, ou a constante negativa EOF quando nenhum caractere está disponível porque a entrada terminou ou uma leitura falhou. Nos sistemas usuais com bytes de oito bits, os valores válidos de byte vão de 0 a 255. Um int mantém esses valores distintos de EOF.

int c;
while ((c = fgetc(in)) != EOF) {
    if (fputc(c, out) == EOF) {
        /* Report a write failure and clean up. */
        break;
    }
}
/* Check ferror(in) before declaring the input complete. */

Um char simples pode perder essa distinção. Com char com sinal, o byte 0xFF pode se tornar -1 e parecer fim de arquivo. Com char sem sinal, o valor negativo EOF é convertido em byte e nunca pode ser comparado como igual a EOF.

Mantenha os dois parênteses ao redor da atribuição. Em c = fgetc(in) != EOF, a comparação ocorre primeiro, portanto c recebe 1 ou 0 em vez do caractere. getc faz o mesmo trabalho de leitura e pode ser uma macro; fputc retorna o caractere gravado ou EOF.

Conte leituras bem-sucedidas, não tentativas

A condição do laço deve executar a leitura. feof descreve uma tentativa anterior que chegou ao fim; ela não pode prever a próxima tentativa. Um laço que verifica !feof(in) e depois conta incondicionalmente acrescenta uma passagem extra ao final.

Para o texto "hi\nyo\n", seis leituras bem-sucedidas fornecem seis caracteres e dois caracteres de nova linha. Contar apenas caracteres de nova linha funciona para linhas terminadas em nova linha. O texto "red\ngreen\nblue" tem duas novas linhas, mas três linhas, pois o "blue" final ainda é uma linha.

Para incluir uma linha final sem nova linha, acompanhe também o último caractere:

size_t lines = 0;
int c, last = '\n';
while ((c = fgetc(in)) != EOF) {
    if (c == '\n') ++lines;
    last = c;
}
if (last != '\n') ++lines;

Iniciar last com '\n' faz um arquivo vazio contar como zero linhas. Um erro de leitura ainda exige um caminho de falha separado; uma contagem parcial não é um resultado completo.

Transforme ou examine o próximo caractere

toupper de <ctype.h> pode mudar letras antes da escrita. Um resultado bem-sucedido de fgetc já está na faixa de entrada válida para toupper, portanto fputc(toupper(c), out) é seguro dentro do laço. Valores arbitrários de char com sinal precisam ser convertidos para unsigned char antes de serem passados a funções de classificação de caracteres.

ungetc(c, in) devolve um caractere ao fluxo para que a próxima leitura o retorne novamente. A devolução de um caractere é garantida; verifique se houve EOF para detectar falha na devolução. Isso ajuda um analisador a examinar o próximo caractere sem perdê-lo. Uma operação de posicionamento descarta o caractere devolvido.

A contagem descreve o que o modo de fluxo selecionado fornece. No Windows, o modo texto conta um par CR LF como um '\n'; o modo binário expõe ambos os bytes. Portanto, uma contagem de caracteres por um fluxo de texto não precisa ser igual à contagem de bytes armazenados.

Principais conclusões

  • Mantenha resultados de fgetc em int para que os valores de byte permaneçam distintos de EOF.
  • Teste o resultado de cada leitura antes de processá-lo ou contá-lo.
  • Conte uma parte final não vazia sem nova linha como uma linha.
  • A devolução de um caractere com ungetc é garantida; o posicionamento a descarta.

2.2 Escreva e leia texto formatado com fprintf e fscanf

A entrada e saída formatada converte valores de C em texto legível e vice-versa. fprintf grava no formato que você escolher; fscanf lê valores que correspondem a um formato. Suas especificações de conversão parecem semelhantes, mas a entrada exige ponteiros para os tipos corretos de destino.

Escreva valores legíveis

Use %d para um int, %ld para um long, %zu para um size_t, %s para uma cadeia de caracteres e %c para um caractere. Na saída, %f exibe um double; um argumento float é promovido a double. %% exibe um sinal de porcentagem.

int result = fprintf(fp, "%-8s%6.2f\n", "Oslo", 3.14159);
if (result < 0) {
    /* Handle a write failure. */
}

%-8s alinha "Oslo" à esquerda em oito colunas; %6.2f alinha "3.14" à direita em seis. A linha resultante é "Oslo 3.14\n", e o retorno é 15 caracteres. A largura de campo é um mínimo, não um limite de comprimento da saída. A precisão também altera a informação armazenada: %.2f grava 3.14159 como "3.14", portanto esses dígitos adicionais não podem ser recuperados do arquivo.

Um programa simples de escrita de CSV pode gerar "Lima,2024,19.5" com uma ordem fixa e vírgulas entre os campos. Texto que contém vírgulas, aspas ou novas linhas precisa de delimitação de campos CSV com aspas. Delimite esse campo com aspas duplas e duplique qualquer aspa dentro dele. Um programa de escrita que usa apenas %s é adequado somente quando os campos de texto não contêm esses caracteres.

Formate em um arranjo com limite

sprintf não tem argumento de tamanho de destino. Formatar "007.jpg" exige oito bytes, incluindo o terminador nulo. Prefira snprintf:

char name[32];
int n = snprintf(name, sizeof name, "%03d.jpg", 7);
if (n < 0 || (size_t)n >= sizeof name) {
    /* Formatting failed or the full result did not fit. */
}

O retorno não negativo é o comprimento que o texto completo exigiria, excluindo o terminador nulo. Um valor igual ao tamanho do buffer já significa truncamento. Verifique se o resultado é negativo antes de convertê-lo para size_t.

Leia a quantidade esperada de valores
char name[20];
int age;
int matched = fscanf(fp, "%19s %d", name, &age);

Essa chamada só é totalmente bem-sucedida se retornar 2. A largura 19 deixa um byte para o terminador. O nome do arranjo fornece seu endereço; o inteiro precisa de &age. Para entrada, %f precisa de float *, enquanto %lf precisa de double *. Uma incompatibilidade causa comportamento indefinido, não uma conversão inofensiva.

A maioria das conversões pula caracteres de espaço em branco iniciais, incluindo novas linhas. Portanto, fscanf não exige um registro por linha, e %s não consegue ler "New York" como um único valor. Um conjunto de leitura como %19[^,] lê até uma vírgula; a leitura da linha inteira costuma ser mais clara para registros.

Em "10 abc 20", %d primeiro armazena 10 e retorna 1. A próxima chamada retorna 0 porque "abc" não corresponde; esse texto permanece sem leitura. Testar != EOF repete a falha indefinidamente. Teste == 1 e depois trate dados inválidos separadamente do fim da entrada ou de um erro de fluxo. Um resultado de conversão é uma contagem de valores atribuídos, não um valor de verdade para o arquivo inteiro.

Principais conclusões

  • Associe cada especificação de conversão ao tipo de argumento correto.
  • Limite %s de entrada ao tamanho do arranjo menos um.
  • Compare fscanf com o número exato de atribuições esperado.
  • snprintf retorna o comprimento total necessário; um retorno igual ou superior à capacidade significa truncamento.
  • Campos de texto CSV precisam de aspas quando contêm vírgulas, aspas ou novas linhas.
  • A saída formatada de ponto flutuante pode descartar precisão.

2.3 Leia linhas com segurança usando fgets

Ler uma linha completa antes de analisá-la mantém cada registro de texto separado. Se um registro for inválido, você pode informar o número da linha e continuar com o próximo. fgets limita o quanto grava, mas você ainda precisa lidar com novas linhas mantidas e linhas maiores que o arranjo.

Leia para um buffer de capacidade conhecida
char line[256];
while (fgets(line, sizeof line, fp) != NULL) {
    /* Process this successful read. */
}
if (ferror(fp)) {
    /* Report an interrupted read. */
}

fgets lê no máximo um caractere a menos que a capacidade, para após uma nova linha se encontrar uma e acrescenta um terminador nulo. Retorna o buffer em caso de sucesso. Um resultado NULL significa que não havia caracteres disponíveis no fim do arquivo ou que ocorreu um erro; não processe o buffer após um erro de leitura.

sizeof line fornece a capacidade do arranjo nesse escopo. Em uma função auxiliar cujo parâmetro é char *line, ele é o tamanho do ponteiro. Passe a capacidade real separadamente. A antiga função gets não consegue limitar a entrada e foi removida no C11.

Reconheça partes de linhas longas

Com char buf[8], "temperature\n" chega como "tempera" e depois "ture\n". A primeira chamada usa sete bytes para caracteres e um para o terminador. Uma leitura bem-sucedida sem nova linha pode ser uma parte de uma linha longa ou a parte final sem nova linha no fim do arquivo.

Escolha uma política: una as partes em um registro maior, processe-as como uma sequência contínua ou rejeite o registro e descarte todas as partes restantes. Para um limite de tamanho, examine o próximo caractere antes de rejeitar um buffer exatamente cheio. Uma nova linha em seguida completa o registro; EOF sem erro de fluxo completa uma linha final sem nova linha; outro caractere significa que há mais conteúdo. Devolva um caractere ao fluxo somente se o código posterior precisar lê-lo novamente.

Remova apenas um final de linha encontrado

Depois de decidir se o registro está completo, remova os finais de linha:

line[strcspn(line, "\r\n")] = '\0';

strcspn de <string.h> encontra o primeiro caractere listado ou o terminador existente se nenhum dos dois ocorrer. Isso trata tanto CR LF mantido quanto LF. Excluir line[strlen(line) - 1] incondicionalmente pode remover dados reais de uma linha final sem nova linha e é inválido para uma cadeia vazia.

fputs(line, out) grava a cadeia sem acrescentar uma nova linha; puts(line) grava em stdout e acrescenta uma. Uma cópia de texto pode passar cada parte lida com sucesso por fgets para fputs, verificando se houve falha, mesmo quando uma linha longa ocupa várias partes. Para obter exatamente os bytes originais, use entrada e saída binária em blocos.

Analise e valide separadamente

sscanf(line, "%d %9s", &qty, item) retorna 2 para "7 apples" e 0 para "seven apples". Uma análise malsucedida não deixa um elemento inválido preso no fluxo de entrada porque a linha já foi lida. Conversões numéricas com sscanf ainda exigem entrada representável; use strtol para uma verificação rigorosa de faixa.

Para strtol, limpe errno, passe um ponteiro de fim da conversão e verifique a ausência de dígitos, ERANGE e texto inesperado ao final. Em "42abc", o resultado 42 é apenas um prefixo numérico. Para um campo de número inteiro, permita os caracteres de espaço em branco finais escolhidos e depois exija o fim da cadeia. Verifique a faixa do tipo de destino antes de converter um long válido para int, de faixa menor.

Principais conclusões

  • fgets mantém uma nova linha quando ela cabe e sempre reserva espaço para um terminador em caso de sucesso.
  • Um buffer cheio sem nova linha exige uma verificação para determinar se a linha está completa.
  • Passe capacidades explicitamente a funções auxiliares que usam ponteiros.
  • Use strcspn para remover apenas um final de linha existente.
  • Leia primeiro e depois analise e valide cada registro.
  • Verifique em strtol a presença de dígitos, erros de faixa e dados ao final.
3

Armazene e carregue dados em arquivos binários

Arquivos binários transferem bytes de objetos sem convertê-los em texto legível. Os tamanhos e as quantidades de elementos determinam como arranjos completos, registros e blocos finais parciais são tratados. Um arquivo compartilhado entre máquinas também precisa de uma representação explícita: larguras dos campos, ordem dos bytes e leiaute. Ler uma assinatura é apenas o começo da verificação dessa representação; comprimentos e contagens devem ser validados antes de o programa confiar nos dados restantes ou alocar espaço para eles.

3.1 Leia e grave dados binários com fread e fwrite

A entrada e saída binária transfere os bytes de objetos sem convertê-los em números ou palavras legíveis. fread e fwrite recebem um endereço, um tamanho de elemento, uma quantidade de elementos e um fluxo. Seus valores de retorno contam elementos completos, portanto a escolha do tamanho do elemento determina o que você pode saber pelo resultado.

Grave e leia arranjos
int a[5] = {1, 2, 3, 4, 5};
if (fwrite(a, sizeof a[0], 5, out) != 5) {
    /* Handle a write failure. */
}

Em um sistema com int de quatro bytes, isso grava 20 bytes e retorna 5. A leitura para outro arranjo de cinco elementos com a mesma representação pode recuperar os valores. Use "wb" e "rb" para que conversões de texto não alterem os bytes.

Para um único objeto, passe seu endereço: fwrite(&rec, sizeof rec, 1, out). Para objetos acessados por um ponteiro p, use fwrite(p, sizeof *p, count, out). sizeof p mede o ponteiro, e &p aponta para a própria variável ponteiro. Nenhum dos dois expressa a transferência de dados pretendida. Quando o tamanho ou a quantidade de elementos é zero, ambas as funções retornam zero sem transferir dados.

Copie exatamente os bytes lidos
unsigned char buf[512];
size_t n;
while ((n = fread(buf, 1, sizeof buf, in)) > 0) {
    if (fwrite(buf, 1, n, out) != n) {
        /* Handle failure and stop copying. */
        break;
    }
}

Um tamanho de elemento de 1 faz de n uma contagem de bytes. Uma entrada de 1300 bytes fornece 512, 512 e 276 bytes, depois zero. A última escrita deve usar 276, não a capacidade 512. Gravar o buffer inteiro acrescenta 236 bytes restantes de leituras anteriores.

Com fread(buf, 512, 1, in), a mesma entrada retorna 1, 1 e depois 0. Os últimos 276 bytes são apenas um elemento parcial; eles não são contados, e o valor desse elemento parcial é indeterminado. Escolha elementos de um byte quando um bloco final parcial for útil. Escolha elementos do tamanho de um registro quando registros incompletos precisarem ser rejeitados.

Um retorno menor que o solicitado de fread pode significar fim de arquivo ou erro. Verifique ferror após a cópia e verifique fclose na saída: uma escrita aceita em um buffer pode falhar mais tarde. Um cabeçalho ou registro parcial nunca deve ser tratado como um objeto completo.

Examine assinaturas e objetos armazenados

Use unsigned char para bytes brutos; em sistemas com bytes de oito bits, ele armazena valores de 0 a 255 sem valores negativos. Dados JPEG começam com 0xFF 0xD8. Fotos de câmeras e celulares frequentemente continuam com um marcador APPn, produzindo o padrão de recuperação de FF D8 FF E0 a FF D8 FF EF. Esse padrão é um teste útil para identificar candidatos; valide o formato antes de confiar nele. Alguns arquivos JPEG usam um segmento seguinte diferente.

Uma estrutura com char name[20] e um int score costuma ocupar 24 bytes. Uma escrita bruta inclui todos os seus bytes armazenados, inclusive o preenchimento de alinhamento. Um membro ponteiro salva um endereço, não a cadeia para a qual aponta. Use um arranjo dentro da estrutura ou grave o comprimento e os caracteres da cadeia separadamente.

Texto legível pode ocupar mais espaço: "1000000\n" usa oito bytes no Linux e nove no modo texto do Windows. Um inteiro de 32 bits codificado explicitamente usa quatro bytes de oito bits. O armazenamento bruto de objetos é compacto, mas vincula o arquivo à representação usada por quem o produziu.

Principais conclusões

  • fread e fwrite retornam contagens de elementos completos, nem sempre contagens de bytes.
  • Use tamanho de elemento 1 quando um bloco final parcial for importante.
  • Grave a quantidade lida, não a capacidade inteira do buffer.
  • Um membro ponteiro gravado diretamente armazena um endereço, não os dados apontados.
  • Verifique transferências incompletas e o fechamento da saída.
  • Use assinaturas para identificar candidatos e depois valide o arquivo.

3.2 Projete formatos binários que funcionem em máquinas diferentes

Um fluxo binário preserva bytes, mas duas máquinas podem interpretar os mesmos bytes de formas diferentes. Um formato portável define o significado de cada byte em vez de adotar qualquer leiaute que o compilador atribua a um objeto.

Especifique tamanhos, ordem e leiaute

Três aspectos tornam uma cópia bruta de objeto dependente da máquina:

AspectoO que pode diferir
Tamanho do tipoint pode ter dois ou quatro bytes; long costuma diferir entre Windows e Linux de 64 bits
Ordem dos bytesO byte menos ou o mais significativo pode vir primeiro
Leiaute da estruturaO preenchimento de alinhamento e os deslocamentos dos membros podem mudar

A ordem do byte menos significativo primeiro armazena esse byte primeiro. A ordem do byte mais significativo primeiro armazena esse byte primeiro. O valor 258, hexadecimal 0x00000102, é 02 01 00 00 na ordem do byte menos significativo primeiro e 00 00 01 02 na ordem do byte mais significativo primeiro.

Um leiaute comum de estrutura para um char seguido de um int ocupa oito bytes: um byte para o caractere, três bytes de preenchimento de alinhamento e quatro para o inteiro. Os valores do preenchimento não são especificados. Tipos de largura exata de <stdint.h>, como uint32_t, fixam as larguras em bits quando disponíveis; eles não fixam a ordem dos bytes nem removem o preenchimento. Exemplos de formatos de arquivo comuns pressupõem bytes de oito bits e a disponibilidade desses tipos.

Decodifique campos explicitamente

Leia quatro bytes por completo antes de interpretá-los. Para um campo na ordem do byte menos significativo primeiro:

uint32_t v = (uint32_t)b[0]
           | (uint32_t)b[1] << 8
           | (uint32_t)b[2] << 16
           | (uint32_t)b[3] << 24;

Aqui, b é um arranjo de bytes sem sinal. Cada conversão explícita de tipo ocorre antes do deslocamento, portanto a operação aritmética tem a largura sem sinal necessária. Para codificar, extraia os oito bits menos significativos, depois os oito seguintes e assim por diante. Verifique cada operação de saída. Gravar v diretamente com fwrite colocaria novamente no formato a ordem dos bytes da máquina.

Defina um formato pequeno e completo

Um formato de pontuações pode usar "SCR1" como assinatura de quatro bytes, uma contagem de quatro bytes na ordem do byte menos significativo primeiro e registros compostos de 20 bytes para o nome mais quatro bytes para a pontuação nessa mesma ordem. A assinatura também identifica a versão. O cabeçalho tem oito bytes; cada registro tem exatamente 24 bytes.

Cinco registros ocupam 128 bytes. O registro de índice 3 começa no byte 80: pule os oito bytes do cabeçalho e três registros completos. Em um formato real, indique a codificação do campo de nome e a regra de terminação ou preenchimento; um campo de nome fixo de 20 bytes não é automaticamente uma cadeia de caracteres em C.

Verifique o comprimento completo e a assinatura de um cabeçalho antes de usar seus campos. Depois, verifique as contagens e os comprimentos em relação a limites razoáveis e aos dados disponíveis antes de alocar memória. Uma contagem plausível não basta se faltarem registros posteriores.

Leia a estrutura real do formato

Alguns arquivos PCM WAV têm um cabeçalho simples de 44 bytes, com a taxa de amostragem nos bytes 24 a 27. Os bytes 44 AC 00 00 são decodificados como 44.100 amostras por segundo. Outros arquivos WAV contêm blocos adicionais, portanto um leitor geral acompanha os identificadores e tamanhos dos blocos para localizar o bloco fmt . Supor um leiaute fixo de cabeçalho para todos os arquivos pode fazer com que um campo sem relação seja lido como a taxa.

Texto como CSV evita problemas de tamanho de inteiro, ordem dos bytes e preenchimento de alinhamento de estruturas e é fácil de examinar. Ele ainda precisa de um leiaute de campos definido, regras de delimitação com aspas e análise verificada. Escolha-o quando legibilidade e intercâmbio forem mais importantes que uma representação binária compacta.

Principais conclusões

  • Um formato binário portável define larguras dos campos, ordem dos bytes e deslocamentos.
  • Tipos inteiros de largura exata, por si só, não tornam portável uma cópia bruta de estrutura.
  • Converta explicitamente os bytes para a largura sem sinal pretendida antes de deslocá-los.
  • Valide o cabeçalho inteiro e limite as contagens antes de confiar nelas.
  • Siga a estrutura dos blocos quando um formato permitir blocos adicionais.
  • Um campo de texto de largura fixa precisa de uma regra explícita de codificação e comprimento.
4

Mova-se para qualquer posição em um arquivo

Posições em arquivos tornam possível o acesso direto quando os registros têm locais conhecidos. Calcular esses locais exige atenção aos cabeçalhos, às larguras dos registros e aos índices iniciados em zero. Posições em texto seguem regras mais restritas porque a conversão pode mudar seu significado. Quando um fluxo permite tanto leitura quanto escrita, o posicionamento também controla mudanças válidas de direção. Assim, atualizar um registro combina o cálculo de uma posição com uma sequência verificada que preserva os dados ao redor.

4.1 Consulte e defina a posição no arquivo com ftell, fseek e rewind

Leituras sequenciais percorrem os dados em ordem. O acesso aleatório permite que um programa salte para um local conhecido, como um registro em um arquivo grande. O posicionamento só funciona quando o fluxo subjacente oferece suporte a ele, e o significado de uma posição difere entre fluxos binários e de texto.

Consulte e altere a posição

ftell(fp) retorna uma posição long ou -1L em caso de falha. Em um arquivo binário, uma posição conta os bytes desde o início. fseek(fp, offset, whence) move em relação a um ponto de referência selecionado e retorna 0 em caso de sucesso e um valor diferente de zero em caso de falha.

ReferênciaSignificado do deslocamento
SEEK_SETA partir do início
SEEK_CURA partir da posição atual
SEEK_ENDA partir do fim

Por exemplo, fseek(fp, -4L, SEEK_END) solicita a posição dos últimos quatro bytes de um arquivo binário em um sistema que aceite posicionamento relativo ao fim. Verifique o resultado antes de ler. Uma solicitação em um canal entre processos ou terminal, ou para uma posição anterior ao início de um arquivo comum, pode falhar.

Calcule a posição de um registro

Para registros binários de tamanho fixo sem cabeçalho, o índice iniciado em zero multiplicado pela largura do registro fornece o deslocamento inicial. Com registros de 24 bytes, o índice 3 começa no byte 72. Após a leitura do registro inteiro, a posição é 96.

long offset = 3L * (long)sizeof(struct record);
if (fseek(fp, offset, SEEK_SET) != 0) {
    /* Handle the failed move before reading. */
}

Este exemplo pressupõe que o arquivo foi gravado com o mesmo leiaute de estrutura. Um formato portável especificado usa a largura de registro definida por ele. Inclua os bytes do cabeçalho quando houver um. O terceiro registro contado a partir de 1 tem índice 2, não índice 3. Para índices grandes, valide a multiplicação e verifique se o resultado cabe em long antes de posicionar o fluxo.

Nos sistemas mais comuns, posicionar no fim e usar ftell pode medir um arquivo binário: um arquivo de 120 bytes com registros de 24 bytes contém cinco registros. Verifique ambas as chamadas e restaure a posição depois. O padrão C não exige um SEEK_END significativo para todo fluxo binário, portanto o método depende do suporte desse fluxo.

Salve posições em texto sem operações aritméticas

O modo texto pode converter finais de linha. Uma posição em texto retornada é uma informação para voltar a um local, não uma contagem à qual somar ou da qual subtrair. Um posicionamento em texto com deslocamento diferente de zero usa um valor retornado anteriormente por ftell para o mesmo arquivo, com SEEK_SET. Um deslocamento zero é permitido com qualquer ponto de referência.

rewind(fp) retorna ao início e limpa os indicadores de fim de arquivo e de erro. Ela não retorna resultado, portanto use fseek(fp, 0L, SEEK_SET) com verificação quando for necessário confirmar que a movimentação teve sucesso. Uma chamada bem-sucedida a fseek limpa o indicador de fim de arquivo e descarta o caractere devolvido com ungetc, mas mantém ativado um indicador de erro existente.

Mantenha um valor de posição

fgetpos(fp, &pos) salva uma posição em fpos_t; fsetpos(fp, &pos) a restaura. Verifique se ambas retornam um valor diferente de zero, que indica falha. Trate fpos_t como um valor opaco, sem operações aritméticas. Ele pode conter informações de posição além de uma simples contagem de bytes.

fseek e ftell usam long, que costuma ter 32 bits no Windows e limita as posições representáveis a cerca de 2 GiB. Um valor de posição evita vincular a interface a long, mas o tamanho de arquivo aceito ainda depende da implementação e da configuração.

Principais conclusões

  • Verifique se fseek retorna um valor diferente de zero e se ftell retorna -1L.
  • O deslocamento de um registro inclui o cabeçalho e todos os registros anteriores.
  • Use índices iniciados em zero de forma consistente.
  • Restaure posições em texto com valores salvos, sem operações aritméticas de deslocamento.
  • rewind limpa ambos os indicadores; uma chamada bem-sucedida a fseek limpa o indicador de fim de arquivo.
  • O posicionamento exige um fluxo que o aceite e deslocamentos representáveis.

4.2 Atualize registros de tamanho fixo no próprio local

Um fluxo de atualização lê e grava no mesmo arquivo. Use "r+b" para preservar um arquivo binário existente enquanto altera seus registros. "w+b" apaga imediatamente o arquivo antigo, e modos de acréscimo forçam toda escrita a ocorrer no fim.

Torne válidas as mudanças de direção

Um fluxo de atualização tem duas regras de alternância:

MudançaAção necessária entre as operações
De escrita para leituraDescarregar a saída ou executar uma operação de posicionamento
De leitura para escritaExecutar uma operação de posicionamento, a menos que a leitura tenha encontrado o fim do arquivo

As funções de posicionamento incluem fseek, fsetpos e rewind. Verifique as funções que informam um resultado antes de continuar. Uma mudança de direção sem a ação necessária causa comportamento indefinido; você não pode prever que ela apenas afetará o próximo registro.

Atualize um registro completo

Suponha que um arquivo sem cabeçalho contenha cinco registros de 24 bytes na mesma representação de struct record. Para alterar o índice 3:

  1. Abra com "r+b" e verifique o ponteiro.
  2. Posicione no byte 72 e verifique se houve sucesso.
  3. Leia exatamente um registro completo.
  4. Altere seu membro score para 99.
  5. Volte à posição inicial do registro.
  6. Grave exatamente um registro e verifique o resultado do fechamento.

As principais operações intermediárias são:

if (fread(&rec, sizeof rec, 1, fp) != 1) {
    /* Report the incomplete input, then clean up. */
    goto cleanup;
}
rec.score = 99;
if (fseek(fp, -(long)sizeof rec, SEEK_CUR) != 0) {
    /* Report the failed seek, then clean up. */
    goto cleanup;
}
if (fwrite(&rec, sizeof rec, 1, fp) != 1) {
    /* Report the failed write, then clean up. */
    goto cleanup;
}

A função que contém esse trecho fornece um rótulo cleanup que fecha seu fluxo e retorna falha nesses ramos. Após a leitura, a posição é 96. Voltar 24 bytes seleciona o registro original e permite a alternância de leitura para escrita. Uma substituição bem-sucedida deixa o arquivo com 120 bytes e cinco registros. Restaurar uma posição inicial salva é outra forma válida de fazer a atualização.

Decida quando regravar

Acrescentar um registro de 24 bytes aumenta esse arquivo para 144 bytes. Posicionar no início de um fluxo "ab" ou "a+b" não transforma sua próxima escrita em sobrescrita; a escrita ainda ocorre no fim atual.

Uma substituição no próprio local deve caber no espaço que substitui. Alterar "Bo,7" para "Bo,9" cabe. Gravar "Bo,12" sobre "Bo,7\n" consome a nova linha e une o texto seguinte ao registro. Para aumentar ou reduzir registros, grave um novo arquivo corrigido. O padrão C não tem função de fluxo que remova uma faixa de bytes do meio de um arquivo. Em vez disso, a exclusão pode copiar todos os registros mantidos ou marcar um registro de tamanho fixo como excluído.

Mantenha a substituição recuperável

Verifique remove e rename; ambas retornam 0 em caso de sucesso. A substituição ou não de um destino existente por rename é definida pela implementação. Linux e macOS permitem a substituição; a biblioteca C da Microsoft falha quando o destino existe.

Um plano portável de recuperação grava e fecha o novo arquivo, renomeia o original para um nome distinto de backup e renomeia o novo arquivo para o nome original. Se a instalação falhar, mantenha o backup disponível para restauração e informe onde ele está. Exclua o backup somente após a instalação ser bem-sucedida. Essa sequência permite recuperação; ela não é uma transação atômica portável nem uma garantia contra falhas de energia.

Principais conclusões

  • Use "r+b" para atualizar um arquivo existente sem truncá-lo.
  • Siga a regra de alternância entre leitura e escrita mesmo quando a posição pretendida parecer óbvia.
  • Volte à posição do registro após lê-lo e antes de substituí-lo.
  • Escritas em modo de acréscimo sempre ocorrem no fim.
  • Regrave os dados quando seu comprimento mudar.
  • Verifique cada etapa da substituição e preserve um original recuperável.
5

Detecte e relate erros de arquivo e recupere-se deles

Uma operação de arquivo pode falhar depois de uma abertura bem-sucedida, e uma falha na saída armazenada em buffer pode aparecer somente no fechamento. Programas confiáveis leem valores de retorno, distinguem dados inválidos de problemas de acesso, preservam informações úteis sobre erros e liberam recursos em todos os caminhos. Essas tarefas funcionam em conjunto: o diagnóstico deve explicar a falha original, enquanto o código final também deve refletir falhas encontradas durante a liberação de recursos. Um programa de cópia completo mostra como essas decisões se encaixam no fluxo de controle comum de C.

5.1 Verifique cada resultado e diferencie fim de arquivo de erros

Um arquivo pode ser aberto com sucesso e ainda assim falhar durante a leitura, a escrita, o posicionamento ou o fechamento. Um programa robusto verifica o resultado da operação que realmente tentou executar. Ele distingue uma leitura concluída de uma entrada interrompida e dados malformados de uma falha no fluxo.

Conheça cada sinal de falha
OperaçãoSinal a tratar
fopen, fgetsNULL
fgetc, fputc, fflush, fcloseEOF
fprintfUm resultado negativo
fputsEOF
fread, fwriteMenos elementos completos que o solicitado
fscanfMenos atribuições que o esperado ou EOF
fseek, fgetpos, fsetposUm resultado diferente de zero
ftell-1L

rewind, clearerr e perror não retornam valor. Se for necessário verificar se a movimentação até o início teve sucesso, use fseek em vez de depender de um resultado de rewind.

Examine o fluxo após uma leitura parar

O fluxo mantém indicadores separados de fim de arquivo e erro. feof(fp) testa o primeiro; ferror(fp) testa o segundo. Cada uma retorna um valor diferente de zero se seu indicador estiver ativado.

while (fgets(line, sizeof line, fp) != NULL) {
    /* Process successful input. */
}
if (ferror(fp)) {
    fprintf(stderr, "Input could not be completed\n");
    /* Return failure after cleanup. */
}

O retorno de fgets sozinho não distingue os dois motivos de parada. Da mesma forma, fgetc retorna EOF e fread retorna uma contagem menor que a solicitada tanto no fim do arquivo quanto em uma falha de leitura. Não teste feof antes da leitura para prever se restam dados.

Os indicadores persistem. clearerr limpa ambos, assim como rewind. Uma chamada bem-sucedida a fseek ou fsetpos limpa o indicador de fim de arquivo, mas não um erro existente. Limpar um indicador reconhece sua ocorrência; isso não reconecta uma unidade removida nem repara um arquivo danificado. Tente novamente somente quando a causa tiver sido resolvida.

Separe dados inválidos de falhas de acesso

Se fscanf(fp, "%d", &value) retornar 0 em "abc", a conversão falhou antes de qualquer atribuição. Não é necessário que tenha ocorrido fim de arquivo ou erro de leitura. Informe que o campo é inválido, de preferência com o número da linha. Uma mensagem sobre o disco descreveria o problema errado.

Se um cabeçalho obrigatório for lido como um elemento e fread retornar 0, o cabeçalho está incompleto. Não examine esse objeto parcialmente preenchido. Se ferror estiver ativado, informe um erro de entrada; se o arquivo tiver terminado, informe dados truncados. Um arquivo vazio e um cabeçalho parcial podem produzir a mesma contagem de elementos, portanto o formato esperado estabelece a exigência de que o cabeçalho exista.

Detecte falhas tardias de saída

Um disco pode ficar cheio depois que o programa abriu sua saída. Escritas armazenadas em buffer podem parecer bem-sucedidas até que fflush ou fclose realmente transfira os bytes pendentes. Verifique o fechamento final e permita que ele transforme um trabalho que seria bem-sucedido em falha. Não feche o mesmo fluxo novamente depois disso.

Em um terminal, Ctrl+D no início de uma linha no Linux ou no macOS, ou Ctrl+Z seguido de Enter no Windows, geralmente sinaliza o fim da entrada. clearerr(stdin) limpa o indicador resultante se o programa precisar de outra tentativa. A ação no terminal e um erro de leitura continuam sendo causas diferentes.

Principais conclusões

  • Verifique cada função de acordo com seu próprio valor de retorno documentado.
  • Leia primeiro e depois use os indicadores do fluxo para identificar o motivo da parada.
  • Uma incompatibilidade de formato significa dados inválidos, não necessariamente um erro de fluxo.
  • Rejeite cabeçalhos e registros obrigatórios incompletos.
  • Um erro tardio no fechamento da saída deve fazer o trabalho falhar.

5.2 Explique falhas com errno, perror e strerror

Um valor de retorno informa que uma operação falhou. Um código de erro pode ajudar a explicar por quê. Use errno apenas no contexto do comportamento documentado da operação e preserve-o antes que chamadas de biblioteca não relacionadas possam alterá-lo.

Deixe a operação estabelecer a falha

errno é uma expressão int modificável de <errno.h>, com duração de armazenamento local à thread no C11. Ele começa em zero. Chamadas de biblioteca não o redefinem como zero, e uma chamada bem-sucedida pode deixar ou definir um valor diferente de zero. Portanto, testar errno após uma chamada bem-sucedida a fopen não informa que a abertura falhou.

Em sistemas POSIX, uma chamada malsucedida a fopen define um código de erro. A biblioteca C da Microsoft também fornece códigos de erro de arquivo. O padrão C não exige que fopen defina errno. Uma forma portável de informar o erro pode limpá-lo antes da abertura e usar uma mensagem geral se nenhum código for fornecido:

errno = 0;
FILE *fp = fopen(name, "r");
if (fp == NULL) {
    int saved = errno;
    if (saved != 0)
        fprintf(stderr, "Cannot open %s: %s\n",
                name, strerror(saved));
    else
        fprintf(stderr, "Cannot open %s\n", name);
    return EXIT_FAILURE;
}

Esse trecho também precisa de <stdio.h>, <stdlib.h> e <string.h>. Salvar o código imediatamente impede que chamadas posteriores para informar o erro ou liberar recursos substituam o motivo original. Um código salvo é útil mesmo que a mensagem final seja exibida muito mais tarde.

Escolha uma função de mensagem

perror(label) escreve em stderr o rótulo, dois-pontos e um espaço, a mensagem de erro atual e uma nova linha. Uma mensagem típica de arquivo ausente é "missing.txt: No such file or directory"; a redação exata depende do sistema.

strerror(code) retorna a mensagem da biblioteca para um código fornecido, portanto serve para um diagnóstico personalizado que indique o programa, a operação e o arquivo. Não modifique a cadeia retornada. Use strerror(saved) após a liberação de recursos em vez de consultar o novo valor de errno.

C define EDOM, ERANGE e EILSEQ. Códigos de arquivo comuns, como ENOENT, EACCES, EEXIST e ENOSPC, são fornecidos pelo POSIX e por bibliotecas C amplamente disponíveis. Ajuste seu código à interface e à plataforma de destino. Não suponha que valores numéricos de códigos ou o texto exato das mensagens em inglês sejam universais.

Trate um valor de retorno ambíguo

Para algumas funções, o resultado sozinho não consegue distinguir sucesso de um erro de faixa. strtol pode retornar LONG_MAX como número válido ou como resultado de estouro. Limpe errno antes da conversão e depois examine o código de faixa documentado:

errno = 0;
char *end;
long value = strtol(text, &end, 10);
if (end == text) {
    /* No digits were converted. */
} else if (errno == ERANGE) {
    /* The value is outside the long range. */
} else {
    /* Validate trailing characters and the target range. */
}

Um diagnóstico útil dá ao usuário informações para agir. Informe o arquivo e a ação tentada; preserve o motivo indicado pelo sistema quando estiver disponível. Envie-o para stderr, deixando stdout disponível para dados válidos de resultado.

Principais conclusões

  • Use o resultado da função para estabelecer a falha antes de interpretar errno.
  • Salve errno imediatamente, antes das chamadas para informar o erro ou liberar recursos.
  • perror usa o errno atual; strerror aceita um código salvo.
  • Redefina errno antes de strtol e verifique ERANGE.
  • Inclua o arquivo e a ação tentada em um diagnóstico.

5.3 Libere recursos e informe o resultado

O tratamento de erros só está completo quando os recursos são liberados e o programa informa o resultado real. Planeje a responsabilidade pela liberação ao abrir um fluxo e faça com que todos os caminhos posteriores respeitem esse plano.

Feche cada fluxo aberto uma vez

Se a abertura da entrada falhar, não há fluxo para fechar. Se a abertura da saída falhar após a entrada ter sido aberta com sucesso, feche a entrada. Se a cópia falhar depois que ambos forem abertos, feche os dois, verifique o fechamento da saída e mantenha um código de falha. Fechar um ponteiro duas vezes não é uma proteção adicional; isso usa um fluxo já encerrado.

Código com retorno antecipado geralmente fecha recursos na ordem inversa. Um rótulo compartilhado de liberação de recursos é útil quando vários caminhos de falha precisam do mesmo trabalho. Inicialize ponteiros com NULL, mantenha um código de falha por padrão e defina sucesso somente após o término da fase de processamento.

O programa completo a seguir copia arquivos distintos de entrada e saída em modo binário. Ele usa mensagens genéricas porque o padrão C não exige que toda falha de stdio forneça errno.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    FILE *in = NULL, *out = NULL;
    int status = EXIT_FAILURE;
    int output_acquired = 0;
    unsigned char buf[512];
    size_t n;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s input output\n", argv[0]);
        return EXIT_FAILURE;
    }
    in = fopen(argv[1], "rb");
    if (in == NULL) {
        fprintf(stderr, "Cannot open input: %s\n", argv[1]);
        goto cleanup;
    }
    out = fopen(argv[2], "wb");
    if (out == NULL) {
        fprintf(stderr, "Cannot open output: %s\n", argv[2]);
        goto cleanup;
    }
    output_acquired = 1;
    while ((n = fread(buf, 1, sizeof buf, in)) > 0) {
        if (fwrite(buf, 1, n, out) != n) {
            fprintf(stderr, "Write failed: %s\n", argv[2]);
            goto cleanup;
        }
    }
    if (ferror(in)) {
        fprintf(stderr, "Read failed: %s\n", argv[1]);
        goto cleanup;
    }
    status = EXIT_SUCCESS;

cleanup:
    if (out != NULL && fclose(out) == EOF) {
        fprintf(stderr, "Close failed: %s\n", argv[2]);
        status = EXIT_FAILURE;
    }
    if (in != NULL && fclose(in) == EOF) {
        fprintf(stderr, "Close failed: %s\n", argv[1]);
        status = EXIT_FAILURE;
    }
    if (output_acquired && status != EXIT_SUCCESS) {
        if (remove(argv[2]) != 0)
            fprintf(stderr, "Cannot remove incomplete output: %s\n",
                    argv[2]);
    }
    return status;
}

O laço de entrada processa apenas os bytes efetivamente lidos. Uma escrita incompleta salta para a liberação de recursos; um erro de entrada é verificado após o laço. O fechamento da saída ainda pode transformar o sucesso em falha. A remoção é tentada somente quando esta execução abriu a saída com sucesso, portanto uma falha de abertura não provoca a exclusão de um arquivo não relacionado. A exigência de arquivos distintos é importante: "wb" apagaria a entrada se os dois nomes identificassem o mesmo arquivo.

Preserve dados existentes importantes

Abrir diretamente a saída não permite desfazer o truncamento. Para substituir dados valiosos, grave primeiro sob um nome temporário separado. Verifique cada escrita e o fechamento final antes de renomear. Mantenha o original sob um nome de backup até que o novo arquivo esteja instalado; verifique cada chamada a rename e remove. Se a instalação falhar, informe a localização do arquivo recuperável em vez de excluí-lo.

Uma função auxiliar deve fechar o que abriu e retornar um resultado de sucesso ou falha à função chamadora. A função chamadora pode decidir se tentará novamente ou encerrará o programa. Retornar EXIT_FAILURE após qualquer etapa incompleta permite que um script pare antes de uma ação dependente, como excluir o original após um backup.

Principais conclusões

  • Inicialize a responsabilidade pelos fluxos e mantenha a falha como código padrão.
  • Feche cada fluxo aberto com sucesso exatamente uma vez em todos os caminhos.
  • Permita que uma falha no fechamento altere o código final.
  • Remova uma saída incompleta somente quando esta execução a tiver criado ou aberto.
  • Grave substituições separadamente e preserve o original até que a instalação seja bem-sucedida.
  • Funções auxiliares informam falhas às funções chamadoras para que elas escolham como se recuperar.

Exercícios resolvidos de Entrada e saída de arquivos em C

5 Lições Interativas

1

Abra um fluxo sem perder dados existentes

12 passos
Escolha um modo de arquivo, acompanhe a conversão de texto e conecte o mesmo código de processamento aos fluxos padrão.
  1. 1
    IntroduçãoDecida o que deve ser preservado

    Um programa está prestes a salvar resultados. Antes de abrir qualquer arquivo, decida se os dados antigos devem ser preservados e se o arquivo contém linhas legíveis ou bytes exatos. Essas escolhas determinam o modo, e uma escolha errada pode apagar dados antigos.

    Você acompanhará uma escrita desde o texto do programa até seu fluxo (o canal da biblioteca para um arquivo ou terminal) e depois escolherá para onde devem ir os resultados normais e os diagnósticos (os fluxos padrão). A abertura já é uma operação sobre o arquivo, portanto essa decisão vem antes da primeira escrita.

  2. 2
    ExplicaçãoAcesse dados por um fluxo

    Um fluxo é o canal da biblioteca padrão para um arquivo, terminal ou canal entre processos. Mantenha sua referência como um FILE * de <stdio.h> e passe-a a funções como fprintf.

    O objeto da biblioteca mantém o buffer, a posição e os indicadores de estado. Você não altera seus campos. A posição no arquivo avança conforme os dados são processados; um terminal ou canal entre processos não pode ser tratado como um arquivo comum para posicionamento.

  3. 3
    ExemploAcompanhe as novas linhas até os bytes armazenados

    Gravar "a\nb\nc\n" fornece três letras e três caracteres de nova linha. No Linux ou no macOS, o arquivo de texto contém seis bytes. No Windows, cada nova linha se torna CR LF, resultando em nove bytes armazenados.

    Ler esse arquivo do Windows em modo texto no Windows restaura seis caracteres. A entrada binária expõe todos os nove bytes. O texto do programa e a sequência de bytes armazenados são duas formas de representar as mesmas linhas.

  4. 4
    ConexãoEscolha um modo para uma imagem

    Uma sequência de bytes em uma imagem compactada pode conter valores que o modo texto converte. Acrescentar b seleciona o modo binário e preserva esses valores.

    Isso explica por que um leitor de imagens que funciona com "r" no Linux pode falhar no Windows. Ele deve usar "rb" porque manipula uma sequência definida de bytes, não linhas que a biblioteca deva converter.

  5. 5
    DesafioVerifique uma contagem de caracteres

    No Windows, uma escrita em modo texto armazena "m\nn\n". Quantos bytes o arquivo resultante contém e por quê?

    ---reveal---

    Ele contém seis bytes: duas letras mais dois pares CR LF. Os quatro caracteres fornecidos pelo programa aumentam porque cada nova linha se torna dois bytes armazenados. Em modo binário, esses mesmos quatro bytes fornecidos seriam gravados sem essa conversão.

  6. 6
    ExplicaçãoEscolha a preservação antes do acesso

    Para um arquivo existente, "r" permite leitura, "w" apaga e permite escrita, e "a" mantém os dados e acrescenta ao fim. Um + permite entrada e saída.

    Use "r+" para preservar um arquivo existente durante atualizações. "w+" ainda o apaga. "wx" do C11 falha se o arquivo existir, o que é útil quando um destino existente precisa ser protegido.

  7. 7
    DicaObtenha e libere um fluxo

    Após FILE *fp = fopen(name, "r");, teste fp == NULL antes de qualquer operação de fluxo. Em caso de falha, não há fluxo para processar ou fechar.

    Em caso de sucesso, o programa é responsável por um fluxo que precisa de uma chamada a fclose. Verifique também esse fechamento. O fluxo está encerrado após a chamada mesmo quando o fechamento falha; tentar fechá-lo novamente usa um fluxo que não é mais válido.

  8. 8
    DesafioProteja o registro de eventos antigo

    Um arquivo de registro de eventos existente deve manter suas entradas, e uma nova linha deve ser acrescentada. Um estudante escolhe "w" porque a tarefa grava dados. Qual modo deve ser usado e quando "w" destruiria as entradas antigas?

    ---reveal---

    Use "a". O modo "w" destrói o conteúdo existente assim que a abertura tem sucesso, mesmo antes de uma escrita. A escolha deve proteger o arquivo durante a abertura, não apenas durante o código de processamento posterior.

  9. 9
    ExplicaçãoSepare resultados de explicações

    Os fluxos já abertos são stdin para entrada, stdout para resultados e stderr para diagnósticos. Uma função que aceita FILE *out pode gravar o mesmo formato em um arquivo ou em stdout.

    Um shell pode redirecionar a saída padrão para um arquivo ou enviá-la por um canal a outro programa. Mantenha o texto de diagnóstico em stderr, para que um resultado legível por máquina não receba mensagens de erro entre suas linhas de dados.

  10. 10
    Ideia-chaveFaça o texto armazenado em buffer aparecer

    A saída pode esperar em um buffer na memória. A saída padrão para terminal costuma ser armazenada em buffer por linha; a saída redirecionada costuma ser totalmente armazenada em buffer. A saída de erro padrão não é totalmente armazenada em buffer.

    Uma mensagem sem nova linha pode precisar de fflush(stdout) com verificação antes de a entrada começar. Descarregar o buffer não descarta a entrada. Para pular uma linha de entrada indesejada, consuma caracteres até sua nova linha ou o fim do arquivo.

  11. 11
    DesafioAcompanhe a saída de um filtro

    Um filtro lê a entrada padrão, grava resultados na saída padrão e grava erros na saída de erro padrão. Ele é executado como filter < raw.txt > clean.txt. Onde deve aparecer uma mensagem sobre um registro rejeitado e que código ele deve retornar se não conseguir concluir o trabalho?

    ---reveal---

    O diagnóstico vai para o destino de erro herdado, geralmente o terminal. Retorne EXIT_FAILURE. O arquivo de resultados permanece separado da mensagem, e o shell pode detectar a falha.

  12. 12
    RecapitulaçãoUse um ciclo de vida planejado para o fluxo

    Escolha a preservação e o comportamento de texto ou binário antes de abrir. Verifique se a abertura produziu um fluxo, processe apenas por meio de ponteiros válidos e feche uma vez cada fluxo sob sua responsabilidade.

    Os fluxos padrão permitem que o shell forneça as conexões. Separe resultados de diagnósticos e retorne um código que descreva o resultado do trabalho. Essas escolhas permitem que o mesmo programa pequeno funcione interativamente, com arquivos ou dentro de uma sequência de programas conectados por canais.

2

Leia um registro de texto e valide seu conteúdo

15 passos
Passe de leituras de caracteres a valores formatados e linhas completas, tratando limites que causam erros comuns de entrada.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoLeia na escala adequada
  2. 2
    ExplicaçãoMantenha um caractere distinto de EOF
  3. 3
    ExemploConte apenas uma leitura bem-sucedida
  4. 4
    DesafioInclua a linha final sem nova linha
  5. 5
    ExemploEscreva em um formato controlado
  6. 6
    DicaReserve espaço para o terminador da cadeia
  7. 7
    ExplicaçãoUse a contagem de atribuições
  8. 8
    DesafioEscolha um nome formatado com limite
  9. 9
    ExplicaçãoLeia uma linha em um espaço de capacidade conhecida
  10. 10
    ExemploAcompanhe uma linha em duas leituras
  11. 11
    DicaRemova o final sem remover dados
  12. 12
    ExplicaçãoAnalise a linha já lida
  13. 13
    DesafioAceite uma linha que cabe exatamente
  14. 14
    DesafioRejeite um prefixo com sufixo inválido
  15. 15
    RecapitulaçãoMantenha leitura e interpretação separadas
3

Transfira bytes e defina seu significado

12 passos
Copie corretamente um bloco final incompleto e depois decodifique registros usando um leiaute binário explícito.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoSepare bytes de valores
  2. 2
    ExplicaçãoEscolha o que o retorno conta
  3. 3
    ExemploAcompanhe o bloco final incompleto
  4. 4
    Ideia-chaveDistinga um registro de um bloco de bytes
  5. 5
    DesafioUse a contagem obtida
  6. 6
    ExplicaçãoNão deixe o compilador definir o formato
  7. 7
    ExemploDecodifique um valor com o byte menos significativo primeiro
  8. 8
    ExemploLocalize um registro a partir de seu leiaute
  9. 9
    DesafioVerifique a quantidade declarada de dados
  10. 10
    ConexãoSiga a estrutura permitida pelo formato
  11. 11
    DesafioExija um campo completo antes de decodificar
  12. 12
    RecapitulaçãoFaça a transferência corresponder ao formato
4

Encontre um registro e substitua-o com segurança

13 passos
Calcule um deslocamento, preserve uma posição salva e siga as regras de fluxos de atualização ao substituir um registro.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoAcesse diretamente os dados necessários
  2. 2
    ExplicaçãoSelecione um ponto de referência
  3. 3
    ExemploLocalize o registro de índice 3
  4. 4
    DicaRestaure posições em texto como valores salvos
  5. 5
    DesafioEncontre o terceiro registro
  6. 6
    ExplicaçãoPreserve o arquivo existente
  7. 7
    ExemploRestaure o início do registro
  8. 8
    Ideia-chaveConclua a substituição
  9. 9
    DesafioEscolha o modo e o posicionamento
  10. 10
    ConexãoRegrave quando um registro aumentar
  11. 11
    DicaMantenha a instalação recuperável
  12. 12
    DesafioInterprete um acréscimo concluído
  13. 13
    RecapitulaçãoO posicionamento faz parte de uma atualização válida
5

Mantenha a falha no resultado ao informar erros e liberar recursos

12 passos
Diagnostique a conclusão da entrada, preserve o erro original e faça falhas tardias de saída alterarem o resultado final.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoO sucesso inclui o fechamento final
  2. 2
    ExplicaçãoLeia o resultado de cada função
  3. 3
    ExplicaçãoExplique por que a entrada parou
  4. 4
    DesafioRejeite um cabeçalho truncado
  5. 5
    ExplicaçãoRegistre o motivo original
  6. 6
    ExemploExiba uma mensagem a partir do código salvo
  7. 7
    DesafioEscolha a fonte correta do diagnóstico
  8. 8
    ExplicaçãoAcompanhe quais fluxos foram obtidos
  9. 9
    ExemploPermita que a liberação de recursos altere o sucesso
  10. 10
    DesafioDecida a próxima ação de um script
  11. 11
    Ideia-chaveMantenha o original após uma falha de renomeação
  12. 12
    RecapitulaçãoRetorne o resultado do trabalho completo

Questões de Entrada e saída de arquivos em C

40 Questões de Prática em 4 conjuntos

Conjunto 1: Escolha fluxos e processe entradas completas10 Questões de Prática

Questão 1 de 10

Uma chamada bem-sucedida a fwrite(a, 4, 7, fp) grava todos os elementos solicitados. O que ela retorna?
  1. 4
  2. 28
  3. 7
  4. 1
Mostrar respostaOcultar resposta
Resposta: C
fwrite retorna o número de elementos completos gravados, portanto retorna 7. A transferência abrange 28 bytes porque cada elemento tem tamanho 4, mas esse total de bytes não é o valor de retorno. Contagens de bytes e de elementos coincidem apenas quando o tamanho do elemento é 1.

Questão 2 de 10

Um campo de 32 bits na ordem do byte menos significativo primeiro contém os bytes de oito bits 07 02 00 00. Que valor ele representa?
  1. 1794
  2. 7
  3. 131079
  4. 519
Mostrar respostaOcultar resposta
Resposta: D
A ordem do byte menos significativo primeiro dá ao primeiro byte peso 1 e ao segundo peso 256, produzindo 7 mais 512, ou 519. Ler 07 02 como um par com o byte mais significativo primeiro daria 1794. A ordem dos bytes da própria máquina não altera a interpretação especificada pelo formato do arquivo.

Questão 3 de 10

Qual modo lê um arquivo compactado sem conversão de texto?
  1. "r"
  2. "rb"
  3. "wb"
  4. "ab"
Mostrar respostaOcultar resposta
Resposta: B
"rb" abre um arquivo existente para entrada binária, preservando seus bytes armazenados. "r" seleciona o modo texto, que pode converter finais de linha e reconhecer Ctrl+Z como fim da entrada no Windows. Os modos de escrita não fornecem o acesso de leitura solicitado.

Questão 4 de 10

Um programa deve acrescentar uma nova entrada a um arquivo de registro de eventos existente, mantendo as entradas anteriores. Qual modo de abertura é adequado?
  1. "w"
  2. "r"
  3. "w+"
  4. "a"
Mostrar respostaOcultar resposta
Resposta: D
O modo de acréscimo mantém o conteúdo existente e coloca cada escrita no fim. O modo "w" apagaria as entradas anteriores assim que a abertura tivesse sucesso. O modo "r" preserva os dados, mas não permite gravar a nova entrada; "w+" permite entrada e saída, mas ainda apaga o arquivo.

Questão 5 de 10

fgets lê com sucesso a última linha, que contém "maple" sem nova linha. O que line[strlen(line) - 1] = '\0'; deixa?
  1. "mapl"
  2. "maple"
  3. "maple\n"
  4. "map"
Mostrar respostaOcultar resposta
Resposta: A
O código sempre substitui o último caractere armazenado, portanto remove o e de "maple". fgets não inventa uma nova linha quando o arquivo não tem uma. Localize CR ou LF com strcspn antes de remover o final, para que uma linha final sem terminador mantenha todos os seus dados reais.

Questão 6 de 10

Em um sistema com char de oito bits com sinal, um arquivo binário começa com o byte 0xFF e contém mais dados. Por que char c; while ((c = fgetc(fp)) != EOF) pode parar imediatamente?
  1. O modo binário converte 0xFF em fim de arquivo.
  2. A atribuição compara antes de armazenar o byte.
  3. O byte pode se tornar -1 ao ser convertido em char.
  4. A primeira leitura bem-sucedida ativa o indicador EOF.
Mostrar respostaOcultar resposta
Resposta: C
fgetc retorna o byte como um int não negativo, mas armazená-lo em um char de oito bits com sinal pode transformar 255 em -1. Esse valor pode ser comparado como igual ao EOF da implementação, interrompendo o laço antes dos bytes posteriores. Os parênteses estão corretos aqui; o tipo de destino mais estreito causa o problema.

Questão 7 de 10

Um relatório é redirecionado para um arquivo. Qual fluxo deve levar uma mensagem explicando que um registro de entrada é inválido?
  1. stderr
  2. stdout
  3. stdin
  4. O fluxo de saída do relatório
Mostrar respostaOcultar resposta
Resposta: A
stderr mantém os diagnósticos separados dos dados do relatório enviados a stdout. Exibir a mensagem em stdout a colocaria dentro do relatório redirecionado e poderia comprometer o formato esperado. A entrada padrão fornece dados para leitura; ela não é o destino de um diagnóstico.

Questão 8 de 10

Dado char tag[14]; int count;, qual chamada lê com segurança uma palavra e um inteiro para esses objetos?
  1. fscanf(fp, "%14s %d", tag, &count)
  2. fscanf(fp, "%13s %d", tag, &count)
  3. fscanf(fp, "%13s %d", tag, count)
  4. fscanf(fp, "%14s %d", tag, count)
Mostrar respostaOcultar resposta
Resposta: B
A conversão da palavra deve permitir no máximo 13 caracteres para que o arranjo de 14 bytes mantenha um byte para seu terminador nulo. A conversão do inteiro também exige &count, um ponteiro para o destino. A largura 14 corresponde ao tamanho do arranjo, mas permite um caractere de entrada a mais do que o arranjo pode armazenar com segurança junto com o terminador.

Questão 9 de 10

Um arquivo binário tem um cabeçalho de 12 bytes e registros de 20 bytes. Após se posicionar no byte 12, um programa lê dois registros completos. Qual chamada relativa a fseek seleciona agora o quarto registro contado a partir de 1?
  1. fseek(fp, 40L, SEEK_CUR)
  2. fseek(fp, 60L, SEEK_CUR)
  3. fseek(fp, 20L, SEEK_CUR)
  4. fseek(fp, 72L, SEEK_CUR)
Mostrar respostaOcultar resposta
Resposta: C
As duas leituras movem a posição do byte 12 para o byte 52. O quarto registro tem índice 3, portanto seu início é o byte 72, após o cabeçalho e três registros anteriores; avançar 20 bytes leva até ele. Passar 72 com SEEK_CUR somaria essa posição absoluta à posição atual em vez de selecioná-la.

Questão 10 de 10

Um cabeçalho obrigatório de 16 bytes é lido com fread(&h, 16, 1, fp). A chamada retorna 0, ferror(fp) é zero e feof(fp) é diferente de zero. Como o leitor deve proceder?
  1. Rejeitar o cabeçalho incompleto sem interpretar seus campos.
  2. Interpretar o cabeçalho porque não houve erro de fluxo.
  3. Repetir a leitura do cabeçalho sem alterar o estado do fluxo.
  4. Limpar os indicadores e aceitar os campos preenchidos com zeros.
Mostrar respostaOcultar resposta
Resposta: A
Nenhum cabeçalho completo chegou, e os indicadores mostram fim de arquivo, não erro de acesso ao fluxo. Portanto, faltam dados obrigatórios do formato no arquivo, embora o mecanismo de leitura não tenha falhado. O objeto pode conter um elemento parcial com valor indeterminado, portanto a ausência de ferror não torna seguro interpretar seus campos.
Conjunto 2: Trate limites de texto e leiautes binários10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um programa é iniciado em /work/run e abre "data/items.txt". Qual caminho é resolvido?
  1. /work/data/items.txt
  2. /work/run/items.txt
  3. /work/run/data/items.txt
  4. O caminho ao lado do arquivo-fonte
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

No comando de shell producer | consumer > result.txt, para onde vai a saída de erro padrão do produtor por padrão?
  1. Para a entrada padrão do consumidor
  2. Para seu destino de erro herdado
  3. Para result.txt com os resultados
  4. Para a entrada padrão do produtor
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um arquivo de 1540 bytes é copiado com um buffer de 600 bytes e fread(buf, 1, 600, in). Que tamanhos as escritas bem-sucedidas devem usar?
  1. 600, 600, 340
  2. 600, 600, 600
  3. 600, 340, 600
  4. 600, 600, 0
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

char name[8]; recebe snprintf(name, sizeof name, "part-%d", 2468), que retorna 9. O que o programa deve concluir?
  1. O destino agora contém o nome completo.
  2. O nome de nove caracteres cabe no buffer.
  3. Nove bytes armazenados incluem o terminador nulo.
  4. O resultado foi truncado e precisa ser tratado.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Um validador permite no máximo sete caracteres de conteúdo por linha. Um arquivo sem erros contém "cedars\nmaplesx". Ele chama repetidamente fgets(buf, 8, fp). Quais limites de registro deve reconhecer?
  1. Um registro válido formado pela união das duas partes.
  2. Um registro válido: “cedars”; rejeitar “maplesx”.
  3. Dois registros válidos: “cedars” e “maples”.
  4. Dois registros válidos: “cedars” e “maplesx”.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Uma entrada sem erros contém "north\nsouth\neast". Quantas linhas e caracteres de nova linha ela contém?
  1. 3 linhas e 3 novas linhas
  2. 2 linhas e 2 novas linhas
  3. 3 linhas e 2 novas linhas
  4. 2 linhas e 3 novas linhas
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Dois sistemas fornecem uint32_t, mas diferem na ordem dos bytes e no preenchimento de alinhamento de estruturas. Um programa que grava um formato copia struct { char kind; uint32_t count; } diretamente com uma chamada a fwrite. Que reformulação torna a representação independente de ambas as diferenças?
  1. Codificar os campos definidos individualmente em uma ordem de bytes escolhida.
  2. Substituir o membro por um unsigned int simples.
  3. Gravar sizeof no cabeçalho e manter a cópia direta.
  4. Manter a estrutura e abrir o arquivo com "wb".
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

A posição de um fluxo de texto foi salva por long p = ftell(fp); e verificada. Após mais leituras, qual chamada válida retorna a ela?
  1. fseek(fp, p, SEEK_CUR)
  2. fseek(fp, p, SEEK_SET)
  3. fseek(fp, p + 1, SEEK_SET)
  4. fseek(fp, -p, SEEK_END)
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um arquivo binário tem um cabeçalho de 8 bytes e cinco registros de 16 bytes. Um fluxo "r+b" posiciona-se no byte 40 e lê um registro completo sem chegar a EOF. Um campo é alterado. Qual operação antes da escrita permite a alternância e seleciona esse mesmo registro?
  1. fseek(fp, -16L, SEEK_CUR), movendo para o byte 40.
  2. fseek(fp, 0L, SEEK_CUR), permanecendo no byte 56.
  3. fseek(fp, 24L, SEEK_SET), movendo para o byte 24.
  4. fflush(fp), deixando a posição no byte 56.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Uma chamada de biblioteca malsucedida define errno. O programa deve fechar outro fluxo antes de informar a causa original. O que ele deve preservar primeiro?
  1. O comprimento atual do buffer de saída
  2. O próximo ponteiro de fluxo disponível
  3. O valor atual de errno
  4. O resultado de uma nova chamada bem-sucedida
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 3: Atualize registros e preserve resultados confiáveis10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um arquivo binário sem erros tem 27 bytes. Duas chamadas usam fread(b, 16, 1, fp) com um arranjo de 16 bytes. O que a segunda chamada retorna e como seu elemento pode ser usado?
  1. 11; seus onze bytes formam um elemento completo.
  2. 1; os cinco bytes ausentes são preenchidos com zeros.
  3. 0; seu valor parcial pode servir como o próximo registro.
  4. 0; o elemento parcial não deve ser interpretado.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

No Windows com bytes de oito bits, "x\ny\n" é gravado em modo texto. Quantos bytes são armazenados como resultado?
  1. 4
  2. 6
  3. 8
  4. 5
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um programa C11 deve criar uma nova exportação binária, mas precisa preservar qualquer arquivo existente com esse nome. Qual modo é adequado?
  1. "wb"
  2. "ab"
  3. "r+b"
  4. "wbx"
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um formato tem um cabeçalho de 8 bytes e registros de exatamente 18 bytes. Seu campo de contagem indica 6 registros, mas o arquivo completo tem apenas 98 bytes. O que um leitor deve concluir antes de alocar espaço para esses registros?
  1. O arquivo não pode fornecer os seis registros que declara.
  2. A contagem é válida porque o cabeçalho está completo.
  3. O arquivo contém seis registros após arredondar o comprimento.
  4. O registro final pode ser completado com bytes zero.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Uma linha completa "64km" é passada a strtol após errno ser limpo. O retorno é 64, errno permanece 0 e end aponta para k. O campo deve ser um número inteiro completo, com caracteres de espaço em branco opcionais ao final. Qual é a decisão correta?
  1. Aceitar porque errno permaneceu zero.
  2. Aceitar após descartar as duas letras.
  3. Rejeitar porque resta texto que não é espaço em branco.
  4. Rejeitar porque nenhum prefixo numérico foi encontrado.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

A entrada é "18 pear 26". Após uma chamada bem-sucedida a fscanf(fp, "%d", &n), a mesma chamada retorna 0 duas vezes. Por que ela não chegou a 26?
  1. A primeira leitura consumiu automaticamente os três campos.
  2. A palavra que não corresponde permanece sem leitura na próxima conversão.
  3. A segunda leitura chegou a EOF e eliminou a palavra.
  4. O destino inteiro precisa ser alterado para double.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Que valor indica que fseek falhou?
  1. Um resultado diferente de zero
  2. O novo deslocamento em bytes
  3. Sempre exatamente EOF
  4. Sempre exatamente -1L
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Um arquivo binário que permite posicionamento contém um cabeçalho de 10 bytes e quatro registros de 14 bytes. Um leitor em "r+b" posiciona-se no byte 38 e lê um registro completo sem chegar a EOF. Ele altera um campo. Qual operação seguinte seleciona o mesmo registro e permite a escrita da substituição?
  1. fflush(fp)
  2. fseek(fp, 0L, SEEK_CUR)
  3. fseek(fp, 38L, SEEK_SET)
  4. fseek(fp, 52L, SEEK_SET)
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Todas as escritas de saída retornaram as contagens esperadas, mas fclose(out) retorna EOF. Que resultado o programa deve informar?
  1. Sucesso, porque todos os dados chegaram ao buffer de escrita.
  2. Sucesso, após chamar fclose novamente no mesmo fluxo.
  3. Falha, somente se feof(out) também estiver ativado.
  4. Falha, porque a saída armazenada em buffer pode estar incompleta.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

A entrada é aberta com sucesso e, em seguida, a abertura da saída retorna NULL. O que esse caminho deve fazer antes de retornar falha?
  1. Fechar a entrada uma vez e informar a falha de abertura da saída.
  2. Fechar ambos os ponteiros, incluindo o ponteiro nulo de saída.
  3. Remover o caminho da saída mesmo que ela não tenha sido aberta.
  4. Retornar imediatamente e deixar a entrada aberta para a função chamadora.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 4: Diagnostique falhas em um fluxo completo de trabalho com arquivos10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um programa lê no Linux uma linha criada no Windows e remove apenas seu LF. A comparação do resultado com "ready" falha, embora as letras visíveis correspondam. Que caractere mantido explica isso?
  1. Uma tabulação antes das letras
  2. Um CR antes do LF removido
  3. Um segundo terminador nulo
  4. Um byte EOF armazenado por fgets
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um programa deve acrescentar sua saída normal a um arquivo do shell chamado totals.txt. Qual operador de redirecionamento é necessário?
  1. < totals.txt
  2. 2> totals.txt
  3. > totals.txt
  4. >> totals.txt
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um arquivo tem três registros de 12 bytes com pontuações 10, 20 e 30. No modo "a+b", um programa posiciona-se no byte 12, lê um registro, altera sua pontuação para 25, volta ao byte 12 e grava o registro. Todas as chamadas têm sucesso. Quais são as pontuações do segundo e do último registro depois disso?
  1. Segundo: 20; último: 25; quatro registros no total.
  2. Segundo: 25; último: 30; três registros no total.
  3. Segundo: 25; último: 25; quatro registros no total.
  4. Segundo: 20; último: 30; três registros no total.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Registros de números inteiros podem conter no máximo sete caracteres de conteúdo. Com char buf[8], as leituras retornam "8642kg\n" e depois "1234567"; a próxima leitura verificada confirma EOF normal. strtol encontra 8642 seguido de kg no primeiro registro e converte todos os dígitos no segundo, sem erros de faixa. Quais registros são válidos?
  1. Aceitar ambos os prefixos numéricos completos.
  2. Rejeitar ambos por serem longos demais para o buffer.
  3. Rejeitar o primeiro; aceitar o segundo.
  4. Aceitar apenas o primeiro, que termina em LF.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Uma substituição é gravada e fechada por completo. A renomeação do original para um backup tem sucesso; a instalação da substituição falha porque seu destino agora está ocupado. Qual ação preserva o original sem sobrescrever o novo ocupante?
  1. Excluir o backup, manter a substituição e retornar falha.
  2. Manter o backup e a substituição, informar a falha e resolver o conflito de nomes antes de tentar novamente.
  3. Renomear o backup para o nome ocupado sem verificar o resultado.
  4. Remover imediatamente o destino ocupado e tentar a instalação novamente.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um arquivo sem erros contém "a\nb". Um programa usa int c; size_t n = 0, lines = 0; while (c = fgetc(in) != EOF) { ++n; if (c == '\n') ++lines; }. Quais totais resultam e que correção faz a contagem de linhas ficar correta?
  1. n = 4, lines = 0; testar feof antes de ler e contar a linha final.
  2. n = 3, lines = 1; corrigir os parênteses da atribuição sem tratar a linha final.
  3. n = 3, lines = 0; corrigir os parênteses da atribuição e contar a linha final sem nova linha.
  4. n = 2, lines = 1; manter a condição e mudar c de int para char.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Uma leitura com tamanho de elemento 1 solicita um cabeçalho obrigatório de 12 bytes, mas obtém 9 bytes. feof está ativado e ferror está desativado. Em seguida, um fseek para o início tem sucesso. O que continua verdadeiro e o que o analisador deve fazer?
  1. EOF está desativado; rejeitar o cabeçalho incompleto, a menos que uma nova tentativa completa tenha sucesso.
  2. EOF permanece ativado; limpar ambos os indicadores e decodificar os nove bytes.
  3. O cabeçalho ficou completo; decodificá-lo após verificar feof novamente.
  4. O indicador de erro agora está ativado; informar uma nova falha de posicionamento.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Uma abertura de entrada falha e seu errno é salvo como open_error. O fechamento de uma saída aberta anteriormente falha em seguida e fornece um código diferente, salvo como close_error. Como um diagnóstico deve preservar ambas as falhas?
  1. Descrever ambas as operações com strerror(close_error); o código mais recente substitui as causas anteriores.
  2. Descrever a abertura com perror após liberar recursos e omitir o diagnóstico do fechamento como redundante.
  3. Descrever o erro de abertura salvo, mas retornar sucesso se a liberação de recursos chegar à última instrução.
  4. Descrever a abertura com strerror(open_error) e o fechamento com strerror(close_error); retornar falha.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

fopen retorna um fluxo válido, mas errno ainda contém um valor anterior diferente de zero. O que esse valor estabelece sobre essa abertura?
  1. O fluxo deve ser fechado como uma abertura malsucedida.
  2. Ele não estabelece falha nessa abertura bem-sucedida.
  3. A próxima leitura certamente falhará imediatamente.
  4. O arquivo foi aberto com um modo de acesso incorreto.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Uma cópia obteve fluxos distintos de entrada e saída. A entrada informa um erro de leitura; a liberação de recursos fecha então a saída, que retorna EOF. A entrada ainda está aberta, e a saída está incompleta. Quais ações restantes e qual resultado protegem a origem e liberam os recursos?
  1. Tentar fechar a saída novamente, fechar a entrada uma vez, remover a saída incompleta, preservar a origem e retornar falha.
  2. Fechar a entrada uma vez, remover a saída incompleta, preservar a origem e retornar sucesso se a liberação de recursos tiver sucesso.
  3. Limpar o erro de leitura, fechar a entrada uma vez, manter ambos os arquivos e retornar sucesso se o último fechamento tiver sucesso.
  4. Fechar a entrada uma vez, tentar remover a saída incompleta com verificação, preservar a origem e retornar falha.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Travou em uma questão sua? Ajuda com Tarefas

Termos-Chave

61 Termos-Chave, cada um com sua definição

A

Acesso aleatório
O acesso aleatório é a movimentação direta para um local escolhido em um arquivo que permite posicionamento, sem ler todos os dados anteriores.
Um cabeçalho e uma largura fixa de registro permitem que um programa calcule onde começa um registro selecionado.
Análise de linha
A análise de linha consiste em interpretar os campos de uma linha completa de entrada após essa linha ter sido lida para a memória.
Uma quantidade inválida pode ser informada com seu número de linha antes da leitura do próximo registro.
Armazenamento em buffer
O armazenamento em buffer é o agrupamento temporário de dados na memória para que muitas solicitações pequenas de entrada e saída compartilhem transferências maiores.
Um relatório pode permanecer no buffer de saída até que o fluxo seja descarregado ou fechado.
Assinatura de arquivo
Uma assinatura de arquivo é uma sequência definida de bytes iniciais que ajuda um leitor a identificar um formato ou versão de arquivo.
O marcador de início JPEG ajuda a localizar imagens candidatas antes da verificação da estrutura restante.
Atualização no próprio local
Uma atualização no próprio local substitui dados dentro de seu espaço existente no arquivo sem deslocar ou regravar os registros seguintes.
Um registro alterado de tamanho fixo deve ser gravado de volta em sua posição inicial original.

C

Cabeçalho
Um cabeçalho é uma parte inicial de um arquivo que contém campos de identificação e estrutura necessários para interpretar os dados seguintes.
Verifique a assinatura e a contagem completas antes de confiar nos registros indicados por um cabeçalho.
Caminho de liberação de recursos
Um caminho de liberação de recursos é o percurso do fluxo de controle que libera recursos obtidos antes de se determinar o sucesso ou a falha.
Um rótulo pode fechar os fluxos abertos após várias falhas diferentes de processamento.
Canal entre processos
Um canal entre processos conecta a saída padrão de um programa à entrada padrão de outro como um fluxo de dados.
Um gerador pode alimentar um programa de ordenação diretamente, sem primeiro salvar um arquivo intermediário.
clearerr
clearerr limpa os indicadores de fim de arquivo e de erro de um fluxo sem corrigir a causa de qualquer falha.
Após resolver um problema de entrada, um programa pode limpar os indicadores antes de uma nova tentativa controlada.
Código de saída
Um código de saída é o resultado que um programa retorna ao ambiente para que scripts possam distinguir uma execução bem-sucedida de uma malsucedida.
Um comando dependente após && não deve ser executado depois de uma cópia de arquivo incompleta.
Contagem de atribuições
Uma contagem de atribuições é o número de valores que uma chamada de entrada formatada armazena com sucesso nos destinos.
Um registro de dois campos lido por fscanf só está completo quando a contagem de atribuições retornada é 2.
Cópia em blocos
Uma cópia em blocos transfere um arquivo por meio de um buffer reutilizável, gravando apenas os bytes fornecidos por cada leitura bem-sucedida.
Uma leitura final incompleta deve produzir uma escrita final menor para que dados restantes do buffer não sejam acrescentados.
Criação exclusiva
A criação exclusiva é a abertura de um novo arquivo somente se seu nome ainda não identificar um arquivo existente.
O modo "wx" do C11 protege um relatório existente contra exclusão pela abertura.

D

Delimitação de campos CSV com aspas
A delimitação de campos CSV com aspas envolve campos de texto que contêm vírgulas, aspas ou novas linhas e duplica as aspas internas.
Um nome de cidade que contém uma vírgula deve permanecer como um único campo quando o registro for lido novamente.
Devolução de caractere ao fluxo
A devolução de caractere ao fluxo consiste em devolver um caractere a um fluxo de entrada para que a próxima leitura o obtenha novamente.
Um analisador pode examinar um separador e usar ungetc para deixá-lo para a próxima etapa.
Diretório de trabalho atual
O diretório de trabalho atual é a pasta de referência do programa em execução para resolver nomes de caminhos relativos.
Iniciar um programa em outra pasta muda o arquivo identificado por "data/input.txt".

E

Elemento parcial
Um elemento parcial é uma unidade incompleta do tamanho de um objeto obtida por uma leitura e omitida da contagem de elementos completos de fread.
Em uma entrada com tamanho de registro, bytes restantes no fim não podem ser tratados como um registro válido.
Entrada padrão
A entrada padrão é o fluxo já aberto stdin, pelo qual um programa normalmente recebe sua entrada principal.
Com < values.txt, um filtro lê dados de um arquivo por stdin em vez do teclado.
EOF
EOF é uma constante inteira negativa usada por funções de entrada de caracteres quando a entrada termina ou ocorre um erro de leitura.
Mantenha o valor retornado em um int para que um byte real não seja confundido com esse marcador.
ERANGE
ERANGE é o código padrão de erro de faixa usado quando uma conversão ou cálculo produz um valor fora da faixa suportada.
Limpe errno antes de strtol para que um erro de faixa antigo não seja confundido com um novo.
errno
errno é uma expressão inteira modificável de código de erro cujo significado depende do comportamento de erro documentado de uma função.
Salve seu valor imediatamente após uma falha informada, antes que outra chamada de biblioteca possa alterá-lo.
Especificação de conversão
Uma especificação de conversão é uma instrução iniciada por um sinal de porcentagem que seleciona como a entrada e saída formatada exibe ou converte um valor.
Na entrada, %lf exige um destino double *, enquanto %f exige um destino float *.

F

Falha de correspondência
Uma falha de correspondência ocorre quando caracteres de entrada não se ajustam a uma conversão formatada solicitada, sem que seja necessário um erro de entrada e saída.
Ler um inteiro de "oak" pode retornar 0 enquanto os indicadores de fim de arquivo e de erro do fluxo permanecem desativados.
fclose
fclose é a função que descarrega a saída pendente, fecha um fluxo e informa sucesso com 0 ou falha com EOF.
Depois que fclose(fp) retorna, mesmo com erro, esse fluxo não pode ser usado novamente.
fgetc
fgetc é a função que lê um caractere como um valor de caractere sem sinal convertido para int, ou retorna EOF.
Um laço conta um separador somente após fgetc retornar um caractere com sucesso.
fgets
fgets lê uma sequência limitada de caracteres, mantém uma nova linha encontrada e acrescenta um terminador nulo em caso de sucesso.
Uma linha maior que um buffer de 32 bytes é retornada em várias leituras bem-sucedidas.
Fluxo
Um fluxo é um canal da biblioteca padrão que conecta um programa a uma sequência de caracteres de entrada ou saída.
Um leitor pode processar um arquivo em disco ou a entrada do terminal pela mesma interface de fluxo.
Fluxo de atualização
Um fluxo de atualização é um fluxo aberto com um modo +, permitindo entrada e saída sob regras de alternância.
Abrir um arquivo existente de registros binários com "r+b" preserva-o para acesso de leitura e escrita.
fopen
fopen é a função da biblioteca padrão que abre um arquivo indicado em um modo selecionado e retorna um ponteiro de fluxo ou NULL.
Uma abertura para leitura malsucedida não deixa um fluxo válido para uma chamada posterior a fgetc ou fclose.
fpos_t
fpos_t é o tipo opaco usado por fgetpos e fsetpos para salvar e restaurar todas as informações necessárias de posição no arquivo.
Um valor salvo é restaurado pelas funções da biblioteca, sem operações aritméticas sobre ele.
fputc
fputc é a função que grava um caractere em um fluxo e retorna o valor desse caractere ou EOF em caso de falha.
Um filtro que converte letras em maiúsculas verifica cada chamada a fputc após transformar o caractere lido.
fread
fread transfere bytes de entrada para a memória e retorna o número de elementos completos obtidos para o tamanho e a quantidade solicitados.
Uma leitura incompleta de registro deve ser verificada antes de qualquer campo do registro ser interpretado.
fseek
fseek solicita uma nova posição no arquivo em relação ao início, à posição atual ou ao fim, retornando um valor diferente de zero em caso de falha.
Um programa verifica o posicionamento antes de ler o registro esperado no deslocamento solicitado.
ftell
ftell informa a posição de um fluxo como long, retornando -1L em caso de falha; uma posição em texto deve ser tratada como um local salvo.
Um leitor de registros binários pode verificar sua posição após consumir um registro completo de tamanho fixo.
fwrite
fwrite transfere bytes de objetos da memória para um fluxo e retorna o número de elementos completos gravados.
Gravar um arranjo exige o endereço de seus dados, o tamanho do elemento e a quantidade pretendida de elementos.

I

Indicador de erro
O indicador de erro registra uma falha de leitura ou escrita do fluxo e permanece ativado até ser explicitamente limpo.
Após fgets retornar NULL, ferror pode distinguir uma falha de acesso da conclusão normal.
Indicador de fim de arquivo
O indicador de fim de arquivo registra que uma operação de entrada anterior encontrou o fim do fluxo.
Ele é verificado após a leitura; testá-lo primeiro não pode prever se o próximo byte existe.

L

Largura de campo
Uma largura de campo controla uma largura mínima de saída ou uma largura máxima de entrada, dependendo da função de entrada e saída formatada.
Na entrada, %23s deixa espaço para um terminador em um arranjo de caracteres de 24 bytes.

M

Modo binário
O modo binário é o acesso a um fluxo que preserva os valores dos bytes sem as conversões de caracteres usadas para texto.
Abra uma imagem com "rb" para que a conversão de texto não possa alterar seus bytes compactados.
Modo de abertura
Um modo de abertura é uma cadeia de caracteres que informa a fopen qual acesso é permitido e se o conteúdo existente é mantido ou apagado.
Escolher "a" preserva entradas anteriores de um registro de eventos e coloca cada nova escrita no fim.
Modo de acréscimo
O modo de acréscimo é um acesso que força cada operação de saída a ocorrer no fim atual do arquivo, independentemente de posicionamentos anteriores.
Posicionar no byte zero em um fluxo "a+b" pode selecionar a entrada, mas não pode redirecionar a próxima escrita.
Modo texto
O modo texto é o acesso a um fluxo para linhas legíveis em que a biblioteca pode converter caracteres para seguir as convenções do sistema.
No Windows, a saída em modo texto transforma uma nova linha do programa na sequência CR LF armazenada.

O

Ordem do byte mais significativo primeiro
A ordem do byte mais significativo primeiro coloca esse byte de um valor de vários bytes no início da sequência de bytes.
O valor 258 aparece como 00 00 01 02 em um campo de 32 bits na ordem do byte mais significativo primeiro.
Ordem do byte menos significativo primeiro
A ordem do byte menos significativo primeiro coloca esse byte de um valor de vários bytes no início da sequência de bytes.
Os quatro bytes 02 01 00 00 representam 258 em um campo de 32 bits na ordem do byte menos significativo primeiro.
Ordem dos bytes
A ordem dos bytes é a ordem em que os bytes de um valor de vários bytes são organizados na memória ou em um arquivo.
Um formato de arquivo especifica sua ordem dos bytes independentemente da máquina que o lê.

P

perror
perror escreve um rótulo e a mensagem para o valor atual de errno na saída de erro padrão, seguidos de uma nova linha.
Um rótulo com o nome do arquivo torna um diagnóstico de arquivo ausente mais útil que uma mensagem sem identificação.
Ponteiro de fim da conversão
Um ponteiro de fim da conversão de strtol marca o primeiro caractere após o prefixo numérico aceito pela conversão.
Para "86cm", o ponteiro chega ao c, permitindo que um campo de número inteiro completo rejeite o sufixo.
Ponteiro para FILE
Um ponteiro para FILE é um valor do tipo FILE * que dá às funções da biblioteca acesso a um fluxo e a seu estado armazenado.
Passe fp a fgetc após verificar se a abertura retornou um ponteiro de fluxo válido.
Posição no arquivo
Uma posição no arquivo é o local em um fluxo onde começa a próxima leitura ou escrita, quando esse fluxo permite posicionamento.
Ler um registro binário de 24 bytes avança a posição para depois de todos os seus 24 bytes.
Preenchimento de alinhamento de estrutura
O preenchimento de alinhamento de estrutura consiste em bytes adicionais que um compilador pode inserir entre membros ou após o último membro para alinhamento.
Um char seguido de um int pode ocupar oito bytes mesmo quando seus tamanhos somam cinco.

R

Redirecionamento
O redirecionamento é uma operação do shell que conecta os fluxos padrão de um programa a arquivos sem alterar seu código de entrada e saída.
O operador 2> pode salvar as mensagens de diagnóstico de um programa em um arquivo separado.
rename
rename altera o nome de um arquivo e retorna 0 em caso de sucesso; o tratamento de um destino existente depende da implementação.
Mantenha um backup disponível se a instalação de uma substituição concluída sob o nome original falhar.
Responsabilidade pela liberação de recursos
A responsabilidade pela liberação de recursos identifica qual parte de um programa é responsável por liberar um fluxo ou outro recurso obtido.
Uma função auxiliar fecha um fluxo que abriu e deixa um fluxo emprestado para a função chamadora.

S

Saída de erro padrão
A saída de erro padrão é o fluxo já aberto stderr usado para diagnósticos independentemente do fluxo de resultados normais de um programa.
Uma conversão malsucedida pode ser descrita em stderr enquanto dados válidos vão para stdout.
Saída padrão
A saída padrão é o fluxo já aberto stdout usado para os resultados normais e outras saídas principais de um programa.
Um canal do shell envia stdout de um conversor para a entrada padrão de outro programa.
snprintf
snprintf formata texto em um arranjo com limite e retorna o comprimento total necessário, excluindo o terminador, ou um valor negativo em caso de erro.
Um retorno igual à capacidade já indica que o texto completo não coube.
strcspn
strcspn encontra o comprimento do trecho inicial de uma cadeia antes de qualquer caractere de um conjunto de rejeição fornecido, ou o comprimento total se nenhum ocorrer.
Usar "\r\n" como conjunto de rejeição localiza um final de linha sem apagar dados finais comuns.
strerror
strerror retorna o texto de uma mensagem pertencente à biblioteca para um código de erro fornecido, permitindo que um programa componha seu próprio diagnóstico.
Use um código salvo quando a liberação de recursos puder ter substituído o valor atual de errno.
Substituição com possibilidade de recuperação
Uma substituição com possibilidade de recuperação mantém um arquivo existente disponível até que uma nova versão concluída tenha sido instalada com sucesso.
Se a renomeação que instala a nova versão falhar, preserve o backup e informe sua localização para restauração.

T

Terminador nulo
Um terminador nulo é o caractere de valor zero que marca o fim de uma cadeia de caracteres em C sem contar como seu texto visível.
Um buffer precisa de um byte adicional além dos caracteres que fgets pode ler.
Tipo inteiro de largura exata
Um tipo inteiro de largura exata tem uma largura especificada exata em bits onde está disponível, sem determinar uma ordem externa dos bytes.
Um campo uint32_t ainda precisa de codificação explícita de bytes para tornar portável um arquivo de intercâmbio.

Sobre esta aula

Por StudeliRelatar um erro

Crie seus próprios Materiais de Estudo

Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.

Começar