Página 1 de 3

File Split & Join

Publicado: 26 Feb 2011 19:42
por Daniel_Lechu
Hola buenas, después de una especie de batalla de programadores que tuve con webultra :pc: he terminado de hacer mi plugin, el plugin parte y une archivos binarios al tamaño que le digas por lo que no es muy complicado :hypno:

En el plugin he puesto un ejemplo simple del funcionamiento con el que puedes separar archivos y volverlos a unir con el tamaño que quieras, además de poder controlar el tamaño del bloque de lectura/escritura que quieres utilizar.

Versión 1.0:
HIDE: ON
Hidebb Message Hidden Description


A la hora de poner el Blocksize es aconsejable poner un tamaño con el que se pueda dividir el tamaño del archivo destino, porque si no da error el plugin.
Por ejemplo, si pones para partir el archivo en cachos de 1000KB puedes poner un blocksize de 5, 10, 20, 50, 100, 200, 250, 500 y 1000 por ejemplo, aunque puede que me deje alguno...

También es aconsejable usar un blocksize de 100Kb en el caso de que el tamaño destino sea múltiplo de 100, ya que es más rápido partiendo el archivo, aquí os dejo unas pruebas que hice con el File.BinarySplit.
Spoiler: Mostrar
1KB: 7' 36"
10KB: 1' 9"
100KB: 25"
1.000KB: 29"
10.000KB: 32"
100.000KB: 1' 30"
Las pruebas las hice con un archivo de 1.000.000 de KB, partiéndolo en partes de 100.000KB y con los tamaños de bloque que pongo. En el caso de no especificar tamaño de bloque el plugin toma 10KB por defecto.

También os dejo el código para que le echéis un vistazo si queréis:

File.BinarySplit:
function File.BinarySplit(filePath, folderPath, sizeKB, blocksizeKB, CallbackFunction, CallbackInSize)
	if blocksizeKB == nil then blocksizeKB = 10; end
	if sizeKB%blocksizeKB ~= 0 then --Comprueba si el tamaño del archivo es múltiplo del tamaño de bloque
		Application.SetLastError(9999); return "The File.SplitBinary function only accepts file sizes multiples of blocksize"; --Si no es múltiplo devuelve este error
	else --en caso contrario continua
		local inputfile = io.open(filePath, "rb"); --Abre el archivo de origen en modo lectura(r)  y binario(b)
		if inputfile then --Si se ha abierto correctamente continua
			local filesize = inputfile:seek("end"); --Calcula el tamaño del archivo iendo al final y devolviendo la posición
			local totalsize = 0
			inputfile:seek("set", 0); --Vuelve al principio del archivo para comenzar a partirlo.
			local partes = Math.Round(filesize / (sizeKB*1024), 0); if filesize%(sizeKB*1024) ~= 0 then partes = partes+1; end; --Calcula el número de partes en las que se partirá el archvo
			for j = 1, partes do --Repite el código de abajo tantas veces como partes haya
				local destfile = io.open(folderPath.."\\"..String.SplitPath(filePath).Filename..String.SplitPath(filePath).Extension.."."..String.Repeat("0", String.Length(tostring(partes))-String.Length(j))..j, "wb"); --Abre el archivo destino en modo escritura(w) y binario(b)
				if destfile then --Si el archivo destino se ha abierto corréctamente continua
					while destfile:seek() < (sizeKB*1024) do --Repite el bucle hasta que el archivo destino tiene el tamaño deseado
						local bloque = inputfile:read(blocksizeKB*1024); --Lee el tamaño de bloque seleccionado del archivo origen
						if(not bloque)then break; end --Si no hay datos de origen (final de archivo) entonces rompe el bucle
						if CallbackFunction ~= nil then --Comprueba si hay funcion callback
							local continuar = "" 
							if CallbackInSize == true then --Comprueba si queremos el callback en tamaño o %
								continuar = CallbackFunction(inputfile:seek(), filesize); --Si lo queremos en tamaño ejecuta el callback con los dos valores
							else
								continuar = CallbackFunction(Math.Round((inputfile:seek() / filesize) * 100, 0)); --Si lo que queremos es % entonces calcula cual sería y ejecuta el callback con ese valor
							end
							if continuar == false then --Si el callback devuelve false...
								destfile:close(); inputfile:close(); -- Se cierran los archivos origen y destino, y...
								Application.SetLastError(1027); return _tblErrorMessages[1027]; --Se devuelve un código de error
							end
						end
						destfile:write(bloque); --En el caso de que no se haya llegado al final del archivo ni se haya devuelto false en el callback escribe los 10KB al archivo.
					end
					totalsize = totalsize + destfile:seek("end"); --calcula el tamaño del archivo destino y lo suma al tamaño total de los archivos.
					destfile:close(); --Cierra el archivo destino
				else
					Application.SetLastError(1004);	return _tblErrorMessages[1004]; --Si el archivo destino no se abrió corréctamente devuelve un código de error
				end
				if(inputfile:seek() == filesize)then break;end --Esta línea más bien podría borrarse pero la mantengo por si acaso, hace que si se llega al final del archivo de origen entonces termina el bucle "for"
			end
			inputfile:close(); --Cierra el archivo de origen.
			if totalsize == filesize then --Comprueba si el total de los archivos destino coincide con el tamaño del archivo de origen
				Application.SetLastError(0); return 0; --Si el tamaño es igual devuelve el código de error 0 que significa que todo ha ido bien
			else
				Application.SetLastError(9999); return _tblErrorMessages[9999]; --En caso contrario devuelve un código de error desconocido (9999)
			end
		else
			Application.SetLastError(1021); return _tblErrorMessages[1021]; --Si no se abrió el archivo origen corréctamente devuelve un código de error
		end
	end
end
File.BinaryJoin:
function File.BinaryJoin(FilePath, FileDest, blocksizeKB, CallbackFunction, CallbackInSize)
	if blocksizeKB == nil then blocksizeKB = 100; end
	if io.open(FilePath) then --Comprueba que existe el archivo de origen
		local tamext = String.Length(String.SplitPath(FilePath).Extension)-1 --Saca el número de caracteres de la extensión
		if tamext > 0 then --Si tiene extensión continua, eso ayuda a distinguir las carpetas también.
			local total = 0;
			local totalsize = 0
						
			for j = 1, String.ToNumber(String.Repeat("9", tamext)) do --Comienza un bucle que se ejecuta x veces 9, si la extensión es .1 serían 9, si es .01 serían 99, y así sucesivamente
				local inputfile = io.open(String.SplitPath(FilePath).Drive..String.SplitPath(FilePath).Folder..String.SplitPath(FilePath).Filename.."."..String.Repeat("0", tamext-(String.Length(j)))..j, "rb"); --Abre el archivo de origen
				if inputfile then	--Si el archivo origen se ha abierto corréctamente entonces continua
					totalsize = totalsize + inputfile:seek("end"); --Suma al total el tamaño del fichero origen
					inputfile:close(); --Cierra el archivo origen
					total = total + 1 --Suma 1 al total de archivos origen, cosa útil más adelante
				else
					--En caso de no existir el archivo origen cancela el bucle para que no se ejecute más veces de las devidas
					--Por ejemplo, tenemos un fichero .01 y el último es .11, es inutil seguir buscando del .12 hasta el .99
					break 
				end
			end
			
			local outputfile = io.open(FileDest, "wb") --Abre el archivo destino en modo escritura(w) y binario(b)
			if outputfile then --Si se abre el archivo destino corréctamente continua
				for j = 1, total do --Repite el bucle tantas veces como archivos haya.
					local inputfile = io.open(String.SplitPath(FilePath).Drive..String.SplitPath(FilePath).Folder..String.SplitPath(FilePath).Filename.."."..String.Repeat("0", tamext-(String.Length(j)))..j, "rb"); --Abre el archivo de origen en modo lectura(r) y binario(b)
					while true do --Hace un bucle infinito
						local bloque = inputfile:read(10240); --Lee 10KB del arhcivo origen
						if(not bloque)then break; end --Si se llega al final del archivo origen entonces sale del bucle infinito
						if CallbackFunction ~= nil then --Comprueba si hay funcion callback
							local continuar = ""
							if CallbackInSize == true then --Comprueba si los datos de la función callback los queremos en tamaño o %
								continuar = CallbackFunction(outputfile:seek(), totalsize); --En caso de quererlo en tamaño envía los dos valores al callback
							else
								continuar = CallbackFunction(Math.Round((outputfile:seek() / totalsize) * 100, 0)); --En caso contrario calcula el % y lo envia al callback
							end
							if continuar == false then --Si la función callback devuelve false entonces cierra los archivos y cancela el progreso
								inputfile:close(); outputfile:close();
								Application.SetLastError(1027); return _tblErrorMessages[1027];
							end
						end
						outputfile:write(bloque); --Escribe el bloque de 10KB que leímos antes	
					end
					inputfile:close(); --Cierra el archivo de origen
				end
				if outputfile:seek("end") == totalsize then --Comprueba que el tamaño del destino coincide con el calculado arriba
					outputfile:close(); --Cierra el archivo destino
					Application.SetLastError(0); return 0; --Si el tamaño es igual devuelve el código de error 0 que significa que todo ha ido bien
				else
					outputfile:close(); --Cierra el archivo destino
					Application.SetLastError(9999); return _tblErrorMessages[9999]; --En caso contrario devuelve un código de error desconocido (9999)
				end
			else
				Application.SetLastError(1004); return _tblErrorMessages[1004]; --Si el archivo destino no se abrió corréctamente devuelve un código de error
			end
		else
			Application.SetLastError(1019); return _tblErrorMessages[1019]; --Si la extensión es nula devuelve un código de error
		end
	else
		Application.SetLastError(1021); return _tblErrorMessages[1021]; --Si no se abrió el archivo origen corréctamente devuelve un código de error
	end
end
File.BinaryAutoJoin:
function File.BinaryAutoJoin(FilePath, blocksizeKB, CallbackFunction, CallbackInSize)
	--La única diferencia entre JoinBinary y AutoJoinBinary es la selección o no del archivo destino
	--por lo que lo único que hace este código es sacarlo automáticamente del archivo origen y ejecutar
	--el File.JoinBinary
	local FileDest = String.SplitPath(FilePath).Drive..String.SplitPath(FilePath).Folder..String.SplitPath(FilePath).Filename
	return File.BinaryJoin(FilePath, FileDest, blocksizeKB, CallbackFunction, CallbackInSize)
end

Re: File Split & Join

Publicado: 27 Feb 2011 07:06
por Geran
Interensate..., Gracias

Re: File Split & Join

Publicado: 27 Feb 2011 08:32
por rafaxplayer
Gracias daniel , tiene buena pinta ;)

Re: File Split & Join

Publicado: 27 Feb 2011 10:47
por carsonzillo
pisharrrrako! XDD

Re: File Split & Join

Publicado: 27 Feb 2011 11:18
por Daniel_Lechu
Heyy carsonzillo!!! xD

Se me olvidó decir que lo he probado varias veces y funciona pero si encontráis algún error decírmelo ;).

PDTA: Creo que más menos he aprendido lo suficiente del io.open y el :seek para poder añadirle cabecera al archivo, que la puedo usar para varias cosas como por ejemplo reconocer si el archivo ha sido partido con el plugin, guardar la extensión o incluso ponerle el CRC para que a la hora de volverlo a unir compruebe si lo ha hecho corréctamente.

Re: File Split & Join

Publicado: 27 Feb 2011 14:11
por abood1987
good

thank you
....................

Re: File Split & Join

Publicado: 09 Abr 2011 08:11
por frankpo
gracias :D

Re: File Split & Join

Publicado: 09 Abr 2011 20:40
por er_mejor
gracias, voy a descargar.

Re: File Split & Join

Publicado: 10 Abr 2011 07:30
por ahmed elsayed
very thanx for you :SOS:

Re: File Split & Join

Publicado: 10 Abr 2011 18:43
por frankpo
Daniel no sirve, no podes partir archivos mayores a 2GB.
Me parece que habria que hacerlo en otro lenguaje al plugin, fijate si se puede cambiar el sistema de manejo de archivos por otro.

Saludos!

Re: File Split & Join

Publicado: 10 Abr 2011 19:33
por Daniel_Lechu
Podría intentar portarlo a C++ y crear una DLL lo único es que de C++ no se mucho y a lo mejor tardo...

Re: File Split & Join

Publicado: 11 Abr 2011 09:10
por frankpo
Hola
Te comento que encontre una solución al problema de los archivos mayores a 2GB.

Lo que tienes que hacer es reemplazar:
local filesize = inputfile:seek("end"); --Calcula el tamaño del archivo iendo al final y devolviendo la posición
por esta declaración:
local filesize = File.GetSize(filePath); --Calcula el tamaño del archivo a partir
La funcion seek es la que no puede procesar archivos mayores a 2gb, pero con la funcion GetSize que viene con AMS no hay ningun problema.

Otra cosa que te recomiendo es que cada vez que haces una declaracion del io de lua lo almacenes en dos variables en lugar de una, de esta forma si tiene un error en lugar de obtener solo nil obtienes un string con un mensaje de error. Es así como logre identificar el problema en tu codigo.

Entonces por ejemplo en vez de realizar la declaracion de esta forma:
local inputfile = io.open(filePath, "rb");
Lo haces asi:
local inputfile, cError = io.open(filePath, "rb");
Cuando la funcion open falla, devuelve dos parametros: nil y el string con la descripcion del error ocurrido.
Entonces puedes obtener informacion sobre el error leyendo la variable cError.

Si te interesa puedo revisar tu codigo, implementar estos detalles y por que no agregar un poquito mas de funcionalidad.

Saludos!

Re: File Split & Join

Publicado: 18 Abr 2011 14:18
por dangngocnguyenit
thanks for topic very good.

Re: File Split & Join

Publicado: 04 Jul 2011 15:30
por nghethihieu
thank you

Re: File Split & Join

Publicado: 21 Nov 2011 16:39
por Haitham.2012
WOOOW .. GOOD JOB

Re: File Split & Join

Publicado: 21 Nov 2011 16:44
por Daniel_Lechu
frankpo escribió:Hola
Te comento que encontre una solución al problema de los archivos mayores a 2GB.

Lo que tienes que hacer es reemplazar:
local filesize = inputfile:seek("end"); --Calcula el tamaño del archivo iendo al final y devolviendo la posición
por esta declaración:
local filesize = File.GetSize(filePath); --Calcula el tamaño del archivo a partir
La funcion seek es la que no puede procesar archivos mayores a 2gb, pero con la funcion GetSize que viene con AMS no hay ningun problema.

Otra cosa que te recomiendo es que cada vez que haces una declaracion del io de lua lo almacenes en dos variables en lugar de una, de esta forma si tiene un error en lugar de obtener solo nil obtienes un string con un mensaje de error. Es así como logre identificar el problema en tu codigo.

Entonces por ejemplo en vez de realizar la declaracion de esta forma:
local inputfile = io.open(filePath, "rb");
Lo haces asi:
local inputfile, cError = io.open(filePath, "rb");
Cuando la funcion open falla, devuelve dos parametros: nil y el string con la descripcion del error ocurrido.
Entonces puedes obtener informacion sobre el error leyendo la variable cError.

Si te interesa puedo revisar tu codigo, implementar estos detalles y por que no agregar un poquito mas de funcionalidad.

Saludos!
Gracias por esto, no lo vi y ya dejé un poco de lado la función ya que no la uso jejeje.

Re: File Split & Join

Publicado: 28 Feb 2012 15:24
por acf
<p>
</p>

Re: File Split & Join

Publicado: 26 Feb 2013 12:43
por hitec
gracias

Re: File Split & Join

Publicado: 27 Mar 2013 17:55
por actionstk
Muchas gracias Ceone.

Re: File Split & Join

Publicado: 27 Mar 2013 21:30
por mecivic
The link is not found