Desafio C
Cópia de arquivo com verificação de erros e assert
Enunciado
Implemente um programa que copia o conteúdo de um arquivo de origem para um destino. O programa deve receber dois argumentos de linha de comando: origem e destino. Use assert para garantir que argc == 3. Abra a origem para leitura e o destino para escrita. Se qualquer abertura falhar, use perror e retorne EXIT_FAILURE. Copie os dados em blocos de 4096 bytes, verificando erros de leitura e escrita. Ao final, feche ambos os arquivos e retorne EXIT_SUCCESS.
Requisitos
- Usar
assert(argc == 3)para validar a quantidade de argumentos. - Abrir origem com
fopenmodo"rb"e destino com modo"wb". - Verificar erros de
freadefwritecomferror. - Fechar os arquivos com
fclosee tratar erros de fechamento. - Retornar
EXIT_FAILUREem qualquer falha eEXIT_SUCCESSno sucesso.
Código inicial
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main(int argc, char *argv[]) {
// seu código aqui
return 0;
}
Saída esperada
Arquivo copiado com sucesso.
Ver dica
Use um buffer de 4096 bytes e um laço com fread. Verifique ferror após cada operação.
Mostrar solução
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define TAM_BUFFER 4096
int main(int argc, char *argv[]) {
assert(argc == 3); // garante que temos origem e destino
const char *origem = argv[1];
const char *destino = argv[2];
FILE *in = fopen(origem, "rb");
if (in == NULL) {
perror("Erro ao abrir origem");
return EXIT_FAILURE;
}
FILE *out = fopen(destino, "wb");
if (out == NULL) {
perror("Erro ao abrir destino");
fclose(in);
return EXIT_FAILURE;
}
unsigned char buffer[TAM_BUFFER];
size_t lidos;
while ((lidos = fread(buffer, 1, TAM_BUFFER, in)) > 0) {
if (fwrite(buffer, 1, lidos, out) != lidos) {
perror("Erro ao escrever no destino");
fclose(in);
fclose(out);
return EXIT_FAILURE;
}
}
if (ferror(in)) {
perror("Erro ao ler da origem");
fclose(in);
fclose(out);
return EXIT_FAILURE;
}
if (fclose(in) != 0) {
perror("Erro ao fechar origem");
fclose(out);
return EXIT_FAILURE;
}
if (fclose(out) != 0) {
perror("Erro ao fechar destino");
return EXIT_FAILURE;
}
printf("Arquivo copiado com sucesso.\n");
return EXIT_SUCCESS;
}
Passo a passo
assert(argc == 3)aborta o programa se o número de argumentos estiver errado. Isso é um bug de uso, não uma falha recuperável.- Abrimos a origem em modo binário
"rb". Se falhar,perroreEXIT_FAILURE. - Abrimos o destino em modo binário
"wb". Se falhar, fechamos a origem e retornamos erro. - No laço,
freadlê até 4096 bytes. Enquantolidos > 0, escrevemos comfwrite. - Se
fwritenão escrever todos os bytes, tratamos como erro, fechamos ambos e retornamos falha. - Após o laço, verificamos
ferror(in)para detectar erro de leitura que não seja fim de arquivo. - Fechamos ambos os arquivos verificando o retorno de
fclose. Se algum falhar, retornamos erro. - Se tudo ocorrer bem, imprimimos a mensagem de sucesso e retornamos
EXIT_SUCCESS.
Por que funciona
O uso de assert para validar a linha de comando separa erros de programação (uso incorreto) de erros de execução (arquivo inexistente, disco cheio). As verificações de ferror capturam falhas de I/O que fread/fwrite podem não reportar diretamente. O fechamento verificado garante que os dados sejam realmente gravados no disco.
Erros comuns
- Não verificar o retorno de
fwrite: se o disco encher, a cópia fica incompleta silenciosamente. - Esquecer de fechar
inquandooutfalha ao abrir: vazamento de descritor. - Usar
assertpara validar a existência do arquivo:assertnão deve ser usado para condições externas, pois pode ser desabilitado comNDEBUG.
Outra forma de resolver
Usar goto cleanup para centralizar o fechamento dos arquivos, evitando repetição. É preferível quando há muitos recursos a liberar.
Saída esperada
Arquivo copiado com sucesso.