Hola a todos. Quiero darles una bienvenida (algo tardía) a todos los integrantes de esta genial comunidad al nuevo curso. Les cuento que a pesar de no estar físicamente en la Universidad actualmente sigo siendo parte de la comunidad de Software Libre y seguiré publicando en la medida que mi trabajo me lo permita.
Hoy quiero compartir con ustedes una solución Home Made a un problema bastante común. Seguro muchos utilizan hoy en día redes wifi de bastante mala calidad. Es muy común que se nos desconecten los dispositivos o se “caiga” la red en cualquier momento lo cual puede ser un dolor de cabeza a la hora de hacer copias de ficheros. La mayoría de las herramientas que permiten hacer copias no están preparadas para una red tan hostil y no contemplan mecanismos de recuperación ante los errores lo que conlleva a que tengamos que empezar a copiar muchas veces desde el principio archivos que ya teníamos descargados a medias, consumiendo mucho más tiempo y recursos.
La herramienta que hoy les traigo como propuesta la programé para realizar la copia de archivos en una red inestable desde servidores cifs/smb (archivos compartidos de windows). Está escrita en groovy y depende de la librería jcifs de la cual ya les estuve hablando en una ocasión aquí. Hasta el momento no tiene una UI basada en formularios; es una aplicación de línea de comandos.
Para comenzar al utilizar la aplicación debe especificar la ruta del archivo o carpeta que deseamos copiar utilizando el formato smb://servidor/archivo. Después debe especificar la ruta local donde desea guardar el mismo, selecciona si el servidor requiere autenticación y de ser positivo especificar las credenciales. Estos datos son guardados en texto plano en un fichero de extensión .magneto_task en el directorio donde se guardará la copia y comienza la descarga. En caso de ocurrir algún problema durante la descarga el servicio se queda tratando de lograr conexión nuevamente. Puede incluso apagar su computadora y reiniciar nuevamente la descarga cuando quiera. Puede ejecutar la aplicación sin parámetros para que la misma pregunte cada una de las especificaciones para la descarga o pasarle como argumento la dirección de un fichero de descarga .magneto_task para que continúe la descarga.
Bien, vamos al código;
#!/usr/bin/env groovy package smbdownload import java.io.File import jcifs.smb.NtlmPasswordAuthentication import jcifs.smb.SmbFile import jcifs.smb.SmbFileInputStream /** * returns the percent between the lengths of two files **/ def percent(file1,file2){ Math.round(file1.length() / file2.length() * 100) } /** * prints the progress bar **/ def printProgress(percent){ print "[" (0..Math.round(percent / 10)).each{ print "|" } (Math.round(percent/10)..10).each{ print " " } print "] ${percent}% " print "\r" } /** * downloads a SmbFile to a Path * only used to download files, not directories **/ def downloadFile(SmbFile file, String path){ try{ file.connect() def newfile = new File(path+"/"+file.getName()) def f = new FileOutputStream(newfile,true) def is = new BufferedInputStream(file.getInputStream()) def buf = new byte[1024*90] println "\ndownloading..." is.skip(newfile.length()) readf = is.read(buf) while (readf > 0){ printProgress(percent(newfile,file)) f.write(buf,0,readf) readf = is.read(buf) } f.close() println "[||||||||||||] 100%" println "[ok]" return true } catch (Exception e){ println e.getMessage() return false } } /** * lists all files on a base directory **/ def getFilesFromDir(SmbFile baseDir) { SmbFile[] files = baseDir.listFiles() List results = new ArrayList() for (SmbFile file : files) { if (file.isDirectory()) { results.addAll(getFilesFromDir(file)) } else { results.add(file) } } return results } /** * writes the configuration file with .magneto_task extension * in order to resume the task **/ def writeConf(url, pathToSave, ua, user = "", password = ""){ String aux = (String)url while (aux.endsWith("/")){ aux = aux.substring(0,aux.length()-1) } aux = aux.substring(aux.lastIndexOf("/"),aux.length()) println "writing config to "+pathToSave+aux+".magneto_task" File fo = new File(pathToSave+"/"+aux+".magneto_task") fo.append(url+"\n") fo.append(pathToSave+"\n") fo.append(ua+"\n") if (ua == "y"){ fo.append(user+"\n") fo.append(password+"\n") } } public static void main (args) { println "Magneto v1.2 by \$h@" println "download from smb servers without loosing track of your files\n" Console sc = System.console() String url = "" def pathToSave = "." def ua = "n" def user = "" def password = "" if (args.length > 0){ File file = new File(args[0]) try { BufferedReader br = new BufferedReader(new FileReader(file)) url = br.readLine() pathToSave = br.readLine() ua = br.readLine() if (ua == "y"){ user = br.readLine() password = br.readLine() } br.close(); } catch (IOException e) { } } else { url = sc.readLine("url: ") pathToSave = sc.readLine("path to save: ") ua = sc.readLine("use auth (y/n): ") } SmbFile file = null if (ua.equals("y")){ if (user == ""){ user = sc.readLine("user: ") } if (password == ""){ password = new String(sc.readPassword("Password: ")) } NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", user, password) file = new SmbFile(url,auth); } else { file = new SmbFile(url); } if (args.length <= 0){ writeConf(url,pathToSave,ua,user,password) } try{ if (!file.exists()){ println "can't find file ${url}" System.exit(1) } if (file.isDirectory()) { print "listing files...\t" def filelist = getFilesFromDir(file) println "[ok]" print "populating dirs...\t" pathToSave += file.getName() new File(pathToSave).mkdirs() for (SmbFile f in filelist){ new File(pathToSave+"/"+f.getParent().replace(url,"")).mkdirs() } println "[ok]" def c = 0 for (SmbFile f in filelist){ println "file ${++c} of ${filelist.size}" println "starting download for: ${f.getPath()}" while (!downloadFile(f,pathToSave+"/"+f.getParent().replace(url,""))){ sleep(100) } } println "[all done]" } else if (file.isFile()){ println "starting download for: ${file.getName()}" while (!downloadFile(file,pathToSave)){ sleep(100) } } } catch (jcifs.smb.SmbException e){ println "${e.message} [failed]" } catch (java.net.UnknownHostException e){ println "Unknow host [failed]" } }
Es algo extenso el código como pueden ver, pero aún así decidí compartirlo completo para que pueda ser consultado fácilmente desde el mismo navegador. Pueden ejecutarlo de varias formas. teniendo groovy instalado y la librería jcifs en el classpath de java podemos ejecutar desde el terminal ./magneto.groovy lo cual iniciará la aplicación. Si desea tener la aplicación compilada en un .jar para poder compartirla con amigos que no tengan groovy instalado pueden copiar el código dentro de un proyecto de netbeans, compilar como si se tratara de un proyecto de aplicación en consola de java y listo.
Y bien, esto fue todo por hoy. Es un placer estar por aquí de nuevo. Espero que la comunidad siga creciendo y mejorando. Happy Hacking!!!
Comentarios ( 7 )
Good!!!!!!
Protect your computers!!! BIG BRO IS BACK IN TOWN!
Vaya que bueno que hayas reaparecido jajaja. Interesante tu script. No te pierdas!!!
Jaja, por mucha soltura que brinda groovy en la sintaxis al final terminamos tipando y haciendo las cosas a lo Java, jeje. Muy buena tu solución bro, mantente en contacto.
Salu2s…
Saludos a la comunidad de humanos desde Ecuador.
Groovy es fantástico.. convina su sintaxis con la de java al mismo tiempo.. hace muchas cosas que con java llevan muchas líneas de código en pocas líneas y cuando lo usas con el framework Grails en el desarrollo web es muy poderoso. No se porque en la Universidad no lo han adoptado en varios proyectos porque aprovecha la potencia de java, spring, hibernate, motor de plantillas y muchas cosas mas, haciéndote que seas altamente productivo. Yo lo recomiendo ya que lo uso constantemente y con muy buenos resultados.
si hubiera un botoncito de “me gusta” … lo pinchaba!!
Troooolllllllll, jjaja. LIKE, malo que no lo pueda probar aqui.