Manejando archivos de texto con C#

Un punto siempre importante es manejar archivos de textos en una plataforma, para esto C# nos proporciona de objetos que nos hacen mas fácil estas tareas.

El namespace System.IO es el que contiene tipos que permiten leer y escribir en los archivos y secuencias de datos, así como tipos que proporcionan compatibilidad básica con los archivos y directorios.  Las clases más relacionadas con la escritura y lectura de archivos (File Input/Output o File I/O) son:

FileStream, cuyo propósito es lectura y escritura de datos binarios (no de texto legible), a cualquier archivo de tipo binario, aunque se puede utilizar para acceder a cualquier tipo de archivo, inclusive los de texto.

StreamReader y StreamWriter, las cuales están diseñadas para lectura y escritura de archivos de texto. Estas clases se asumen como de un nivel más alto que FileStream.

La lectura y escritura a un archivo son hechas usando un concepto genérico llamado stream. La idea detrás del stream existe hace tiempo, cuando los datos son pensados como una transferencia de un punto a otro, es decir, como un flujo de datos.

El uso de streams para la lectura y escritura de archivo es directa pero lenta. Por esta razón la clase BufferedStream existe y es más eficiente. Puede ser utilizado por cualquier clase de stream. Para operaciones de archivo es posible utilizar FileStream, donde el buffering está ya incluido.

La clase base abstracta Stream es compatible con bytes de lectura y escritura. Stream tiene compatibilidad asincrónica. Sus implementaciones predeterminadas definen lecturas y escrituras sincrónicas según sus correspondientes métodos asincrónicos, y viceversa.

Todas las clases que representan secuencias se derivan de la clase Stream. La clase Stream y sus clases derivadas proporcionan una visión genérica de los orígenes de datos y los repositorios, aislando al programador de los detalles específicos del sistema operativo y sus dispositivos subyacentes.

Las secuencias comprenden estas operaciones fundamentales:

En las secuencias se puede leer. La lectura es la transferencia de datos desde una secuencia a una estructura de datos, como, por ejemplo, una matriz de bytes.

En las secuencias se puede escribir. La escritura consiste en la transferencia de información desde un origen de datos a una secuencia.

Las secuencias pueden admitir operaciones de búsqueda. Las operaciones de búsqueda consisten en la consulta y modificación de la posición actual en una secuencia.

Según el origen de datos o repositorio subyacente, las secuencias pueden admitir sólo algunas de estas características. Por ejemplo, NetworkStreams no admite operaciones de búsqueda. Las propiedades CanReadCanWrite, y CanSeek de Stream y sus clases derivadas determinan las operaciones que son compatibles con diferentes secuencias.

Entre las clases suadas para entrada y salida de archivos tenemos Directory, DirectoryInfo, DriveInfo, File, FileInfo, FileStream, FileSystemInfo, Path, DeflateStream, GZipStream, DeflateStream, SerialPort, pero nosotros nos centraremos en FileStream.

De igual modo tenemos varias clases que nos permiten leer y escribir en secuencias BinaryReader, BinaryWriter, StreamReader, StreamWriter, StringReader, StringWriter, TextReader, TextWriter pero en este articulo nos centraremos en StreamReader y StreamWriter.

También tenemos clases para manejar secuencias de Entrada y Salida BufferedStream, CryptoStream (Aunque CryptoStream deriva de Stream, no forma parte del namespace System.IO, sino de System.Security.Cryptography), MemoryStream, NetworkStream (Aunque CryptoStream deriva de Stream, no forma parte del namespace System.IO, sino de System.Net.Sockets).

El FileStream actúa como un intermediario entre el sistema de archivos y nuestra aplicación, permitiendo realizar de una manera limpia y sencilla operaciones de escritura y lectura en archivos. Para utilizar el FileStream, lo primero que se debe hacer es crear una instancia que apunte al archivo deseado. usando el siguiente constructor inicializamos una nueva instancia de la clase FileStream con el permiso de uso compartido, el permiso de lectura/escritura, el modo de creación y la ruta de acceso especificados.

public FileStream(
   string path,
   FileMode mode,
   FileAccess access,
   FileShare share
)

 

Parámetros:

path
Tipo: System.String
Ruta relativa o absoluta del archivo que va a encapsular el objeto FileStream actual.

mode
Tipo: System.IO.FileMode
Constante que determina cómo abrir o crear el archivo.

access
Tipo: System.IO.FileAccess
Constante que determina cómo puede obtener acceso al archivo el objeto FileStream. Obtiene las propiedades CanRead y CanWrite del objeto FileStream. La propiedad CanSeek es true si path especifica un archivo de disco.

share
Tipo: System.IO.FileShare
Constante que determina cómo compartirán el archivo los procesos.

Una observación acerca de la declaración de nombres/rutas de archivos en C#. Usualmente, la ruta de un archivo contiene el carácter  ‘\’, que en C# se utiliza como caracter de control para símbolos especiales (como el cambio de línea: ‘\n’). Sin embargo, entendiendo que no es el mismo sentido el que se le quiere dar en la interpretación de rutas de archivos (por ej: “C:\Mis documentos\Programas\ejemplo.cs”), se utiliza una sintaxis particular, anteponiendo el símbolo ‘@’ antes del string con la ruta del archivo.  Por ejemplo:

string rutaarchivo = @”C:\Temp\archivo.txt”;

 

StreamReader y StreamWriter

StreamReader  implementa un TextReader que lee los caracteres de una secuencia de bytes en una codificación determinada.

StreamReader está diseñado para la entrada de caracteres mediante una codificación determinada, mientras que la clase Stream está diseñada para la entrada y salida de bytes. Se utiliza StreamReader para leer líneas de información desde un archivo de texto estándar.

StreamReader adopta la codificación UTF-8 de forma predeterminada, a menos que se especifique otra, en lugar de utilizar la página de códigos ANSI del sistema actual. UTF-8 utiliza los caracteres Unicode correctamente y ofrece resultados coherentes en versiones traducidas del sistema operativo.

Son básicamente tres los métodos propios de StreamReader que permiten efectuar lectura desde el stream (archivo) declarado.

ReadLine()
Al igual que el conocido Console.ReadLine(), este método lee una línea completa de un archivo de texto hasta el cambio de línea más próximo. Al igual que su equivalente de consola, StreamReader.ReadLine() no incluye en el string el carácter de cambio de línea.

string linea = sr.ReadLine()

 

ReadToEnd()
Este método, por su parte, se encarga de acumular la información que hay desde la lectura anterior (que pudo haberse hecho con ReadLine(), por ejemplo) hasta el final del archivo, todo en el mismo string.

string linea = sr.ReadToEnd()

 

Read ()
Finalmente, el método simple Read() se encarga de leer un caracter a la vez, lo que permite procesar símbolo por símbolo el contenido del archivo. Convenientemente, este método reconoce el cambio de línea y se lo salta como si no existiese. Cuando se encuentra con el fin de archivo, retorna un valor –1, considerando que su retorno es siempre un int (y no un char).

int SigCaracter = sr.Read();

Este mismo método ofrece una declaración alternativa (sobrecarga), donde es posible leer una cantidad específica de caracteres y almacenarlos en un arreglo de enteros.

char[] CharArray = new char[100];
int[] nChars = sr.Read(CharArray, 0, 100);

 

nChars es un arreglo con los enteros retornados por el método, y será menor si es que la cantidad de caracteres que quedan en el archivo es menor de 100.

StreamWriter implementa TextWriter para escribir los caracteres de una secuencia en una codificación determinada.

StreamWriter está diseñado para obtener caracteres como salida en una codificación determinada, mientras que las clases derivadas de Stream están diseñadas para entrada y salida de bytes.

StreamWriter utiliza de forma predeterminada una instancia de UTF8Encoding, a menos que se especifique lo contrario. Esta instancia de UTF8Encoding se construye de modo que el método Encoding.GetPreamble devuelva la marca de orden de bytes Unicode escrita en UTF-8. El preámbulo de la codificación se agrega a una secuencia cuando no se anexa a una secuencia existente. Esto significa que cualquier archivo de texto que se cree con StreamWriter tendrá tres marcas de orden de bytes al principio. UTF-8 utiliza todos los caracteres Unicode correctamente y ofrece resultados coherentes en versiones traducidas del sistema operativo.

Son básicamente dos los métodos propios de StreamWriter que permiten escribir hacia el stream (archivo) declarado y son los mismos que se usan para escribir en la consola: Write() y WriteLine().

WriteLine()
Totalmente equivalente a Console.WriteLine(), se utiliza la misma idea, y el mismo formato, sabiendo que se estará escribiendo el texto no a la consola, sino que al stream abierto con el constructor.

string linea = “Texto de prueba”;
sw.WriteLine(linea);
sw.WriteLine(“Los valores posibles son: {0} y {1}”, 3, 5);

 

Write ()
También presente, el método simple Write(), permite escribir texto en el stream, de la misma forma que su equivalente método de la clase Console. En este caso se reconocen las siguientes alternativas de uso:

//Imprimir un string
string linea = “Texto de prueba”;
sw.Write(linea);

//Imprimir un caracter
char caracter = ‘T’;
sw.Write(caracter);

//Imprimir un arreglo de caracteres
char[] caracteres = new char[100];
for(int i=0; i<100; i++) caracteres[i] = ‘+‘;
sw.Write(caracteres);

//Imprimir una porción de un arreglo de caracteres
char[] caracteres = new char[100];
for(int i=0; i<100; i++) caracteres[i] = ‘+‘;
sw.Write(caracteres, 25, 50); // Desde posición 25 se escriben 50 caracteres.

 

Fuente

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *