Desafio C
Cópia de arquivo com tratamento de erros
Enunciado
Implemente um programa que copie o conteúdo de um arquivo de origem para um arquivo de destino. O programa deve receber os nomes dos arquivos como argumentos de linha de comando (./copia origem destino). Use fread e fwrite para copiar em blocos de 1024 bytes. Trate todos os possíveis erros: número incorreto de argumentos, falha ao abrir origem/destino, falha na leitura/escrita. Ao final, exiba uma mensagem indicando quantos bytes foram copiados.
Requisitos
- Verificar se
argcé igual a 3; caso contrário, exibir mensagem de uso e sair com código 1. - Abrir o arquivo de origem no modo
"rb"e o de destino no modo"wb". - Usar um buffer de 1024 bytes e
fread/fwriteem loop. - Verificar se
freadretornou menos que o solicitado devido a erro (usarferror). - Verificar se
fwritegravou todos os bytes lidos. - Fechar ambos os arquivos e imprimir o total de bytes copiados.
Código inicial
#include <stdio.h>
#include <stdlib.h>
#define BUFSIZE 1024
int main(int argc, char *argv[]) {
// Seu código aqui
return 0;
}
Saída esperada
Uso: ./copia origem destino
Ver dica
Após fread, se o retorno for menor que BUFSIZE, verifique feof e ferror. Para fwrite, compare o retorno com o número de bytes lidos.
Mostrar solução
#include <stdio.h>
#include <stdlib.h>
#define BUFSIZE 1024
int main(int argc, char *argv[]) {
// Verifica argumentos
if (argc != 3) {
fprintf(stderr, "Uso: %s origem destino\n", argv[0]);
return 1;
}
// Abre origem para leitura binária
FILE *origem = fopen(argv[1], "rb");
if (origem == NULL) {
perror("Erro ao abrir origem");
return 1;
}
// Abre destino para escrita binária
FILE *destino = fopen(argv[2], "wb");
if (destino == NULL) {
perror("Erro ao abrir destino");
fclose(origem);
return 1;
}
unsigned char buffer[BUFSIZE];
size_t total = 0;
size_t lidos;
// Loop de cópia
while ((lidos = fread(buffer, 1, BUFSIZE, origem)) > 0) {
size_t escritos = fwrite(buffer, 1, lidos, destino);
if (escritos != lidos) {
perror("Erro ao escrever no destino");
fclose(origem);
fclose(destino);
return 1;
}
total += lidos;
}
// Verifica se a leitura parou por erro
if (ferror(origem)) {
perror("Erro ao ler da origem");
fclose(origem);
fclose(destino);
return 1;
}
// Fecha arquivos
fclose(origem);
fclose(destino);
printf("Bytes copiados: %zu\n", total);
return 0;
}
Passo a passo
- Verificamos se
argcé 3. Se não, imprimimos a mensagem de uso e retornamos 1. - Abrimos o arquivo de origem com
fopen(argv[1], "rb"). Se falhar,perrormostra o motivo e saímos. - Abrimos o destino com
fopen(argv[2], "wb"). Se falhar, fechamos a origem e saímos. - Declaramos um buffer de 1024 bytes e variáveis para contagem.
- No loop,
freadlê até 1024 bytes. Se retornar 0, pode ser fim de arquivo ou erro; saímos do loop. - Para cada bloco lido,
fwritegrava exatamentelidosbytes. Seescritos != lidos, houve erro de escrita; tratamos e saímos. - Após o loop, verificamos
ferror(origem)para distinguir fim de arquivo de erro de leitura. - Fechamos ambos os arquivos e imprimimos o total de bytes copiados.
Por que funciona
A cópia em blocos é eficiente e funciona para qualquer tipo de arquivo (texto ou binário). Usar modo binário evita traduções indesejadas. Verificar fread e fwrite garante que erros de E/S sejam detectados. A verificação de ferror após o loop captura erros que não resultam em retorno 0.
Erros comuns
- Não verificar o retorno de
fwrite: se o disco encher, a gravação pode ser parcial. Compareescritoscomlidos. - Usar
while (!feof(origem)): isso causa uma iteração extra porquefeofsó é verdadeiro após uma tentativa de leitura falhar. Prefirawhile ((lidos = fread(...)) > 0). - Esquecer de fechar a origem se o destino falhar: vazamento de recurso. Sempre feche o que já foi aberto.
- Não tratar
ferrorapós o loop: um erro de leitura pode ser confundido com fim de arquivo.
Outra forma de resolver
Poderia usar fgetc/fputc para copiar byte a byte, mas seria muito mais lento. Para arquivos pequenos, é aceitável; para grandes, a cópia em blocos é preferível. Também é possível usar sendfile em sistemas POSIX, mas não é portável.
Saída esperada
Uso: ./copia origem destino