Beraldo 864 Denunciar post Postado Outubro 21, 2008 Montei um programinha que salva e lista corretamente um arquivo binário. #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #define NOME_ARQUIVO "teste.bin" typedef struct { int x; float y; double z; char str[20]; } ESTRUTURA; FILE * abrir_arquivo(char *nome, char *modo); int fechar_arquivo(FILE *fp); ESTRUTURA salvar(int x, float y, double z, char *str); void imprimir(); int main() { salvar(1, 42.59987, 7.889751410232548, "Beraldo1"); salvar(2, 43.59987, 8.889751410232548, "Beraldo2"); salvar(3, 44.59987, 9.889751410232548, "Beraldo3"); imprimir(); return 0; } FILE * abrir_arquivo(char *nome, char *modo) { FILE *fp; if ((fp = fopen(nome, modo)) == NULL) { fprintf(stderr, "Erro ao abrir arquivo\n"); exit(1); } return fp; } /*****************************************/ int fechar_arquivo(FILE *fp) { return fclose(fp); } /********************************************/ ESTRUTURA salvar(int x, float y, double z, char *str) { FILE *fp; ESTRUTURA e; e.x = x; e.y = y; e.z = z; strcpy(e.str, str); fp = abrir_arquivo(NOME_ARQUIVO, "ab"); fwrite(&e, sizeof(ESTRUTURA), 1, fp); fechar_arquivo(fp); } /*********************************************/ void imprimir() { FILE *fp; ESTRUTURA *e; int i, total; struct stat st; stat(NOME_ARQUIVO, &st); total = st.st_size / sizeof(ESTRUTURA); e = (ESTRUTURA *) malloc(total * sizeof(ESTRUTURA)); fp = abrir_arquivo(NOME_ARQUIVO, "rb"); fread(e, sizeof(ESTRUTURA), total, fp); fechar_arquivo(fp); for (i = 0; i < total; i++) { printf("x=%d | y=%f | z=%f | str=%s\n", e[i].x, e[i].y, e[i].z, e[i].str); } } O que quero fazer agora é uma função de remoção, que apague uma das estruturas salvas no arquivo. Mas nem tenho idéia de como fazer isso sem precisar reescrever todo o arquivo (reescrevendo fica fácil :P ) Alguém sabe? Compartilhar este post Link para o post Compartilhar em outros sites
quitZAUMMM 18 Denunciar post Postado Outubro 21, 2008 nunca fiz algo assim.. + sem reescrever o arquivo acho q vai ser meio complicado... bom acho eu neh :lol: sera q o comando fseek te ajuda um pouco?? []'s Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 21, 2008 Pensei no fseek(). Ele vai ajudar se houver uma forma de remover todo o conteúdo que está após o ponteiro do arquivo. Mas ainda não descobri como fazer isso... http://forum.imasters.com.br/public/style_emoticons/default/no.gif Quero evitar a reescrita do arquivo pois meu professor falou para tentarmos manipular o arquivo em disco, não em memória. Compartilhar este post Link para o post Compartilhar em outros sites
_Isis_ 202 Denunciar post Postado Outubro 21, 2008 Se você quer mudar o conteúdo do arquivo sem reescrevê-lo, ajoelhe e reze. O jeito mais fácil é criar um arquivo e ir copiando os bytes que se quer manter, remover o antigo (man 3 remove), e renomear o novo arquivo (man 2 rename). Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 21, 2008 Se você quer mudar o conteúdo do arquivo sem reescrevê-lo, ajoelhe e reze.:lol: Vou tentar. :P Pelo jeito é só reescrevendo, mesmo... Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 23, 2008 Consegui! :D Usei truncate(). Assim não é necessário reescrever o arquivo. A função para truncar ficou assim: void truncar() { int total, tamanho; struct stat st; stat(NOME_ARQUIVO, &st); total = st.st_size / sizeof(ESTRUTURA); tamanho = (total - 1) * sizeof(ESTRUTURA); if (truncate(NOME_ARQUIVO, tamanho) == 0) { printf("Truncado com sucesso. Novo tamanho: %d\n", tamanho); } } O código completo: #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #define NOME_ARQUIVO "teste.bin" typedef struct { int x; float y; double z; char str[20]; } ESTRUTURA; FILE * abrir_arquivo(char *nome, char *modo); int fechar_arquivo(FILE *fp); ESTRUTURA salvar(int x, float y, double z, char *str); void imprimir(); void truncar(); int main() { salvar(1, 42.59987, 7.889751410232548, "Beraldo1"); salvar(2, 43.59987, 8.889751410232548, "Beraldo2"); salvar(3, 44.59987, 8.889751410232548, "Beraldo3"); truncar(); salvar(4, 45.59987, 8.889751410232548, "Beraldo4"); imprimir(); return 0; } /******************************************/ FILE * abrir_arquivo(char *nome, char *modo) { FILE *fp; if ((fp = fopen(nome, modo)) == NULL) { fprintf(stderr, "Erro ao abrir arquivo\n"); exit(1); } return fp; } /*****************************************/ int fechar_arquivo(FILE *fp) { return fclose(fp); } /********************************************/ ESTRUTURA salvar(int x, float y, double z, char *str) { FILE *fp; ESTRUTURA e; e.x = x; e.y = y; e.z = z; strcpy(e.str, str); fp = abrir_arquivo(NOME_ARQUIVO, "ab"); fwrite(&e, sizeof(ESTRUTURA), 1, fp); fechar_arquivo(fp); } /*********************************************/ void imprimir() { FILE *fp; ESTRUTURA *e; int i, total; struct stat st; stat(NOME_ARQUIVO, &st); total = st.st_size / sizeof(ESTRUTURA); e = (ESTRUTURA *) malloc(total * sizeof(ESTRUTURA)); fp = abrir_arquivo(NOME_ARQUIVO, "rb"); fread(e, sizeof(ESTRUTURA), total, fp); fechar_arquivo(fp); for (i = 0; i < total; i++) { printf("[%d] => x=%d | y=%f | z=%f | str=%s\n", i, e[i].x, e[i].y, e[i].z, e[i].str); } } void truncar() { int total, tamanho, tr; struct stat st; stat(NOME_ARQUIVO, &st); total = st.st_size / sizeof(ESTRUTURA); tamanho = (total - 1) * sizeof(ESTRUTURA); if (truncate(NOME_ARQUIVO, tamanho) == 0) { printf("Truncado com sucesso. Novo tamanho: %d\n", tamanho); } } http://forum.imasters.com.br/public/style_emoticons/default/joia.gif Compartilhar este post Link para o post Compartilhar em outros sites
_Isis_ 202 Denunciar post Postado Outubro 23, 2008 Retire bytes do meio do arquivo usando truncate. Mesmo usando truncate você está reescrevendo o arquivo. Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 23, 2008 Retire bytes do meio do arquivo usando truncate.Nesse caso, substituo os X bytes do meio do arquivo pelos últimos X bytes do fim do arquivo. Depois chamo truncate() para apagar os últimos X bytes do arquivo. Mesmo usando truncate você está reescrevendo o arquivo.Fiz uma função para reescrever o arquivo manualmente para compararUsando truncate foi mais rápido. Usei este código: #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #define NOME_ARQUIVO "teste.bin" #define LINHAS 20 typedef struct { int x; char str[20]; } ESTRUTURA; FILE * abrir_arquivo(char *nome, char *modo); int fechar_arquivo(FILE *fp); void salvar(); void imprimir(char *filename); void remover(int linha); void remover2(int linha); int main() { double tempo1 = 0, tempo2 = 0; struct timeval antes, depois; gettimeofday(&antes, NULL); salvar(); remover(5); remover(2); remover(7); remover(10); gettimeofday(&depois, NULL); tempo1 = (depois.tv_sec - antes.tv_sec) + (depois.tv_usec - antes.tv_usec) / 1.e6; gettimeofday(&antes, NULL); salvar(); remover2(5); remover2(2); remover2(7); remover2(10); gettimeofday(&depois, NULL); tempo2 = (depois.tv_sec - antes.tv_sec) + (depois.tv_usec - antes.tv_usec) / 1.e6; /*imprimir("saida.bin");*/ printf("\nTempo:\nCom remover(): %.10lf\nCom remover2(): %.10lf\n\n", tempo1, tempo2); return 0; } /******************************************/ FILE * abrir_arquivo(char *nome, char *modo) { FILE *fp; if ((fp = fopen(nome, modo)) == NULL) { fprintf(stderr, "Erro ao abrir arquivo '%s' no modo '%s'\n", nome, modo); exit(1); } return fp; } /*****************************************/ int fechar_arquivo(FILE *fp) { return fclose(fp); } /********************************************/ void salvar() { FILE *fp; ESTRUTURA e; int i; fp = abrir_arquivo(NOME_ARQUIVO, "wb"); for (i = 0; i < LINHAS; i++) { e.x = i; sprintf(e.str, "Beraldo%d", i); fwrite(&e, sizeof(ESTRUTURA), 1, fp); } fechar_arquivo(fp); } /*********************************************/ void imprimir(char *filename) { FILE *fp; ESTRUTURA *e; int i, total; struct stat st; stat(filename, &st); total = st.st_size / sizeof(ESTRUTURA); e = (ESTRUTURA *) malloc(total * sizeof(ESTRUTURA)); fp = abrir_arquivo(filename, "rb"); fread(e, sizeof(ESTRUTURA), total, fp); fechar_arquivo(fp); for (i = 0; i < total; i++) { printf("[%d] => x=%d | str=%s\n", i, e[i].x, e[i].str); } } void remover(int linha) { int total, tamanho, tr; ESTRUTURA e; struct stat st; FILE *fp; stat(NOME_ARQUIVO, &st); total = st.st_size / sizeof(ESTRUTURA); tamanho = (total - 1) * sizeof(ESTRUTURA); fp = abrir_arquivo(NOME_ARQUIVO, "r+b"); fseek(fp, tamanho, SEEK_SET); fread(&e, sizeof(ESTRUTURA), 1, fp); fseek(fp, linha * sizeof(ESTRUTURA), SEEK_SET); fwrite(&e, sizeof(ESTRUTURA), 1, fp); fechar_arquivo(fp); if (truncate(NOME_ARQUIVO, tamanho) != 0) { fprintf(stderr, "Erro ao truncararquivo"); } } void remover2(int linha) { int total, tamanho, i = 0; ESTRUTURA e; struct stat st; FILE *fp, *fp2; stat(NOME_ARQUIVO, &st); total = st.st_size / sizeof(ESTRUTURA); tamanho = (total - 1) * sizeof(ESTRUTURA); fp = abrir_arquivo(NOME_ARQUIVO, "r+b"); fseek(fp, tamanho, SEEK_SET); fread(&e, sizeof(ESTRUTURA), 1, fp); fseek(fp, linha * sizeof(ESTRUTURA), SEEK_SET); fwrite(&e, sizeof(ESTRUTURA), 1, fp); fechar_arquivo(fp); fp = abrir_arquivo(NOME_ARQUIVO, "rb"); fp2 = abrir_arquivo("saida.bin", "wb"); while (!feof(fp)) { /*printf("i=%d\n", i++);*/ fread(&e, sizeof(ESTRUTURA), 1, fp); fwrite(&e, sizeof(ESTRUTURA), 1, fp2); } fechar_arquivo(fp); fechar_arquivo(fp2); } $ gcc teste.c -o teste $ ./teste Tempo: Com remover(): 0.0002450000 Com remover2(): 0.0002660000 [edit] A função remover2() está errada. Eu a refiz: void remover2(int linha) { int total, tamanho, i = 0, pos = 0; ESTRUTURA e; struct stat st; FILE *fp, *fp2; stat(NOME_ARQUIVO, &st); total = st.st_size / sizeof(ESTRUTURA); tamanho = (total - 1) * sizeof(ESTRUTURA); fp = abrir_arquivo(NOME_ARQUIVO, "r+b"); fseek(fp, tamanho, SEEK_SET); fread(&e, sizeof(ESTRUTURA), 1, fp); fseek(fp, linha * sizeof(ESTRUTURA), SEEK_SET); fwrite(&e, sizeof(ESTRUTURA), 1, fp); rewind(fp); fp2 = abrir_arquivo("saida.bin", "wb"); while ((pos = i * sizeof(ESTRUTURA)) < tamanho) { fread(&e, sizeof(ESTRUTURA), 1, fp); fwrite(&e, sizeof(ESTRUTURA), 1, fp2); i++; } fechar_arquivo(fp); fechar_arquivo(fp2); remove(NOME_ARQUIVO); rename("saida.bin", NOME_ARQUIVO); } $ ./teste Tempo: Com remover(): 0.0002500000 Com remover2(): 0.0003270000 Com truncate() continua mais rápido Compartilhar este post Link para o post Compartilhar em outros sites
_Isis_ 202 Denunciar post Postado Outubro 23, 2008 Fiz uma função para reescrever o arquivo manualmente para compararUsando truncate foi mais rápido. Nesse caso, substituo os X bytes do meio do arquivo pelos últimos X bytes do fim do arquivo. Depois chamo truncate() para apagar os últimos X bytes do arquivo. você ainda não entendeu ou não está sabendo se explicar. Suponha que o arquivo seja assim: R1,R2,R3 R4,R5,R6 R7,R8,R9 R10,R11,R12 R13,R14,R15 Substituindo os bytes da 3a linha do arquivo pela mesma quantidade de bytes do final do arquivo, você tem R1,R2,R3 R4,R5,R6 R13,R14,R15 R10,R11,R12 R13,R14,R15 Apagando os mesmos bytes do final do arquivo, você some com a ordem entre os registros. Se isso for um arquivo com dados meteorológicos, uma seqüência numérica p/ plotar, ou na pior das hipóteses, dados "marcadores" (como se fossem tags de início e final de seção, como as dos arquivos de configuração no Linux) você dança. +1,5% + 5% -3% -0,9% +1,2% A reescrita do arquivo acontece de qualquer modo e é isso que você não está entendendo. O que você faz com o truncate é modificar o campo que contém o tamanho do arquivo na estrutura (além das datas de modificação e talvez outras coisas mais) que contém os dados do arquivo. Aparentemente, quando você especifica um tamanho menor, o marcador de final do arquivo é colocado no último byte que você especifica. No caso de você expandir o arquivo, dados são adicionados no final dele. Então, dizer que você vai truncar um arquivo sem reescrevê-lo é meio nonsense. Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 23, 2008 Eu entendi quando você falou que truncate() faz uma reescrita de arquivo. Também me expliquei bem (pelo menos você entendeu exatamente o que eu tentei dizer). :D Fiz a função própria de rescrita só para comparar o tempo de execução. Para a aplicação que estou desenvolvendo, a ordem dos registros no arquivo não importa, por isso posso deslocar os bytes, simplesmente.. Mas se a ordem interferir, aí, deveras, será necessário reescrever manualmente. Compartilhar este post Link para o post Compartilhar em outros sites
_Isis_ 202 Denunciar post Postado Outubro 23, 2008 Cara, tempo de execução não diz nada. Teu processo pode sofrer um renice pra prioridade mais baixa possível e nunca ser executado ou é executado sempre e mais rápido porque tem prioridade mais alta do que os outros processos do sistema. E ainda depende do algoritmo de escalonamento... Compartilhar este post Link para o post Compartilhar em outros sites