Buscador

Manipulación de directorios mediante las clases Directory y DirectoryInfo - I

Las clases Directory y DirectoryInfo contienen métodos y propiedades para crear, borrar, copiar y mover directorios, así como otra serie de tareas para su manejo y obtención de información. 
Al igual que sucedía con las clases del anterior apartado, los miembros de Directory son compartidos, mientras que los de DirectoryInfo son de instancia; esta es su principal diferencia. 
En el ejemplo del Código fuente 378, el método Exists( ) comprueba la existencia de un directorio, y en caso afirmativo, obtenemos su última fecha de uso mediante GetLastAccessTime( ). Seguidamente obtenemos un array String con su lista de archivos mediante GetFiles( ), y creamos un subdirectorio de respaldo con CreateSubdirectory( ). En caso de que el directorio no exista, lo creamos con CreateDirectory( ).

Dim sNombreDir As String
Dim Archivos() As String
Dim Archivo As String
Dim oDirInfo As DirectoryInfo
Console.WriteLine("Introducir un nombre de directorio")
sNombreDir = Console.ReadLine()
If Directory.Exists(sNombreDir) Then
Console.WriteLine("Fecha último acceso: {0}", _
Directory.GetLastAccessTime(sNombreDir))
Console.WriteLine("Archivos del directorio {0}", sNombreDir)
Archivos = Directory.GetFiles(sNombreDir)
For Each Archivo In Archivos
Console.WriteLine(Archivo)
Next
oDirInfo = New DirectoryInfo(sNombreDir)
oDirInfo.CreateSubdirectory("bak")
Else
Directory.CreateDirectory(sNombreDir)
Console.WriteLine("No existía el directorio, se acaba de crear")
End If
Código fuente 378

Manipulación de archivos mediante las clases File y FileInfo - III

Además de esta excepción, el espacio de nombres IO proporciona algunas clases de excepción adicionales para tratar otras diversas circunstancias de error. Consulte el lector la documentación de la plataforma referente a IO. 

Los métodos Copy( ), Move( ) y Delete( ), nos permiten copiar, mover y borrar respectivamente el nombre de archivo que pasemos como parámetro. El método GetCreationTime( ) nos devuelve un tipo Date con la fecha de creación del archivo. 

Por otro lado, si queremos obtener información adicional sobre un archivo, como su nombre, extensión, ruta, etc., instanciaremos un objeto FileInfo( ), pasando al constructor una cadena con el nombre del archivo, y utilizaremos algunas de sus propiedades como Name, Extensión, DirectoryName. Veamos una muestra de todo esto en el Código fuente 377.

Dim sNombreFich As String
Dim iOperacion As Integer
Dim oFInfo As FileInfo
Console.WriteLine("Introducir ruta y archivo")
sNombreFich = Console.ReadLine()
Console.WriteLine("Fecha creación archivo: {0}", _
File.GetCreationTime(sNombreFich))
oFInfo = New FileInfo(sNombreFich)
Console.WriteLine("Introducir el número de operación a realizar:")
Console.WriteLine("1 - Copiar")
Console.WriteLine("2 - Mover")
Console.WriteLine("3 - Borrar")
iOperacion = Console.ReadLine()
Select Case iOperacion
Case 1
File.Copy(sNombreFich, "\pruebas\distinto" & oFInfo.Extension)
Case 2
Console.WriteLine("Vamos a mover el archivo {0}", oFInfo.Name)
Console.WriteLine("que está en la ruta {0}", oFInfo.DirectoryName)
File.Move(sNombreFich, "\pruebas\" & oFInfo.Name)
Console.WriteLine("Completado")
Console.ReadLine()
Case 3
File.Delete(sNombreFich)
End Select
Código fuente 377

Manipulación de archivos mediante las clases File y FileInfo - II

Para obtener los atributos de un archivo, disponemos del método GetAttributes( ), al que pasamos la ruta de un archivo, y devuelve un valor de la enumeración FileAttributes con la información sobre los atributos. En el caso de que al intentar acceder a un archivo, este no exista, se producirá una excepción de tipo FileNotFoundException, que podemos tratar en una estructura de manejo de excepciones. 

Ver el Código fuente 376.

Dim sNombreFich As String
Dim oAtributos As FileAttributes
Try
Console.WriteLine("Introducir ruta y archivo")
sNombreFich = Console.ReadLine()
oAtributos = File.GetAttributes(sNombreFich)
Console.WriteLine("Atributos del archivo: {0}", oAtributos.ToString())
Catch oExcep As FileNotFoundException
Console.WriteLine("Se ha producido un error {0}{1}", _
ControlChars.CrLf, oExcep.Message)
Finally
Console.WriteLine("Proceso finalizado")
Console.ReadLine()
End Try
Código fuente 376

Manipulación de archivos mediante las clases File y FileInfo - I

Las clases File y FileInfo, proporcionan a través de sus miembros, el conjunto de operaciones comunes que podemos realizar con archivos en cuanto a su creación, copia, borrado, etc. 
La diferencia principal entre ambas radica en que los miembros de File son todos compartidos, con lo cual se facilita en gran medida su uso, al no tener que crear una instancia previa de la clase; mientras que en FileInfo deberemos crear un objeto para poder utilizarla, ya que sus miembros son de instancia. FileInfo dispone de algunos métodos adicionales que no se encuentran en File. 
Comenzando por la clase File, los métodos CreateText( ) y OpenText( ), devuelven respectivamente un objeto StreamWriter y StreamReader, que utilizaremos para escribir y leer en el archivo pasado como parámetro a estos métodos. Con el método Exists( ), comprobamos si existe un determinado archivo. 
Veamos un ejemplo en el Código fuente 375.

Dim sNombreFich As String
Dim srLector As StreamReader
Dim swEscritor As StreamWriter
Console.WriteLine("Introducir ruta y archivo")
sNombreFich = Console.ReadLine()
If File.Exists(sNombreFich) Then
srLector = File.OpenText(sNombreFich)
Console.WriteLine("El archivo contiene:{0}{1}", _
ControlChars.CrLf, srLector.ReadToEnd())
srLector.Close()
Else
swEscritor = File.CreateText(sNombreFich)
swEscritor.WriteLine("este es")
swEscritor.WriteLine("un nuevo archivo")
swEscritor.Close()
End If
Console.WriteLine("Proceso finalizado")
Console.ReadLine()
Código fuente 375

La clase FileStream - II

Para las operaciones de lectura tenemos los siguientes métodos: 
  • ReadByte( ). Devuelve el valor sobre el que esté posicionado el objeto en ese momento. 
  • Read( ). Traspasa valores a un array de bytes. 
Si queremos desplazarnos por los elementos del Stream, podemos utilizar el método Seek( ), pasando la cantidad de posiciones a movernos, y el punto desde el que queremos realizar dicho desplazamiento, mediante los valores de la enumeración SeekOrigin. Para averiguar el elemento del Stream en el que estamos situados, disponemos de la propiedad Position.

Veamos algunos ejemplos de lectura sobre este tipo de objetos, en el Código fuente 374.

' lectura con FileStream
Dim oFileStream As FileStream
oFileStream = New FileStream("\pruebas\apuntes.dtt", FileMode.Open)
Dim Valor As Byte
Valor = oFileStream.ReadByte() ' obtener un valor
Console.WriteLine("Se ha leido el valor: {0}", Valor)
Console.WriteLine("Nos desplazamos dos bytes en el stream")
oFileStream.Seek(2, SeekOrigin.Begin)
Valor = oFileStream.ReadByte()
Console.WriteLine("Se ha leido el valor: {0}", Valor)
Console.WriteLine("La posición actual del stream es: {0}", _
oFileStream.Position)
' leer varios valores, pasándolos a un array
' previamente dimensionado
Dim VariosValores(3) As Byte
oFileStream.Read(VariosValores, 0, 4)
Console.WriteLine("Leer bloque de valores del stream")
Dim Enumerador As IEnumerator
Enumerador = VariosValores.GetEnumerator()
While Enumerador.MoveNext
Console.WriteLine("Valor: {0}", Enumerador.Current)
End While
Console.ReadLine()
Código fuente 374

La clase FileStream - I

Realiza escritura y lectura de bytes sobre un archivo; en el caso de que el archivo no exista, lo crearíamos al mismo tiempo que instanciamos este objeto. Uno de los constructores de esta clase, nos permite especificar una cadena con la ruta del archivo a utilizar, mientras que en el segundo parámetro utilizaremos un valor de la enumeración FileMode, mediante la que indicamos el modo de trabajo sobre el archivo: añadir, abrir, crear, etc. Las propiedades CanRead, CanWrite y CanSeek, devuelven un valor lógico que nos informa de si en el objeto podemos realizar operaciones de lectura, escritura y desplazamiento por los bytes que contiene. Para escribir datos, disponemos de los siguientes métodos: • WriteByte( ). Escribe un byte en el archivo • Write( ). Escribe, de un array de bytes pasado como parámetro, una cantidad de elementos determinada, empezando por una de las posiciones de dicho array. 

Veamos en el Código fuente 373, un ejemplo de escritura con esta clase.

' escrituras con Filestream
Dim oFileStream As FileStream
oFileStream = New FileStream("\pruebas\apuntes.dtt", FileMode.CreateNew)
oFileStream.Write(New Byte() {15, 160, 88, 40, 67, 24, 37, 50, 21}, 0, 6)
oFileStream.WriteByte(75)
Console.WriteLine("Opciones en el FileStream")
Console.WriteLine("Podemos leer: {0}", IIf(oFileStream.CanRead, "SI", "NO"))
Console.WriteLine("Podemos escribir: {0}", IIf(oFileStream.CanWrite, "SI", "NO"))
Console.WriteLine("Podemos movernos: {0}", IIf(oFileStream.CanSeek, "SI", "NO"))
oFileStream.Close()
oFileStream = Nothing
Código fuente 373

La clase StreamReader - II

Otro de los métodos de lectura es ReadBlock( ), que recibe como parámetro un array de tipo Char, sobre el que se depositarán una cierta cantidad de caracteres leídos del archivo. En el segundo parámetro de este método indicamos la posición del array desde la que se comenzarán a guardar los caracteres, y en el tercer parámetro, el número de caracteres a leer. El método Read( ) utilizado sin parámetros, devuelve un valor numérico correspondiente al código del carácter que se acaba de leer. Cuando tras sucesivas operaciones de lectura lleguemos al final del Stream, este método devolverá -1. 
Para convertir de nuevo a carácter los valores que devuelve Read( ), debemos pasarlos a un array de tipo Byte, y después, utilizando un objeto ASCIIEncoding, llamaremos a su método GetString( ), que convertirá el array en una cadena. Veamos unos ejemplos de estos métodos en el Código fuente 372. Observe el lector, que para poder utilizar en el programa un objeto ASCIIEnconding, debemos importar el espacio de nombres System.Text.

Imports System.IO
Imports System.Text
Module Module1
Sub Main()
' crear un Stream de lectura
Dim srLector As StreamReader = New StreamReader("\pruebas\NOTAS.txt")
' obtener valores del Stream con el método ReadBlock()
' ----------------------------------------------------
' crear un array Char que contendrá los caracteres leídos
Dim Caracteres(15) As Char
' leemos 16 caracteres del archivo y los pasamos al array
' comenzando a grabarlos a partir de su posición 0
srLector.ReadBlock(Caracteres, 0, 16)
' pasamos el array de valores Char a String mediante
' el constructor de la clase String que recibe como
' parámetro un array Char
Dim Parte1 As String = New String(Caracteres)
Console.WriteLine("Resultado de la lectura con ReadBlock()")
Console.WriteLine(Parte1)
Console.WriteLine()
' obtener valores del stream con el método Read()
' -----------------------------------------------
Dim Valor As Integer
Dim Codigos() As Byte
' vamos a ir volcando en un bucle los códigos de carácter
' leidos desde el archivo a un array Byte
Valor = srLector.Read()
While (Valor <> -1) ' cuando lleguemos al final, obtendremos -1
If Codigos Is Nothing Then
ReDim Codigos(0)
Else
ReDim Preserve Codigos(Codigos.GetUpperBound(0) + 1)
End If
Codigos(Codigos.GetUpperBound(0)) = Valor
Valor = srLector.Read()
End While
Dim Codificador As New ASCIIEncoding()
Dim Parte2 As String
' con el objeto ASCIIEncoding, método GetString(),
' obtenemos una cadena, pasando como parámetro un array
' de tipos Byte
Parte2 = Codificador.GetString(Codigos)
Console.WriteLine("Resultado de la lectura con ReadBlock()")
Console.WriteLine(Parte2)
Console.ReadLine()
End Sub
End Module
Código fuente 372

Finalmente, el método Peek( ), al igual que Read( ), devuelve el siguiente valor disponible del Stream, pero sin extraerlo del búfer, con lo que deberemos utilizar alguno de los métodos anteriormente descritos para realizar una lectura real.

La clase StreamReader - I

Un objeto StreamReader realiza operaciones de lectura de texto sobre un archivo. El proceso que debemos llevar a cabo para leer el contenido de un Stream de lectura es muy similar al de escritura: instanciar el objeto con uno de sus constructores, abriendo un archivo para leer; ejecutar alguno de los métodos de lectura del StreamReader, y cerrar el objeto con Close( ). 
Entre los métodos de lectura de este objeto, tenemos ReadLine( ), que devuelve una línea del archivo; y ReadToEnd( ), que devuelve el resto del contenido del archivo, desde el punto en el que se encontrara el Stream al realizar la última lectura. Veamos unos ejemplos en el Código fuente 371

Dim srLector As StreamReader = New StreamReader("\pruebas\NOTAS.txt")
Console.WriteLine("**Leer una primera línea**")
Dim Linea As String
Linea = srLector.ReadLine()
Console.WriteLine("La línea contiene --> {0}", Linea)
Console.WriteLine()
Console.WriteLine("**Ahora leemos el resto del archivo**")
Dim Texto As String
Texto = srLector.ReadToEnd()
Console.WriteLine("El texto restante contiene --> {0}", Texto)
srLector.Close()
' ***********************************************
' leer línea a línea mediante un bucle
Dim srLector As StreamReader = New StreamReader("\pruebas\Datos.txt")
Dim Linea As String
Dim ContadorLin As Integer = 1
Linea = srLector.ReadLine()
Do While Not (Linea Is Nothing)
Console.WriteLine("Línea: {0} - Contenido: {1}", ContadorLin, Linea)
ContadorLin += 1
Linea = srLector.ReadLine()
Loop
Código fuente 371

La clase StreamWriter - II

En el caso de que el archivo sobre el que vamos a escribir ya exista, podemos utilizar, de los métodos constructores de StreamWriter, aquel que nos permite especificar en el segundo parámetro si vamos a añadir texto al archivo, o vamos a sobrescribir el texto previamente existente. Veamos un ejemplo en el Código fuente 369.

' abre el archivo y se sitúa al final del texto para añadir
swEscritor = New StreamWriter("\pruebas\NOTAS.txt", True)
' se elimina el contenido previo del archivo
swEscritor = New StreamWriter("\pruebas\NOTAS.txt", False)
Código fuente 369

Después de crear un objeto de este tipo, y escribir algunas líneas de texto sin cerrar el Stream, si abrimos su archivo de texto correspondiente (con el Bloc de Notas por ejemplo), nos encontraremos con que no hay texto dentro del archivo. Ello es debido a que todavía no se ha volcado el contenido del búfer del objeto sobre el archivo. Para forzar dicho volcado, deberemos llamar al método Flush( ), que se encarga de traspasar el búfer al archivo asociado al Stream. Veamos el Código fuente 370.

Dim swEscritor As StreamWriter
' creamos un stream de escritura
swEscritor = New StreamWriter("\pruebas\NOTAS.txt", False)
' escribir líneas
swEscritor.WriteLine("la primera línea")
swEscritor.WriteLine("un poco más de texto")
' si abrimos el archivo antes de la siguiente, estará vacío
swEscritor.Flush()
' ahora el archivo ya contendrá texto
' cerrar el stream y el archivo asociado
swEscritor.Close()
Código fuente 370

La clase StreamWriter - I

Un objeto StreamWriter realiza operaciones de escritura de texto sobre un archivo. El proceso típico de escritura de datos mediante un StreamWriter, comprende los siguientes pasos: 
  • Instanciar un objeto de esta clase mediante alguno de los constructores disponibles. Aquí creamos un nuevo archivo para escribir datos sobre él, o abrimos uno existente. 
  • Escritura de texto mediante los métodos WriteLine( ) y Write( ). El primero escribe el texto pasado como parámetro, y añade los caracteres especiales de retorno de carro y nueva línea. El segundo escribe el texto pasado y deja el puntero de escritura a partir del último carácter escrito, con lo que no produce un cambio automático de línea. Deberemos utilizar la propiedad NewLine para introducir manualmente un salto de línea. 
  • Cierre del Stream con el método Close( ). Esta acción vuelca el contenido del búfer del objeto en el archivo.

 El Código fuente 368 muestra el proceso básico que acabamos de describir.

Imports System.IO
Module Module1
Sub Main()
Dim swEscritor As StreamWriter
' creamos un stream de escritura, y al mismo tiempo un
' nuevo archivo para escribir texto sobre él
swEscritor = New StreamWriter("\pruebas\NOTAS.txt")
' escribir líneas
swEscritor.WriteLine("esta es la primera línea")
swEscritor.WriteLine("segunda línea de texto")
' ahora escribimos texto pero sin provocar un salto de línea
swEscritor.Write("Juan y Luna ")
swEscritor.Write("van de paseo")
swEscritor.Write(swEscritor.NewLine) ' esto introduce el salto de línea
swEscritor.WriteLine("con esta línea cerramos")
' cerrar el stream y el archivo asociado
swEscritor.Close()
End Sub
End Module
Código fuente 368

Objetos Stream

Un objeto Stream representa un flujo o corriente de datos, es decir, un conjunto de información guardada en formato de texto o binario, que podremos leer y escribir sobre un soporte físico, también denominado almacén de respaldo (backing store), en la plataforma .NET. 

Algunos tipos de Stream, para optimizar el flujo de transferencia de datos entre el objeto y su medio físico de almacenamiento, disponen de una característica denominada almacenamiento intermedio (buffering), que consiste en mantener un búfer intermedio con los datos. En el caso, por ejemplo, de tareas de escritura, todas las operaciones se realizarían en el búfer, mientras este dispusiera de capacidad. Una vez terminado el proceso de escritura, o cuando el búfer estuviera lleno, su contenido pasaría al archivo físico. Podemos también, alterar el comportamiento por defecto del búfer a través de diversas propiedades y métodos del objeto Stream correspondiente.

System.IO, el punto de partida para el manejo de archivos

Mediante VB.NET podemos hacer uso de las clases de la plataforma .NET situadas en el espacio de nombres System.IO, para todos los aspectos relacionados con el manejo de archivos.
Operaciones tales como lectura y escritura de información en archivos, y la gestión de los mismos en operaciones de borrado, copia, etc., entre directorios y unidades pueden ser llevadas a cabo a través de las clases contenidas en IO. 
Los propios directorios y unidades pueden ser igualmente tratados como objetos, lo que facilita enormemente el trabajo del programador. A lo largo de este tema realizaremos una descripción, con ejemplos de uso, de algunas de las clases contenidas en IO. Por lo que en todos los ejemplos utilizados aquí, tendremos que importar este espacio de nombres.

Manipulación de archivos

¿Qué es un archivo? 

En los ejemplos realizados hasta el momento, cuando necesitamos guardar un conjunto de valores en algún lugar empleamos un array. Sin embargo, existen situaciones en las que debemos almacenar cantidades muy elevadas de datos, no constituyendo los arrays el elemento adecuado para este fin. Adicionalmente, el array es manipulado en memoria durante la ejecución del programa, por lo que su contenido se pierde al finalizar el mismo. Ante este tipo de casos debemos recurrir a los archivos.

Un archivo es un medio de almacenamiento separado del programa, que nos permite guardar en el mismo una gran cantidad de información. 

Al tratarse de un soporte de almacenamiento permanente, podemos utilizarlo para grabar datos que puedan ser consultados en posteriores ejecuciones del programa que lo creó, o de otros programas que accedan a ese archivo. 

El uso de un archivo para guardar datos de forma externa es recomendable en procesos que no necesiten una organización muy compleja de los datos a manipular, ya que en tal caso, lo mejor sería utilizar un programa gestor de base de datos, que ya incorpora, de modo mucho más optimizado, los algoritmos y procesos específicos para el tratamiento de la información.