[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