sábado, 24 de septiembre de 2022

Subir y bajar archivos desde un servidor FTP con una aplicación de VB.Net

Para subir o bajar archivos desde un equipo local a una dirección FTP remota con Visual Basic.Net antes se utilizaba la librería de Visual Studio FtpWebRequest. Pero actualmente la documentación indica que dicha librería será descontinuada y que para nuevos desarrollos se utilicen librerías de terceros. Una librería muy utilizada es FluenFTP que es la que vamos a utilizar.

Lo primero que vamos a hacer es descargar dicha librería, para ello desde nuestro proyecto en Visual Studio vamos al menú  de Proyecto y elegimos la opción Administrar paquetes NuGet.

Administrar paquetes NuGet.

Esto nos abre una pantalla desde al que podemos instalar en nuestra aplicación multitud de paquetes de terceros. En nuestro caso ponemos FTP en el buscador y nos muestra una lista de las librerías disponibles. Elegimos FluentFTP pulsamos el botón Instalar. Esto instala automáticamente la librería en nuestro proyecto. Ahora ya podemos utilizar esta librería desde nuestra aplicación.

FluentFTP

Para tener acceso a sus propiedades, funciones y métodos basta con poner la correspondiente llamada Imports, al comienzo de nuestra aplicación de Visual Basic.Net

 

Imports FluentFTP

 

El siguiente paso será definir un Objeto de la clase FTPClient, para ello escribimos

 

Dim client = New FtpClient(strFTP, strUsuario, strPassword)

 

Donde strFTP será una variable de tipo string que traerá la dirección del FTP, ojo, hay que tener en cuenta que será una dirección del tipo ftp://servidor.remoto.es/DIRECTORIO  Si no trae el ftp:// del principio se lo podemos añadir por programa con algo así:

 

strFTP = "ftp://" & strDireccionDestino

 

strUsuario y strPassword traerán el usuario y contraseña correspondientes para conectarnos al servidor FTP deseado. También debemos conectarnos al servidor. Con esta librería es tan fácil como escribir:

 

client.Connect()

 

Ahora lo que queremos es pasar un archivo desde un directorio de nuestro equipo a un FTP remoto. Escribimos la siguiente línea.

 

client.UploadFile(strDireccionOrigen & "\" & strNombreOrigen, strNombreDestino)

 

Donde en strDireccionOrigen vendrá una cadena con la dirección de nuestro equipo del tipo  “C:\Directorio\Subdirectorio” en strNombreOrigen vendrá el nombre de nuestro archivo de origen, y si deseamos nombrarlo con un nuevo nombre podemos almacenar el nuevo nombre en strNombreDestino o podemos enviar directamente strNombreOrigen en el segundo parámetro si deseamos que el archivo se llame igual que el del origen.

 

Si deseamos copiarlo en un subdirectorio del FTP podemos hacer

 

client.UploadFile(strDireccionOrigen & "\" & strNombreOrigen, strSubdirectorio_FTP & "/" & strNombreDestino)

 

Donde strSubdirectorio_FTP traerá el nombre del subdirectorio del tipo “/SUBDIRECTORIO” no siendo necesario escribir el nombre completo del FTP.

 

Esta función tiene varias sobrecargas, de modo que podemos hacer

 

client.UploadFile(strDireccionOrigen & "\" & strNombreOrigen, strSubdirectorios_FTP & "/" & strNombreDestino, FtpRemoteExists.Overwrite, True, FtpVerify.Retry)

 

Esta llamada Sobreescribe el archivo en destino si ya existe uno del mismo nombre. Esto lo hace el parámetro FtpRemoteExists.Overwrite, el siguiente parámetro True indica que si no existe el directorio en el destino lo crea, y el último parámetro FtpVerify.Retry verifica si se ha copiado el archivo correctamente en el FTP.

 

Finalmente cerramos la conexión

 

client.Disconnect()

 

Ahora vamos a traer un archivo desde FTP a nuestro equipo. Para ello creamos el objeto y abrimos la conexión igual que hicimos anteriormente

 

Dim client = New FtpClient(strFTP, strUsuario, strPassword)

client.Connect()

 

Ahora para traer el archivo desde el FTP remoto tenemos que hacer un For Each sobre los objetos del FTP remoto para traer todos los que encontremos

 

For Each item As FtpListItem In client.GetListing(strSubdirectorios_FTP)

                    client.DownloadFile(strDireccionDestino & item.FullName, item.FullName, FtpLocalExists.Overwrite)

                   

                    client.DeleteFile(item.FullName)

Next item

                   

En este caso, si el archivo se encuentra en un subdirectorio del FTP, nos lo creará en el destino indicado de nuestro equipo y escribirá los archivos en el directorio creado, estos vendrán en strSubdirectorios_FTP. Si el FTP no tiene subdirectorios podemos hacer strSubdirectorios_FTP = “”. Para no dejar los archivos copiados en el FTP de origen podemos borrarlos con

 

client.DeleteFile(item.FullName)

 

Terminamos igual que en el caso anterior con

 

client.Disconnect()

 

Finalmente dejo como podrían ser las dos Funciones para enviar y obtener ficheros desde nuestro equipo a un FTP.  Esta sería para llevar un archivo desde nuestro equipo al FTP remoto.

 

Private Function Trata_Archivo_FTP(ByVal Folder_file As Object,  ByVal strDireccionOrigen As String, ByVal strDireccionDestino As String, ByVal strUsuario As String, ByVal StrPassword As String) As Boolean

        Dim strNombreOrigen As String = ""

        Dim strNombreDestino As String = ""

        Dim strSubdirectorios_FTP As String = "/SUBDIR_FTP"

 

                Try

                

            'crea un cliente FTP

            Dim client = New FtpClient(strFTP, strUsuario, StrPassword)

            client.Connect()

 

            For Each File As FileInfo In Folder_file

                strNombreOrigen = File.Name

                strNombreDestino = File.Name

                    'sube un archivo a un FTP

                    client.UploadFile(strDireccionOrigen & "\" & strNombreOrigen, strSubdirectorios_FTP & "/" & strNombreDestino, FtpRemoteExists.Overwrite, True, FtpVerify.Retry)

                    'Como el origen del fichero no es FTP, borramos archivo en nuestro equipo

                    My.Computer.FileSystem.DeleteFile(strDireccionOrigen & "\" & strNombreOrigen)

        Next

            'desconecta FTP

            client.Disconnect()

            Trata_Archivo_FTP = False

        Catch ex As Exception

        End Try

    End Function

 

La función anterior recorre nuestro directorio local pasado en strDireccionOrigen para ver los archivos que tiene, para ello tiene como parámetro de entrada el objeto Folder_file. La llamada a esta función será de este estilo:

 

Dim folder As New DirectoryInfo(strDireccionOrigen)

bErrores = Trata_Archivo_FTP(folder.GetFiles(), strDireccionOrigen, strDireccionDestino, strUsuarioFTP, strPasswordFTP)

 

Una definición de la función para traer un archivo al equipo local desde un FTP podría ser de este estilo:

Private Function Trata_FTP_Archivo(ByVal strDireccionDestino As String, ByVal strUsuario As String, ByVal strPassword As String) As Boolean

        Dim strNombreOrigen As String = ""

        Dim strNombreDestino As String = ""

        Dim strSubdirectorios_FTP As String ="/SUBDIR_FTP"

 

        Try

 

            'crea un FTP cliente

            Dim client = New FtpClient(strFTP, strUsuario, strPassword)

            client.Connect()

            'Se trae todo lo que hay en el FTP remoto

            For Each item As FtpListItem In client.GetListing(strSubdirectorios_FTP)

               

                    client.DownloadFile(strDireccionDestino & item.FullName, item.FullName, FtpLocalExists.Overwrite)

               client.DeleteFile(item.FullName)

 

            Next ítem

            'desconecta

            client.Disconnect()

            Trata_FTP_Archivo = False

        Catch ex As Exception

            MsgBox(ex.Message)

        End Try

    End Function

Si queremos hacer un traspaso de FTP a FTP yo no he sido capaz de hacerlo directamente con FTPFluent, pero si llamando a estas dos  funciones descritas arriba alternativamente utilizando el directorio del equipo local C:\FTP como repositorio para almacenar los archivos traídos desde un FTP antes de enviarlos al FTP de destino.

Dim strAuxDireccion As String

bErrores = Trata_FTP_Archivo(strDireccionOrigen, "C:\FTP", strUsuarioFTP_Ori, strPasswordFTP_Ori)

Dim folder2 As New DirectoryInfo(strAuxDireccion)

 

bErrores = Trata_Archivo_FTP(folder2.GetFiles(),strAuxDireccion, strDireccionDestino, strUsuarioFTP_Des, strPasswordFTP_Des)

Hay que tener en cuenta, que si el FTP de origen tiene los archivos en un subdirectorio, creará el subdirectorio sobre C:\FTP con lo que tendremos que tratarlo para que no de error al leerlo de nuevo. Dentro de Trata_Archivo_FTP debemos sacar el subdirectorio creado con algo como esto:

Dim strFTP As String

Dim intPosBarra As Integer

            'Si la direccion FTP es un directorio separa el servidor y los subdirectorios

intPosBarra = InStr(strDireccionDestino, "/")

If intPosBarra <> 0 Then

      strSubdirectorios_FTP = Mid(strDireccionDestino, intPosBarra)

      strFTP = "ftp://" & Mid(strDireccionDestino, 1, intPosBarra)

Else

      strSubdirectorios_FTP = ""

      strFTP = "ftp://" & strDireccionDestino

End If

 

Y en Trata_FTP_Archivo, algo como esto

 

Dim intPosBarra As Integer

Dim strAuxDir() As String

            'Si la direccion FTP es un directorio separa el servidor y los subdirectorios

            intPosBarra = InStr(strDireccionOrigen, "/")

            If intPosBarra <> 0 Then

                strSubdirectorios_FTP = Mid(strDireccionOrigen, intPosBarra)

                strFTP = "ftp://" & Mid(strDireccionOrigen, 1, intPosBarra)

            Else

                strSubdirectorios_FTP = ""

                strFTP = "ftp://" & strDireccionOrigen

            End If




sábado, 17 de septiembre de 2022

Archivos externos de recursos resx en .NET

Para no tener que recompilar un proyecto cuando cambian ciertas condiciones (rutas, ubicaciones, etc) conviene almacenar algunas variables en un archivo externo de recursos .resx donde podremos modificar manualmente dichas variables sin tener que recompilar de nuevo el proyecto.

1ª Opción

En nuestro proyecto, elegimos proyecto -> propiedades

 

Archivos externos de recursos resx en .NET

Vamos a la última pestaña de recursos y pulsamos sobre “Este proyecto no contiene un archivo de recursos predeterminado….”

 

Este proyecto no contiene un archivo de recursos predeterminado

Esta acción, nos abre una pantalla de recursos donde podemos introducir la declaración de variables y sus valores correspondientes

 

declaración de variables y sus valores correspondientes

Hecho esto, no es necesario que declaremos dichas variables en el código, podemos referirnos a ellas desde nuestro código tecleando My.Resources.[Nombre_Variable]

Estas definiciones se encuentran en la carpeta My Project del explorador de soluciones

 

carpeta My Project del explorador de soluciones

Podemos ir al directorio de nuestro proyecto y en la carpeta My Project encontraremos un archivo llamado Resources.resx donde se encuentran definidas nuestras variables, podemos modificar sus valore directamente en el archivo abriéndolo con un editor, por ejemplo notepad++


notepad++


Y al final del archivo aparecen nuestras definiciones donde podemos cambiar los valores sin necesidad de recompilar el proyecto

 

definiciones donde podemos cambiar los valores

En este ejemplo hemos utilizado rutas, pero si no escribimos bien la ruta puede dar error, porque en realidad leerá C:\Ruta_Aplicacion\C:\PRUEBAS Hay que estar atentos a ver que parte de la ruta ponemos, podemos poner por ejemplo en vez de C:\PRUEBAS poner sólo pruebas, y el programa lo añadirá a la ruta de la aplicación, pero si queremos una ruta diferente de la aplicación podemos utilizar la segunda opción.

2ª Opción

Otra solución consiste en añadir un archivo de configuración app.config o settings. En el explorador de soluciones con el botón derecho del ratón pulsamos Agregar -> Nuevo elemento

app.config o settings


Sobre la pestaña General de Elementos comunes, elegimos Archivo de configuración 


Pestaña General de Elementos comunes

Ahora nos sale una pantalla donde podemos elegir el nombre de la variable y su valor

 

Archivo de configuración

Si el código creado automáticamente no funciona, podemos editarlo manualmente y dejarlo de este modo:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

     <configSections>

          <sectionGroup name="applicationSettings"

                      type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >

 

                <section name="Nombre_de_tu_Proyecto.Properties.Settings"

                     type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

                     requirePermission="false" />

 

          </sectionGroup>

     </configSections>

   

     <appSettings>

          <!--Directorio de entrada de los ficheros-->

          <add key="dirEntrada" value="C:\Pruebas" />

          <!--Directorio de salida para el fichero una vez unido-->

          <add key="dirSalida" value="C:\Pruebas\Out" />

          <!--Directorio donde se deja la copia del original-->

          <add key="dirCopiaOriginal" value="C:\Pruebas\Original" />

          <add key="dirTemporal" value="C:\Pruebas\TEMPORAL" />

          <!--Posicion final e inicial de coincidencia de archivos-->

          <add key="posInicial" value= "1" />

          <add key="posFinal" value= "1" />

     </appSettings>

</configuration>


Luego en el código le llamamos así a las variables definidas.

Dim dirEntrada As String = ConfigurationManager.AppSettings("dirEntrada").ToString()

Para que el código nos reconozca las instrucciones de llamada a ConfigurationManage, es importante importar antes la librería System.Configuration

Imports System.Configuration

Si aun así no funciona, es posible que tengamos que instalar el paquete System.Configuration desde nuget, para ello sobre el error pulsamos en Mostrar posibles correcciones del error.

Mostrar posibles correcciones del error.


Esto nos despliega un combo con las diferentes opciones, elegimos Instalar Paquete “System.ConfigurationManager” -> Buscar e instalar la última versión

 

Instalar Paquete “System.ConfigurationManager” -> Buscar e instalar la última versión

Ahora ya podemos editar el archivo app.config o settings para cambiar los valores de las variables definidas, sin necesidad de recompilar el proyecto cada vez.