[eside-ghost] Lectura/escritura eficiente de ficheros en C
Perki Pat
perki_pat5 en yahoo.es
Vie Ene 27 22:04:44 CET 2006
> 1) Función para averiguar tamaño de bloque, si falla, usar tamaño
> estándar.
alguna sugerencia para hallar el tamaño? un tamaño por defecto? 4096?
>
> 2) lseek del fichero origen (o ficheros origen, porque... ¿el port
> de cp es completo? [*]) y creación de un mapeo de ese tamaño. El tipo
> de escritura debería ser:
>
> a) diferida si el origen está en el mismo dispositivo.
> b) directa si el origen no está en el mismo dispositivo.
cómo saber en qué dispositivo están?
cómo hacer la diferida? pasarlo a un bufer en memoria y luego
escribirlo? y si es un fichero grande?
>
> 3) Leer a saco en bloques de TAMAÑO_BLOQUE, escribiendo directamente en
> el mapeo.
>
> 4) Desmapeo.
>
el problema q he visto es que el fichero tiene que tener suficiente
tamaño para poder albergar todo lo q mapees sobre él.
A lo mejor me he equivocado en algo...
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define _POSIX_MAPPED_FILES
#define _POSIX_SYNCHRONIZED_IO
#include <unistd.h>
#include <sys/mman.h>
int main(int argc, char *argv[])
{
int fd[2],tmp;
size_t file_t, bloque_t=4096;
caddr_t mem,mem_n;
void * bloque;
if(argc!=3) {
fprintf(stderr,"Sintaxis: %s <src> <dst>\n",argv[0]);
exit(EXIT_FAILURE);
}
fd[0]=open(argv[1],O_RDONLY);
if(-1==fd[0]) {
perror("Error al abrir el archivo fuente");
exit(EXIT_FAILURE);
}
fd[1]=open(argv[2],O_RDWR|O_CREAT,S_IWUSR|S_IRUSR);
if(-1==fd[1]){
perror("Error al abrir el archivo destino");
exit(EXIT_FAILURE);
}
/*longitud del fichero*/
file_t=(size_t)lseek(fd[0],0,SEEK_END);
if((off_t)-1==file_t) {
perror("Error al medir la longitud");
exit(EXIT_FAILURE);
}
if((off_t)-1==lseek(fd[0],0,SEEK_SET)) {
perror("Error al rebobinar");
exit(EXIT_FAILURE);
}
printf("file_t=%lu;\n",(unsigned long)file_t);
/*mapear*/
mem=mmap(NULL,file_t,PROT_WRITE,MAP_SHARED,fd[1],0);
if(MAP_FAILED==mem) {
perror("Error al mapear fichero de destino");
exit(EXIT_FAILURE);
}
/*AQUÍ ESTÁ EL PASTEL!!. Comentad este bloquecito: no va*/
/*el fichero destino debe tener suficiente tamaño para poder escribir*/
if(!(bloque=calloc(1,file_t))) {
perror("Error al reservar memoria");
exit(EXIT_FAILURE);
}
write(fd[1],bloque,file_t);
free(bloque);
/*copiar*/
mem_n=mem;
while( (tmp=(int)read(fd[0],mem_n,bloque_t)) )
mem_n+=bloque_t;
if(-1==tmp) {
perror("Error al read");
exit(EXIT_FAILURE);
}
close(fd[0]);
/*finalizar*/
if(-1==msync(mem,file_t,MS_SYNC)) {
perror("Error al msync");
exit(EXIT_FAILURE);
}
if(-1==munmap(mem,file_t)) {
perror("Error al unmap");
exit(EXIT_FAILURE);
}
close(fd[1]);
exit(EXIT_SUCCESS);
}
Además si mapeas el fichero en memoria necesitas memoria suficiente para
que te quepa el fichero entero, no? y si es muy grande, p.ej. 4G?
Más información sobre la lista de distribución eside-ghost