Etiqueta: VB.NET

Temas relacionados con Visual Basic para .NET Framework

  • Descargar archivos de un FTP

    Pues eso… un artículillo "tesnico" para que no digas..

    Esto lo publico a raíz de una pregunta en mis foros… y más que nada porque pensaba que ya lo tenía publicado, pero se ve que no… ya que tenía un ejemplo para acceder a un servidor FTP pero sólo para listar el contenido de un directorio FTP.

    La cuestión es que en realidad ese código que publiqué con un par de añadidos sirve para poder descargar un archivo (o fichero) de un directorio FTP y aquí te los mostraré tanto para Visual Basic.NET como para Visual C#.

    La clase en cuestión que nos sirve para hacer esto que te comento es FtpWebRequest que está definida en el espacio de nombres System.Net.

    Y sin más preámbulos (ni rollos) aquí tienes el código de VB y C#.

    ¡Que lo descargues bien!

     

    Código de VB

    '------------------------------------------------------------------------------
    ' Descargar archivos de un FTP                                      (06/Dic/11)
    '
    ' ©Guillermo 'guille' Som, 2011
    '------------------------------------------------------------------------------
    Option Strict On
    Option Infer On
    
    Imports System
    Imports System.Net
    Imports System.IO
    Imports System.Text
    
    Module Module1
    
        Sub Main()
            ' En este ejemplo usamos un FTP público y anónimo
            ' pero puedes indicar el que quieras
            descargarFic("ftp://ftp.rediris.es/welcome.msg", _
                         "anonimous@nadie.com", "", _
                         "E:\pruebas2")
    
            Console.WriteLine("descargado")
            Console.ReadLine()
        End Sub
    
        Private Sub descargarFic(ByVal ficFTP As String, _
                                 ByVal user As String, ByVal pass As String, _
                                 dirLocal As String)
    
            Dim dirFtp As FtpWebRequest = CType(FtpWebRequest.Create(ficFTP), FtpWebRequest)
    
            ' Los datos del usuario (credenciales)
            Dim cr As New NetworkCredential(user, pass)
            dirFtp.Credentials = cr
    
            ' El comando a ejecutar usando la enumeración de WebRequestMethods.Ftp
            dirFtp.Method = WebRequestMethods.Ftp.DownloadFile
    
            ' Obtener el resultado del comando
            Dim reader As New StreamReader(dirFtp.GetResponse().GetResponseStream())
    
            ' Leer el stream (el contenido del archivo)
            Dim res As String = reader.ReadToEnd()
    
            ' Mostrarlo.
            'Console.WriteLine(res)
    
            ' Guardarlo localmente con la extensión .txt
            Dim ficLocal As String = Path.Combine(dirLocal, Path.GetFileName(ficFTP) & ".txt")
            Dim sw As New StreamWriter(ficLocal, False, Encoding.Default)
            sw.Write(res)
            sw.Close()
    
            ' Cerrar el stream abierto.
            reader.Close()
        End Sub
    
        Sub listarFTP(ByVal dir As String, ByVal user As String, ByVal pass As String)
            Dim dirFtp As FtpWebRequest = CType(FtpWebRequest.Create(dir), FtpWebRequest)
    
            ' Los datos del usuario (credenciales)
            Dim cr As New NetworkCredential(user, pass)
            dirFtp.Credentials = cr
    
            ' El comando a ejecutar
            dirFtp.Method = "LIST"
    
            ' También usando la enumeración de WebRequestMethods.Ftp
            dirFtp.Method = WebRequestMethods.Ftp.ListDirectoryDetails
    
            ' Obtener el resultado del comando
            Dim reader As New StreamReader(dirFtp.GetResponse().GetResponseStream())
    
            ' Leer el stream
            Dim res As String = reader.ReadToEnd()
    
            ' Mostrarlo.
            Console.WriteLine(res)
    
            ' Cerrar el stream abierto.
            reader.Close()
        End Sub
    End Module

     

     

    Código de C#

    //-----------------------------------------------------------------------------
    // Descargar archivos de un FTP                                     (06/Dic/11)
    //
    // ©Guillermo 'guille' Som, 2011
    //-----------------------------------------------------------------------------
    
    using System;
    using System.Text;
    using System.Net;
    using System.IO;
    
    namespace descargar_archivos_FTP_cs
    {
        class Program
        {
            static void Main(string[] args)
            {
                descargarFic("ftp://ftp.rediris.es/welcome.msg", 
                    "anonimous@nadie.com", "", @"E:\pruebas2");
    
                Console.WriteLine("descargado");
                Console.ReadLine();
            }
    
            static void descargarFic(string ficFTP, string user, string pass, string dirLocal)
            {
                FtpWebRequest dirFtp = ((FtpWebRequest)FtpWebRequest.Create(ficFTP));
    
                // Los datos del usuario (credenciales)
                NetworkCredential cr = new NetworkCredential(user, pass);
                dirFtp.Credentials = cr;
    
                // El comando a ejecutar usando la enumeración de WebRequestMethods.Ftp
                dirFtp.Method = WebRequestMethods.Ftp.DownloadFile;
    
                // Obtener el resultado del comando
                StreamReader reader =
                    new StreamReader(dirFtp.GetResponse().GetResponseStream());
    
                // Leer el stream
                string res = reader.ReadToEnd();
    
                // Mostrarlo.
                //Console.WriteLine(res);
    
                // Guardarlo localmente con la extensión .txt
                string ficLocal = Path.Combine(dirLocal, Path.GetFileName(ficFTP) + ".txt");
                StreamWriter sw = new StreamWriter(ficLocal, false, Encoding.UTF8);
                sw.Write(res);
                sw.Close();
    
                // Cerrar el stream abierto.
                reader.Close();
            }
    
            static void listarFTP(string dir, string user, string pass)
            {
                FtpWebRequest dirFtp = ((FtpWebRequest)FtpWebRequest.Create(dir));
    
                // Los datos del usuario (credenciales)
                NetworkCredential cr = new NetworkCredential(user, pass);
                dirFtp.Credentials = cr;
    
                // El comando a ejecutar
                dirFtp.Method = "LIST";
    
                // También usando la enumeración de WebRequestMethods.Ftp
                dirFtp.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
    
                // Obtener el resultado del comando
                StreamReader reader =
                    new StreamReader(dirFtp.GetResponse().GetResponseStream());
    
                // Leer el stream
                string res = reader.ReadToEnd();
    
                // Mostrarlo.
                Console.WriteLine(res);
    
                // Cerrar el stream abierto.
                reader.Close();
            }
        }
    }

     

     

    Nos vemos.

    Guillermo

    …

  • El número de decimales del tipo decimal de SQL Server

    Pues eso… últimamente estoy «trasteando» en un programa (hecho con Visual Basic 2010) que accede a una base de datos de SQL Server Express 2005 y quisiera ir poniendo por aquí las cosillas que me voy encontrando mientras «tecleo» en ese programa, y lo último que he modificado es esto que te muestro, que no es que no lo hubiera detectado antes, pero haciendo pruebas hoy he visto que me había dejado «sin optimizar» un campo de una de las tablas.

    El tema es el siguiente:

    Cuando añades un campo a una tabla de SQL Server (en mi caso con el SQL Server Management Studio 2008 (Express)) y le indicas que es de tipo decimal, automáticamente te lo pone de esta forma:

    decimal(18, 0)

    El 18 es la precisión, o número de dígitos que puede tener este número, y el 0 es la «escala» o número de decimales que puede tener este número.

    Como verás cero decimales no es algo que sea demasiado aceptable en valores de tipo moneda, que sí, que podía haber elegido el tipo «money» y me hubiese quitado de problemas, pero de haberlo hecho no te estaría contando esto y… puede que un día te diera por usar el tipo «decimal» por aquello de que es el más parecido al tipo «moneda» que tiene el punto net y lo mismo te preguntarías por qué narices me redondea el número cuando lo guarda en la base de datos… sí, podría ocurrirte esto… como le ocurrió a uno que me conozco…

    La cuestión es que si quieres usar el tipo «decimal» de SQL Server para que acepte un número de decimales (por ejemplo cuatro decimales) tendrías que declararlo de esta otra forma:

    decimal(18, 4)

     

    Y debido a que a la hora de usar este valor desde la base de datos el número de dígitos decimales siempre se guarda (aunque sean todos ceros), me he creado una función que recibe un valor de tipo Object y lo convierte en cadena (String), pero quitando los ceros extras que tenga y en el caso de que el valor «total» sea cero, al menos deje un cero (pero siempre que esté a la izquierda del decimal).

     

    Esta función para quitar los ceros extras que añade el SQL Server:

    ''' <summary>
    ''' Convierte un tipo Object en un valor Decimal,
    ''' pero se devuelve como cadena.
    ''' Ese objeto es el valor leído de la base de datos
    ''' Si el contenido es válido se devuelve el valor
    ''' si no, se devuelve una cadena vacía.
    ''' Se quitan los ceros que haya después del signo decimal,
    ''' si no tiene decimales, no se muestran los ceros.
    ''' </summary>
    Friend Function dataDecimal(ByVal obj As Object) As String
        If obj Is Nothing OrElse obj.Equals(DBNull.Value) Then
            Return ""
        Else
            ' Conversión extra para evitar "sustos"                 (06/Oct/11)
            Dim d As Decimal = 0
            Decimal.TryParse(obj.ToString, d)
            Return d.ToString.TrimEnd("0"c).TrimEnd({"."c, ","c})
    
            'Return CDec(obj).ToString.TrimEnd("0"c).TrimEnd({"."c, ","c})
    
        End If
    End Function

     

    Como ves, no me fio de que el valor recibido sea un valor decimal válido, por eso hago algunas comprobaciones.

    La primera es saber si el valor pasado como argumento a la función es un valor nulo, ya sea «nulo de punto net» o nulo de base de datos (DBNull.Value), en ese caso, la función devuelve una cadena vacía.

    La segunda es usar TryParse para no producir una excepción (o error) en el caso de que el valor de ese objeto no sea «convertible» a un tipo Decimal.

    La función TryParse recibe un valor de tipo cadena que será el valor a convertir (en este caso a un tipo Decimal) y en el segundo parámetro le indicamos un valor (por referencia) del mismo tipo al que queremos convertir, de forma que si la conversión falla, se utilice el valor que previamente tenga dicha variable.

    En el caso de que la conversión NO falle, se asignará a la variable de ese segundo argumento el valor que de como resultado la conversión. Por eso debe ser por referencia, para que la variable se pueda modificar dentro de la función.

     

    Como queremos quitar todos los ceros que «sobren» por el final, utilizo la función TrimEnd al valor convertido (el que tiene la variable d) indicándole el carácter que quiero quitar, esa función recibe como parámetro un valor de tipo Char indicando qué carácter queremos quitar del final, y como Visual Basic permite indicar los caracteres en la forma «cadena» seguida de la letra c, pues… eso es lo que he hecho, por tanto «0»c significa que es el carácter CERO (o valor 48).

    Esto seguramente ya lo sabías, pero… no está de más una aclaración.

     

    Si el valor almacenado en la base de datos no tiene decimales (por ejemplo el número 205) con el TrimEnd que hemos hecho se nos quedaría la coma (o el punto) que indica que hay decimales, por tanto volvemos a hacer un TrimEnd al resultado del TrimEnd anterior, pero en este caso queremos quitar tanto las comas como los puntos, es decir, queremos quitar «dos tipos de caracteres», en estos casos, la función TrimEnd permite indicar un array (o arreglo o matriz) de caracteres con cada uno de los caracteres a quitar del final de la cadena.

    Los caracteres individuales ya sabes cómo indicarlos, y si lo que quieres indicar es un array, esos caracteres individuales los separas con comas y los incluyes entre llaves: {«.»c, «,»c}.

     

    Y esto es todo.

     

    Sólo me queda decirte cómo lo utilizo:

    En mi caso (en este programa que estoy haciendo) lo hago de dos formas:

    En una leo el valor de la tabla en un DataTable y accedo a cada valor por medio de un objeto que representa a la fila (DataRow) a la que estoy accediendo:

     

    For Each r As DataRow In dt.Rows
        Dim lvi As New ListViewItem
    
    ...
    
    lvi.SubItems.Add(dataDecimal(r("Importe")))
    
    ...

     

    En la otra accedo a los valores por medio de un objeto SqlDataReader y básicamente hago lo mismo:

     

    Dim re As SqlDataReader = cmd.ExecuteReader()
    
    ...
    
    ImporteTextBox.Text = dataDecimal(re("Importe"))
    
    ...

     

    Espero que te sea de utilidad.

     

    Nos vemos.
    Guillermo

    P.S. (08/Dic/18)
    Creo que esto también te interesará:
    Error al guardar datos decimales: El valor del parámetro ‘xxx’ está fuera del intervalo

    …

  • Reutilizar un control en otros controles

    Pues eso… aquí te voy a explicar cómo usar un mismo control en más de un "contenedor" (o colección de controles), y como comprobarás, en principio, es algo muy simple de hacer (una vez que se sabe cómo hacerlo, claro, que si no… ¡ja! ya me dirás tú cómo lo harías si nadie lo explicara, pues eso…)

     

    Sí, es un tema técnico… 😉 pero eso no quiere decir que no lo empiece cómo "debe ser".

     

    A lo que vamos, de lo que se trata es de tener, por ejemplo, un control PictureBox y ese mismo control mostrarlo (o usarlo) en controles diferentes.
    En realidad en contenedores de controles o colecciones de controles, que para el caso es lo mismo, además de que en .NET todos los controles pueden tener otros controles dentro (al menos eso es lo que parece o hace suponer al existir en cada objeto de tipo Control una propiedad llamada Controls que es un objeto del tipo ControlCollection (para saber más pulsa en los enlaces y te llevará a la documentación de .NET Framework 4.0).

    Para lograr eso lo que tenemos que hacer es añadir el control en cuestión a la colección Controls del contenedor al que lo queremos mover.
    Por ejemplo, si tenemos un control del tipo TabControl y cuando pulsamos en la primera y/o la segunda ficha (TabPage), haremos que un control llamado PictureBox1 se añada a esa ficha.
    Con el siguiente código (para Visual Basic) lo conseguiremos:

     

    Private Sub TabControl1_SelectedIndexChanged(ByVal sender As Object, _
                                                 ByVal e As EventArgs) _
                                                Handles TabControl1.SelectedIndexChanged
    
        Select Case TabControl1.SelectedIndex
            Case 0
                TabPage1.Controls.Add(PictureBox1)
            Case 1
                TabPage2.Controls.Add(PictureBox1)
        End Select
    End Sub

     

    Si prefieres usar C#, utiliza el siguiente código:

    private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
    {
        switch (tabControl1.SelectedIndex)
        {
            case 0:
                tabPage1.Controls.Add(pictureBox1);
                break;
    
            case 1:
                tabPage2.Controls.Add(pictureBox1);
                break;
        }
    }

     

    Si en lugar de añadirlo directamente a una ficha (tabControl) necesitas que esté en otro contenedor, por ejemplo, dentro de un GroupBox, simplemente sustituye el nombre del control que hay justamente antes de Controls.Add por el control que te convenga. Lo mismo ocurre con el control añadido (el que está entre paréntesis después de .Add), puedes añadir cualquier control.

     

    Si al ver el código de ejemplo te preguntas algo así:

    P: Guille, ¿no crees que sería necesario quitar el control antes de añadirlo a otra colección? ya que de esa forma tendríamos repetido el mismo control en más de una colección.

    La respuesta podría ser como esta:

    R: Buena pregunta, lo que indica que "has leído el código", pero no es necesario.

     

    ¿Por qué no es necesario eliminar un control de una colección antes de añadirla a otra?

    Porque el propio .NET se encarga de eso, es decir, si un control se añade a una colección de controles, automáticamente se quita de la que ya estuviera.

    Esto no es que lo haya "adivinado" yo, es que está en la documentación del método Add, que por cierto yo no lo había leído hasta después de hacer el proyecto de ejemplo, en el que me dio por probar a ver qué pasaba si no eliminaba previamente el control de la colección, y al ver que no ocurría "nada raro" (es decir, todo funcionaba como debería funcionar) me dio por leer la documentación y esa documentación tiene una nota que dice:

     

    Un objeto Control sólo se puede asignar a una colección Control.ControlCollection a la vez. Si el Control ya es secundario de otro control, se quita de ese control antes de agregarlo a otro.

    (el texto anterior está extraído de la ayuda en línea de .NET Framework 4.0 en castellano, concretamente de la definición del método Add de la clase Control.ControlCollection)

     

     

    Espero que te sea de utilidad.

     

    Nos vemos.

    Guillermo

    Publicado con fecha del lunes 16 de mayo a las 22:00, pero en realidad lo acabé de escribir (y publicar) el martes 17 de mayo a las 00:05

    …