Lo prometido es deuda, así que vamos a ver (más bien a repasar) el tema de FTP.
Tengo varias cosas que contar antes de empezar (como de costumbre)...
Estoy preparando mucho (MUCHO) material nuevo para el blog, solo necesito tiempo para estructurarlo... será un curso entero, también (no tan extenso como el de matemáticas, pero tendrá "chicha").
¡¡Ya hemos lanzado nuestro canal de YouTube!! Aquí podéis encontrarlo. Podréis ver cómo DoH (yo), Meryhell (co-propietaria de Cosplay & Co, junto a mi), y James_Strange jugamos a nuestros juegos favoritos... a veces logran sacarnos de quicio (literalmente), jejeje :-)
Cuando acabe esta saga (es decir, antes de empezar el tema III de matemáticas), habrá una pequeña entrada de "Las aventuras de DoHITB"...
Dejando de lado la "vida privada", vayamos a lo que hemos venido a hacer... ¡FTP con VB.net!
En esta entrada tenéis una visión globlal del uso de FTP bajo VB.net.
Vamos, partiendo de esa base, a realizar algunas mejoras; a la vez que dejaremos el código más accesible y configurable.
El código original se basaba, principalmente, en dos funciones públicas:
subirFichero(ByVal fichero As String, ByVal destino As String, ByVal dir As String) As String
bajarArchivo(ByVal fichero As String, ByVal destino As String) As Boolean
A su vez, éstos delegaban en varias funciones privadas, que gestionaban temas como ver si el directorio a acceder existía, o si existía cierto archivo.
Como dijimos antes, vamos a realizar algunas mejoras en el código para dejar la clase más accesible, y sobretodo, más "configurable".
Vamos allá.
Empezamos con los métodos públicos.
subirFichero:
a) Lo renombraremos, usando una notación "estándar", por "subirObjeto".
b) Modificaremos un poco el código:
Public Function subirObjeto(ByVal objeto As String, ByVal destino As String, ByVal dir As String) As String
Dim infoFichero As New FileInfo(objeto)
Dim uri As String = destino
If Not existeObjeto(dir) and Me.crearSiNo Then
creaDirectorio(dir)
Else
Return "No se ha subido el archivo por que no existe el directorio"
End If
Dim peticionFTP As FtpWebRequest = CType(FtpWebRequest.Create(New Uri(destino)), FtpWebRequest)
Me.configurarFTP(peticionFTP, WebRequestMethods.Ftp.UploadFile)
peticionFTP.KeepAlive = False
peticionFTP.UsePassive = False
peticionFTP.UseBinary = Me.useBinary
peticionFTP.ContentLength = infoFichero.Length
Dim lector As Byte() = New Byte(Me.longitudBuffer) {}
Dim num As Integer
Dim fs As FileStream = infoFichero.OpenRead()
Try
Dim escritor As Stream = peticionFTP.GetRequestStream()
num = fs.Read(lector, 0, Me.longitudBuffer)
While (num <> 0)
escritor.Write(lector, 0, num)
num = fs.Read(lector, 0, longitudBuffer)
End While
escritor.Close()
fs.Close()
Return String.Empty
Catch ex As Exception
Return ex.Message
End Try
End Function
Dim infoFichero As New FileInfo(objeto)
Dim uri As String = destino
If Not existeObjeto(dir) and Me.crearSiNo Then
creaDirectorio(dir)
Else
Return "No se ha subido el archivo por que no existe el directorio"
End If
Dim peticionFTP As FtpWebRequest = CType(FtpWebRequest.Create(New Uri(destino)), FtpWebRequest)
Me.configurarFTP(peticionFTP, WebRequestMethods.Ftp.UploadFile)
peticionFTP.KeepAlive = False
peticionFTP.UsePassive = False
peticionFTP.UseBinary = Me.useBinary
peticionFTP.ContentLength = infoFichero.Length
Dim lector As Byte() = New Byte(Me.longitudBuffer) {}
Dim num As Integer
Dim fs As FileStream = infoFichero.OpenRead()
Try
Dim escritor As Stream = peticionFTP.GetRequestStream()
num = fs.Read(lector, 0, Me.longitudBuffer)
While (num <> 0)
escritor.Write(lector, 0, num)
num = fs.Read(lector, 0, longitudBuffer)
End While
escritor.Close()
fs.Close()
Return String.Empty
Catch ex As Exception
Return ex.Message
End Try
End Function
Vemos varios cambios en el cuerpo de la función:
- Variable de clase "crearSiNo": podemos hacer que, en caso de no existir el directorio, retorne un error.
- Método "configurarFTP" : configura la parte común de todos los métodos (respecto al FTPWebRequest)
- Variable de clase "useBinary": podemos especificar si la transferencia será en modo binario (true) o no (false)
- Variable de clase "longitudBuffer": podemos indicar el tamaño de buffer, y variarlo entre llamadas (dependiendo, por ejemplo, del tamaño de archio o la carga de memoria de la máquina)
Vamos a ver ahora "bajarArchivo" (rebautizado como "bajarObjeto")
Public Function bajarObjeto(ByVal fichero As String, ByVal destino As String) As Boolean
Dim localfile As String = destino
Dim peticionFTP As FtpWebRequest = CType(FtpWebRequest.Create(New Uri(fichero)), FtpWebRequest)
Me.configurarFTP(peticionFTP, WebRequestMethods.Ftp.DownloadFile)
peticionFTP.KeepAlive = False
peticionFTP.UsePassive = False
Try
Using response As System.Net.FtpWebResponse = CType(peticionFTP.GetResponse, System.Net.FtpWebResponse)
Using responseStream As IO.Stream = response.GetResponseStream
Using fs As New IO.FileStream(localfile, IO.FileMode.Create)
Dim buffer(longitudBuffer - 1) As Byte
Dim read As Integer = 0
Do
read = responseStream.Read(buffer, 0, buffer.Length)
fs.Write(buffer, 0, read)
Loop Until read = 0
responseStream.Close()
fs.Flush()
fs.Close()
End Using
responseStream.Close()
End Using
response.Close()
End Using
Return true
Catch ex As Exception
MsgBox(ex.Message)
End Try
Return false
End Function
Dim localfile As String = destino
Dim peticionFTP As FtpWebRequest = CType(FtpWebRequest.Create(New Uri(fichero)), FtpWebRequest)
Me.configurarFTP(peticionFTP, WebRequestMethods.Ftp.DownloadFile)
peticionFTP.KeepAlive = False
peticionFTP.UsePassive = False
Try
Using response As System.Net.FtpWebResponse = CType(peticionFTP.GetResponse, System.Net.FtpWebResponse)
Using responseStream As IO.Stream = response.GetResponseStream
Using fs As New IO.FileStream(localfile, IO.FileMode.Create)
Dim buffer(longitudBuffer - 1) As Byte
Dim read As Integer = 0
Do
read = responseStream.Read(buffer, 0, buffer.Length)
fs.Write(buffer, 0, read)
Loop Until read = 0
responseStream.Close()
fs.Flush()
fs.Close()
End Using
responseStream.Close()
End Using
response.Close()
End Using
Return true
Catch ex As Exception
MsgBox(ex.Message)
End Try
Return false
End Function
Cambios realizados:
- Cambio en el nombre del método
- Eliminada variable de retorno; ahora el retorno se hace de manera directa (Return true / Return false)
- Optimizado el código con la función "configurarFTP".
Veamos, ahora, el método privado "configurarFTP":
Private Sub configurarFTP(ByRef ftp As FtpWebRequest, ByVal tipo As String)
peticionFTP.Credentials = New NetworkCredential(user, pass)
peticionFTP.Method = tipo
End Sub
peticionFTP.Credentials = New NetworkCredential(user, pass)
peticionFTP.Method = tipo
End Sub
Como vemos, son dos líneas de nada. Pero dos líneas que nos ahorramos por método, a fin de cuentas es un ahorro (aunque pequeño), ¿no? :-)
Vamos ahora con las funciones privadas:
Empezamos por "existeObjeto":
Private Function existeObjeto(ByVal dir As String) As Boolean
Dim peticionFTP As FtpWebRequest = CType(WebRequest.Create(New Uri(dir)), FtpWebRequest)
Me.configurarFTP(peticionFTP, WebRequestMethods.Ftp.GetDateTimestamp)
peticionFTP.UsePassive = False
Try
Dim respuestaFTP As FtpWebResponse = CType(peticionFTP.GetResponse(), FtpWebResponse)
Return True
Catch ex As Exception
Return False
End Try
End Function
Dim peticionFTP As FtpWebRequest = CType(WebRequest.Create(New Uri(dir)), FtpWebRequest)
Me.configurarFTP(peticionFTP, WebRequestMethods.Ftp.GetDateTimestamp)
peticionFTP.UsePassive = False
Try
Dim respuestaFTP As FtpWebResponse = CType(peticionFTP.GetResponse(), FtpWebResponse)
Return True
Catch ex As Exception
Return False
End Try
End Function
Mejoras:
- Optimizado código usando la función "configurarFTP".
Echemos un ojo a la función "crearDirectorio"
Private Function creaDirectorio(ByVal dir As String) As String
Dim peticionFTP As FtpWebRequest = CType(WebRequest.Create(New Uri(dir)), FtpWebRequest)
Me.configurarFTP(peticionFTP, WebRequestMethods.Ftp.MakeDirectory)
Try
Dim respuesta As FtpWebResponse
respuesta = CType(peticionFTP.GetResponse(), FtpWebResponse)
respuesta.Close()
Return String.Empty
Catch ex As Exception
Return ex.Message
End Try
End Function
Dim peticionFTP As FtpWebRequest = CType(WebRequest.Create(New Uri(dir)), FtpWebRequest)
Me.configurarFTP(peticionFTP, WebRequestMethods.Ftp.MakeDirectory)
Try
Dim respuesta As FtpWebResponse
respuesta = CType(peticionFTP.GetResponse(), FtpWebResponse)
respuesta.Close()
Return String.Empty
Catch ex As Exception
Return ex.Message
End Try
End Function
Mejoras:
- Optimizado código usando la función "configurarFTP"
Con esto, casí está lista nuestra mejorada clase para FTP sobre VB.net; faltaría ver los campos de clase:
Dim host, user, pass As String
Dim crearSiNo, useBinary As Boolean
Dim longitudBuffer as Integer
Dim crearSiNo, useBinary As Boolean
Dim longitudBuffer as Integer
De esta manera, el nuevo constructor sería:
Public Sub New(ByVal host As String, ByVal user As String, ByVal pass As String)>
Me.host = host
Me.user = user
Me.pass = pass
Me.crearSiNo = True
Me.useBinary = True
Me.longitudBuffer = 2048
End Sub
Me.host = host
Me.user = user
Me.pass = pass
Me.crearSiNo = True
Me.useBinary = True
Me.longitudBuffer = 2048
End Sub
Lo último (para rizar el rizo) sería elaborar "setters" para las variables de clase. Esta parte la omitiremos de código, pero es esencial que estén presentes para poder dar la funcionalidad total a la clase.
Veamos, una vez más, cómo usar esta clase para usar FTP:
Dim ftp As New Ftp("miweb.com", "usuario", "pass")
ftp.bajarArchivo("archivo/a/bajar", "ruta/a/bajar")
ftp.subirFichero("fichero/a/subir", "ftp://miweb.com/", "carpeta/de/destino")
Como último aspecto a destacar, comentar una "ayuda" que nos brinda VB.net: el objeto "Environment".
Éste tiene un método llamado "GetEnvironmentVariable", al que le pasamos un String, y retorna el valor de dicha variable de entorno.
Es decir, para aquellos que no estén familiarizados con las variables de entorno:
Las variables de entorno son aquellas que están "grabadas" en el sistema, y permiten crear "atajos", configurar aplicaciones, y diversas cosas más.
Ejemplos de algunas varialbes de entorno son TEMP, TMP, APPDATA, USERPROFILE... que contienen rutas a carpetas de sistema (o carpetas útiles).
De esta manera, a la hora de realizar una instalación, nos podemos referir a estas rutas mediante su variable de entorno, haciéndolas "relativas".
Con esto, podemos referirnos a la carpeta de sistema, o a la ruta donde se instalan los programas por defecto (APPDATA), sin tener que escribirla a mano (puede que un usuario tenga los programas en otra carpeta, o incluso en otra unidad del sistema).
Así, usando esta facilidad, podremos acceder a los ficheros de una manera más "universal".
Espero que os sea útil la entrada. Recordad que yo solo os brindo conocimiento (¡cómo lo uséis es cosa vuestra!)
Como siempre digo,
¡Hasta la próxima!
No hay comentarios:
Publicar un comentario