Leer CSV .NET: El enfoque más sencillo en C# con IronXL
Leer CSV .NET: El enfoque más sencillo en C# usando IronXL
Leer y escribir archivos CSV en aplicaciones .NET se convierte en algo notablemente sencillo con la biblioteca adecuada. En lugar de escribir lógica de análisis personalizada para manejar delimitadores, campos entrecomillados y diversos tipos de datos, los desarrolladores pueden cargar datos CSV con una sola llamada a un método y acceder inmediatamente a ellos como datos estructurados de hoja de cálculo en formato de tabla.
IronXL transforma el procesamiento de CSV tratando los archivos separados por comas como libros de Excel. Esta biblioteca .NET elimina la complejidad del análisis sintáctico manual de cadenas al tiempo que proporciona potentes funciones como conversión de tablas de datos, acceso a nivel de celda y salida en formato Excel sin fisuras. La biblioteca funciona en .NET Framework, .NET Core y .NET 5+ sin necesidad de instalar Microsoft Office, por lo que resulta ideal para proyectos de API web ASP.NET Core y .NET Core.
Esta guía muestra técnicas prácticas para leer archivos CSV, manejar delimitadores personalizados, convertir registros en DataTables y escribir archivos CSV en formatos Excel, todo ello con un código mínimo. Cada ejemplo de código incluye explicaciones detalladas para ayudarle a entender cómo funciona el sistema.
Introducción al trabajo con archivos CSV
Los archivos CSV (valores separados por comas) son un elemento básico en el intercambio y almacenamiento de datos, gracias a su simplicidad y amplia compatibilidad. Ya se trate de importar datos a una base de datos, exportar informes o integrarlos con sistemas de terceros, los archivos CSV ofrecen un formato ligero y flexible para manejar datos tabulares. En .NET, trabajar con archivos CSV es una tarea común: los desarrolladores a menudo necesitan analizar, leer y escribir datos CSV como parte de la lógica empresarial, la generación de informes o los flujos de trabajo de migración de datos.
El sistema .NET ofrece varias formas de procesar archivos CSV, desde operaciones básicas con cadenas y archivos hasta bibliotecas robustas como CsvHelper. Es esencial un análisis sintáctico adecuado, ya que incluso una simple coma puede introducir complejidad cuando aparece dentro de campos entrecomillados o como parte de los propios datos. Al aprovechar las herramientas .NET adecuadas y comprender los matices del análisis sintáctico de CSV, los desarrolladores pueden garantizar la integridad de los datos y agilizar el procesamiento de datos en sus aplicaciones.
¿Cuál es la forma más sencilla de leer archivos CSV en .NET?
El enfoque más simple utiliza el método WorkBook.LoadCSV para importar datos CSV directamente a una estructura de libro de trabajo. Este método único se encarga del análisis sintáctico, la detección de delimitadores y la organización de datos de forma automática, sin necesidad de crear un nuevo StreamReader ni de procesar manualmente cada línea de cadena.
Instale IronXL a través de la consola del gestor de paquetes NuGet en Visual Studio. Abra su proyecto .NET y ejecútelo:
Install-Package IronXL.Excel
Leer CSV .NET: The Simplest C# Approach Using IronXL: Imagen 1 - Instalación
using IronXL;
using System;
class Program
{
static void Main(string[] args)
{
// Load CSV file into a workbook with one method call
WorkBook workbook = WorkBook.LoadCSV("sales_data.csv", fileFormat: ExcelFileFormat.XLSX, listDelimiter: ",");
// Access the default worksheet containing CSV data
WorkSheet sheet = workbook.DefaultWorkSheet;
// Display all rows and CSV columns
foreach (var row in sheet.Rows)
{
foreach (var cell in row)
{
Console.Write(cell.Value + "\t");
}
Console.WriteLine();
}
}
}using IronXL;
using System;
class Program
{
static void Main(string[] args)
{
// Load CSV file into a workbook with one method call
WorkBook workbook = WorkBook.LoadCSV("sales_data.csv", fileFormat: ExcelFileFormat.XLSX, listDelimiter: ",");
// Access the default worksheet containing CSV data
WorkSheet sheet = workbook.DefaultWorkSheet;
// Display all rows and CSV columns
foreach (var row in sheet.Rows)
{
foreach (var cell in row)
{
Console.Write(cell.Value + "\t");
}
Console.WriteLine();
}
}
}Entrada
Leer CSV .NET: The Simplest C# Approach Using IronXL: Image 2 - Sample CSV Input
Resultado
Leer CSV .NET: El enfoque más sencillo de C# utilizando IronXL: Imagen 3 - Salida de la consola
Como alternativa, puede leer un archivo CSV utilizando la biblioteca CsvHelper, muy popular para manejar operaciones CSV en .NET. Para leer un archivo CSV con CsvHelper, cree un StreamReader y, a continuación, una nueva instancia de CsvReader, a menudo asignada a una variable como var csv o var reader:
using (var reader = new StreamReader("sales_data.csv"))
using (var csv = new CsvHelper.CsvReader(reader, System.Globalization.CultureInfo.InvariantCulture))
{
var records = csv.GetRecords<dynamic>().ToList();
// Process records as needed
}using (var reader = new StreamReader("sales_data.csv"))
using (var csv = new CsvHelper.CsvReader(reader, System.Globalization.CultureInfo.InvariantCulture))
{
var records = csv.GetRecords<dynamic>().ToList();
// Process records as needed
}También puede escribir en un archivo CSV utilizando CsvHelper creando una instancia StreamWriter y una instancia CsvWriter.
El método LoadCSV acepta tres parámetros: la ruta del archivo, el formato Excel de destino para la representación interna y el carácter delimitador que separa los valores. Una vez cargado, el contenido CSV se vuelve accesible a través de la propiedad DefaultWorkSheet, que proporciona la hoja de trabajo principal que contiene todos los registros importados.
La estructura de bucle anidado itera por cada Fila de la hoja de cálculo y, a continuación, por cada Celda de esa fila. La propiedad Value devuelve el contenido de la celda como un objeto, mientras que el carácter de tabulación crea una separación de columnas legible en la salida de la consola. Este patrón funciona de forma idéntica tanto si el archivo fuente contiene 10 filas como si se manejan archivos CSV de gran tamaño con miles de registros en memoria.
¿Cómo se compara el análisis manual de CSV con el uso de una biblioteca?
Comprender la complejidad que IronXL elimina ayuda a apreciar su valor. El análisis sintáctico manual de CSV requiere manejar múltiples casos extremos que parecen sencillos pero que rápidamente se convierten en problemáticos en cualquier proyecto.
using System;
using System.IO;
class Program
{
static void Main(string[] args)
{
// Manual approach - requires extensive code for basic functionality
string path = "data.csv";
string[] lines = File.ReadAllLines(path);
foreach (string line in lines)
{
// This breaks when CSV fields contain commas inside quotes
string[] fields = line.Split(',');
foreach (string field in fields)
{
Console.Write(field.Trim() + "\t");
}
Console.WriteLine();
}
}
}using System;
using System.IO;
class Program
{
static void Main(string[] args)
{
// Manual approach - requires extensive code for basic functionality
string path = "data.csv";
string[] lines = File.ReadAllLines(path);
foreach (string line in lines)
{
// This breaks when CSV fields contain commas inside quotes
string[] fields = line.Split(',');
foreach (string field in fields)
{
Console.Write(field.Trim() + "\t");
}
Console.WriteLine();
}
}
}Entrada
Leer CSV .NET: El enfoque más sencillo de C# usando IronXL: Imagen 4 - Entrada CSV
Resultado
Leer CSV .NET: The Simplest C# Approach Using IronXL: Image 5 - Manual CSV Parsing Output
El método manual falla cuando los campos CSV contienen comas incrustadas entre comillas, algo habitual en los campos de dirección o las descripciones. La lectura y escritura correctas de archivos CSV requiere el manejo de campos entrecomillados, comillas escapadas, valores multilínea y codificaciones variables. Utilizar la biblioteca CsvHelper o paquetes CSV Helper similares añade dependencias, mientras que desarrollar tu propio analizador significa crear un nuevo StreamReader, implementar un patrón de lectura var y gestionar todo el proceso de lectura de archivos tú mismo.
using IronXL;
using System;
class Program
{
static void Main(string[] args)
{
// IronXL approach - handles all edge cases automatically
WorkBook workbook = WorkBook.LoadCSV("data.csv", fileFormat: ExcelFileFormat.XLSX, listDelimiter: ",");
var records = workbook.DefaultWorkSheet.Rows;
foreach (var row in records)
{
foreach (var cell in row)
{
Console.Write(cell.Value + "\t");
}
Console.WriteLine();
}
}
}using IronXL;
using System;
class Program
{
static void Main(string[] args)
{
// IronXL approach - handles all edge cases automatically
WorkBook workbook = WorkBook.LoadCSV("data.csv", fileFormat: ExcelFileFormat.XLSX, listDelimiter: ",");
var records = workbook.DefaultWorkSheet.Rows;
foreach (var row in records)
{
foreach (var cell in row)
{
Console.Write(cell.Value + "\t");
}
Console.WriteLine();
}
}
}La versión de IronXL realiza la misma tarea a la vez que maneja adecuadamente los campos CSV entrecomillados, los caracteres especiales y las variaciones de codificación. La clase WorkBook gestiona internamente la complejidad del análisis sintáctico, lo que permite a los desarrolladores centrarse en trabajar con los datos en lugar de extraerlos. A diferencia de los enfoques que requieren una nueva instancia de CsvReader o una configuración del paquete CsvHelper, IronXL no necesita ninguna configuración adicional, solo cargar y usar.
¿Cómo se gestionan los diferentes delimitadores CSV?
Los archivos CSV no siempre utilizan comas como separadores. Las exportaciones de sistemas europeos utilizan con frecuencia el punto y coma debido al uso de la coma en los números decimales, mientras que los valores separados por tabulaciones (TSV) y los archivos delimitados por tuberías aparecen regularmente en las exportaciones de datos de diversas aplicaciones.
using IronXL;
using System;
class Program
{
static void Main(string[] args)
{
// Reading a semicolon-delimited file (common in European exports)
WorkBook euroData = WorkBook.LoadCSV("german_report.csv", fileFormat: ExcelFileFormat.XLSX, listDelimiter: ";");
// Reading a tab-separated file
WorkBook tsvData = WorkBook.LoadCSV("exported_data.tsv", fileFormat: ExcelFileFormat.XLSX, listDelimiter: "\t");
// Reading a pipe-delimited file
WorkBook pipeData = WorkBook.LoadCSV("legacy_system.csv", fileFormat: ExcelFileFormat.XLSX, listDelimiter: "|");
// Access data identically regardless of original delimiter
WorkSheet sheet = euroData.DefaultWorkSheet;
int rowsCount = sheet.RowCount;
Console.WriteLine($"Loaded {rowsCount} rows with {sheet.ColumnCount} CSV columns");
}
}using IronXL;
using System;
class Program
{
static void Main(string[] args)
{
// Reading a semicolon-delimited file (common in European exports)
WorkBook euroData = WorkBook.LoadCSV("german_report.csv", fileFormat: ExcelFileFormat.XLSX, listDelimiter: ";");
// Reading a tab-separated file
WorkBook tsvData = WorkBook.LoadCSV("exported_data.tsv", fileFormat: ExcelFileFormat.XLSX, listDelimiter: "\t");
// Reading a pipe-delimited file
WorkBook pipeData = WorkBook.LoadCSV("legacy_system.csv", fileFormat: ExcelFileFormat.XLSX, listDelimiter: "|");
// Access data identically regardless of original delimiter
WorkSheet sheet = euroData.DefaultWorkSheet;
int rowsCount = sheet.RowCount;
Console.WriteLine($"Loaded {rowsCount} rows with {sheet.ColumnCount} CSV columns");
}
}El parámetro listDelimiter de LoadCSV acepta cualquier carácter o secuencia de escape como separador de campos. Los caracteres de tabulación utilizan la secuencia de escape \t. Tras la carga, la estructura de datos se mantiene coherente independientemente del formato original, lo que facilita el procesamiento de archivos CSV de múltiples fuentes con delimitadores variables. El valor predeterminado para la mayoría de los archivos CSV es una coma, pero esta flexibilidad permite manejar cualquier variación que encuentre su proyecto.
Entrada
Leer CSV .NET: The Simplest C# Approach Using IronXL: Image 6 - Semicolon-delimited CSV File Input (Leer CSV .NET: El enfoque más simple de C# usando IronXL: Imagen 6 - Entrada de archivo CSV delimitado por punto y coma)
Resultado
Leer CSV .NET: The Simplest C# Approach Using IronXL: Imagen 7 - Salida delimitada por punto y coma
Las propiedades de clase RowCount y ColumnCount proporcionan una rápida verificación de que el archivo se ha cargado correctamente, lo que resulta especialmente útil cuando se trabaja con fuentes de datos desconocidas o se validan cargas de usuario en una aplicación ASP.NET Core.
¿Cuáles son los mejores métodos para convertir CSV a DataTable?
La conversión de datos CSV en una DataTable permite la integración con operaciones de bases de datos, la vinculación de datos en aplicaciones de interfaz de usuario y las consultas LINQ. El método ToDataTable realiza esta conversión con una sola llamada.
using IronXL;
using System;
using System.Data;
class Program
{
static void Main(string[] args)
{
// Load CSV and convert to DataTable
WorkBook workbook = WorkBook.LoadCSV("customers.csv", ExcelFileFormat.XLSX, ",");
WorkSheet sheet = workbook.DefaultWorkSheet;
// Convert worksheet to DataTable - true parameter uses CSV file header as column names
DataTable dataTable = sheet.ToDataTable(true);
// DataTable is now ready for database operations, binding, or LINQ queries
Console.WriteLine($"DataTable created with {dataTable.Columns.Count} columns:");
foreach (DataColumn column in dataTable.Columns)
{
// Property names from CSV header become column names
Console.WriteLine($" - {column.ColumnName}");
}
Console.WriteLine($"\nTotal records: {dataTable.Rows.Count}");
// Access data using standard DataTable syntax
foreach (DataRow row in dataTable.Rows)
{
// Access by column index or name attribute
string name = row["Name"].ToString();
string email = row["Email"].ToString();
Console.WriteLine($"Customer: {name}, Email: {email}");
}
}
}using IronXL;
using System;
using System.Data;
class Program
{
static void Main(string[] args)
{
// Load CSV and convert to DataTable
WorkBook workbook = WorkBook.LoadCSV("customers.csv", ExcelFileFormat.XLSX, ",");
WorkSheet sheet = workbook.DefaultWorkSheet;
// Convert worksheet to DataTable - true parameter uses CSV file header as column names
DataTable dataTable = sheet.ToDataTable(true);
// DataTable is now ready for database operations, binding, or LINQ queries
Console.WriteLine($"DataTable created with {dataTable.Columns.Count} columns:");
foreach (DataColumn column in dataTable.Columns)
{
// Property names from CSV header become column names
Console.WriteLine($" - {column.ColumnName}");
}
Console.WriteLine($"\nTotal records: {dataTable.Rows.Count}");
// Access data using standard DataTable syntax
foreach (DataRow row in dataTable.Rows)
{
// Access by column index or name attribute
string name = row["Name"].ToString();
string email = row["Email"].ToString();
Console.WriteLine($"Customer: {name}, Email: {email}");
}
}
}El parámetro booleano de ToDataTable determina si la primera fila debe convertirse en cabeceras de columna (true) o en datos (false). Cuando se establece en true, las columnas de la DataTable resultante llevan los nombres de las propiedades de la fila de cabecera del archivo CSV, lo que permite un acceso intuitivo a los datos utilizando nombres de columnas como row["Name"].
Esta conversión resulta muy útil en situaciones que requieren inserciones masivas en bases de datos mediante SqlBulkCopy, rellenar controles DataGridView en aplicaciones Windows Forms o realizar transformaciones de datos complejas con expresiones LINQ. El formato DataTable también se integra de forma natural con Entity Framework y otras herramientas ORM en su proyecto de API web .NET Core.
¿Se pueden convertir archivos CSV a formato Excel?
Una de las capacidades más destacadas de IronXL es la conversión de datos CSV a formatos Excel adecuados. Esto permite añadir fórmulas, formatos, gráficos y múltiples hojas de cálculo a datos CSV planos en un principio, algo que no se puede conseguir únicamente escribiendo archivos CSV.
using IronXL;
using System;
class Program
{
static void Main(string[] args)
{
// Load CSV data from file path
string path = "quarterly_sales.csv";
WorkBook workbook = WorkBook.LoadCSV(path, ExcelFileFormat.XLSX, ",");
// Save as Excel XLSX format - create new Excel file
workbook.SaveAs("quarterly_sales.xlsx");
// Alternative: Save as legacy XLS format for older Excel versions
workbook.SaveAs("quarterly_sales.xls");
Console.WriteLine("CSV successfully converted to Excel format");
}
}using IronXL;
using System;
class Program
{
static void Main(string[] args)
{
// Load CSV data from file path
string path = "quarterly_sales.csv";
WorkBook workbook = WorkBook.LoadCSV(path, ExcelFileFormat.XLSX, ",");
// Save as Excel XLSX format - create new Excel file
workbook.SaveAs("quarterly_sales.xlsx");
// Alternative: Save as legacy XLS format for older Excel versions
workbook.SaveAs("quarterly_sales.xls");
Console.WriteLine("CSV successfully converted to Excel format");
}
}El método SaveAs determina automáticamente el formato de salida en función de la extensión del archivo. XLSX crea archivos Office Open XML modernos compatibles con Excel 2007 y versiones posteriores, mientras que XLS produce documentos heredados de Binary Interchange File Format para aplicaciones más antiguas.
Entrada
Leer CSV .NET: The Simplest C# Approach Using IronXL: Image 8 - CSV Data
Resultado
Leer CSV .NET: The Simplest C# Approach Using IronXL: Image 9 - Excel Output
Leer CSV .NET: The Simplest C# Approach Using IronXL: Image 10 - CSV to Excel Output
Este flujo de trabajo resulta especialmente útil cuando es necesario mejorar las exportaciones CSV de bases de datos o API antes de distribuirlas a un usuario. Tras la conversión, el archivo de Excel puede recibir formato adicional, fórmulas o combinarse con otras hojas de trabajo, todo ello mediante programación a través de completas capacidades de edición de IronXL. A diferencia de los enfoques que utilizan un escritor var con una nueva instancia StreamWriter para escribir archivos CSV, IronXL maneja toda la conversión de archivos sin problemas.
¿Cómo se accede a valores de celda específicos en datos CSV?
Además de iterar a través de todos los registros, IronXL proporciona acceso directo a las celdas mediante un direccionamiento familiar al estilo Excel. Esto permite la extracción selectiva de datos y la recuperación de valores seguros en diferentes tipos de datos.
using IronXL;
using System;
// Example class to demonstrate structured data access
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
WorkBook workbook = WorkBook.LoadCSV("inventory.csv", ExcelFileFormat.XLSX, ",");
WorkSheet sheet = workbook.DefaultWorkSheet;
// Access specific cells using Excel-style addresses by index
string productName = sheet["A2"].StringValue;
int quantity = sheet["B2"].IntValue;
decimal price = sheet["C2"].DecimalValue;
Console.WriteLine($"Product: {productName}");
Console.WriteLine($"Quantity: {quantity}");
Console.WriteLine($"Price: ${price:F2}");
// Access a range of cells - return records from column A
var productRange = sheet["A2:A10"];
Console.WriteLine("\nAll products:");
foreach (var cell in productRange)
{
Console.WriteLine($" - {cell.StringValue}");
}
}
}using IronXL;
using System;
// Example class to demonstrate structured data access
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
WorkBook workbook = WorkBook.LoadCSV("inventory.csv", ExcelFileFormat.XLSX, ",");
WorkSheet sheet = workbook.DefaultWorkSheet;
// Access specific cells using Excel-style addresses by index
string productName = sheet["A2"].StringValue;
int quantity = sheet["B2"].IntValue;
decimal price = sheet["C2"].DecimalValue;
Console.WriteLine($"Product: {productName}");
Console.WriteLine($"Quantity: {quantity}");
Console.WriteLine($"Price: ${price:F2}");
// Access a range of cells - return records from column A
var productRange = sheet["A2:A10"];
Console.WriteLine("\nAll products:");
foreach (var cell in productRange)
{
Console.WriteLine($" - {cell.StringValue}");
}
}
}El direccionamiento de las celdas sigue las convenciones de Excel, donde las letras representan columnas CSV (A, B, C) y los números representan posiciones de índice de fila (1, 2, 3). La clase Cell proporciona accesores específicos de tipo, incluidos StringValue, IntValue, DecimalValue, BoolValue y DateTimeValue. Estos accesores gestionan el análisis sintáctico y la conversión de forma automática, eliminando la conversión manual de tipos y reduciendo la sobrecarga de memoria en comparación con el almacenamiento de todo como valores de cadena.
La selección de rangos utilizando una notación como A2:A10 devuelve un objeto Range que admite iteración, funciones agregadas y operaciones masivas. Esto resulta valioso a la hora de extraer columnas específicas o regiones de datos rectangulares de archivos CSV de gran tamaño. Por ejemplo, puede crear una nueva lista de valores a partir de una columna específica o escribir datos filtrados en otro archivo.
Manejo de errores en operaciones con archivos CSV
La gestión de errores es esencial cuando se trabaja con archivos CSV en aplicaciones .NET. La lectura y escritura de archivos CSV puede dar lugar a diversos problemas, como archivos que faltan, datos mal formados o errores de análisis inesperados. Para gestionar estas situaciones, la mejor práctica consiste en envolver las operaciones con archivos y datos en bloques try-catch, lo que permite que la aplicación gestione las excepciones con elegancia y proporcione información significativa.
Conclusión
La lectura de archivos CSV en .NET requiere un esfuerzo mínimo si se utiliza el enfoque adecuado. El método LoadCSV de IronXL maneja la complejidad del análisis automáticamente, soportando varios delimitadores y proporcionando acceso inmediato a datos estructurados a través de conceptos familiares de hojas de cálculo. Tanto si está creando una aplicación ASP.NET Core, una API web .NET Core o un proyecto de consola, esta biblioteca agiliza el procesamiento de CSV.
Inicie una prueba gratuita para experimentar cómo IronXL simplifica la lectura de archivos CSV en sus proyectos .NET. Para el despliegue en producción, las opciones de licencia comienzan en $799 con derechos de uso perpetuo y un año de soporte incluido.
Preguntas Frecuentes
¿Cuál es la forma más sencilla de leer archivos CSV en C#?
La forma más sencilla de leer archivos CSV en C# es utilizar IronXL, que proporciona un método sencillo y eficaz para manejar datos CSV.
¿Puede IronXL manejar archivos CSV grandes de manera eficiente?
Sí, IronXL está diseñado para manejar eficazmente archivos CSV de gran tamaño, por lo que es adecuado para procesar grandes conjuntos de datos sin problemas de rendimiento.
¿Es IronXL compatible con las aplicaciones .NET?
IronXL es totalmente compatible con las aplicaciones .NET, lo que permite a los desarrolladores integrar fácilmente las funciones de lectura de CSV en sus proyectos de C#.
¿Es IronXL compatible con la lectura de archivos CSV con diferentes delimitadores?
IronXL es compatible con la lectura de archivos CSV con varios delimitadores, lo que proporciona flexibilidad para manejar archivos con diferentes formatos.
¿Puede IronXL analizar archivos CSV con encabezados?
Sí, IronXL puede analizar archivos CSV con encabezados, lo que le permite acceder fácilmente a los datos por nombres de columna.
¿Cómo simplifica IronXL la manipulación de datos CSV?
IronXL simplifica la manipulación de datos CSV ofreciendo métodos intuitivos para leer, editar y escribir datos CSV directamente en C#.
¿Existe soporte para leer archivos CSV de forma asíncrona en IronXL?
IronXL proporciona soporte para operaciones asíncronas, lo que le permite leer archivos CSV sin bloquear el hilo principal de la aplicación.
¿Puede IronXL convertir datos CSV a formato Excel?
IronXL puede convertir datos CSV a formato Excel, lo que le permite aprovechar las funciones avanzadas de Excel para el análisis y la presentación de datos.
¿Tiene IronXL alguna dependencia para leer archivos CSV?
IronXL es una biblioteca independiente que no requiere dependencias externas para leer archivos CSV, lo que simplifica el proceso de configuración en sus proyectos.
¿Se puede utilizar IronXL para exportar datos de CSV a otros formatos?
Sí, IronXL puede exportar datos de CSV a varios formatos, incluido Excel, lo que proporciona versatilidad en el manejo de datos y la generación de informes.







