XML con estructura de directorio en C# y VB

Crear en el Escritorio un archivo XML con la estructura de un directorio, incluyendo archivos y subcarpetas de forma recursiva, utilizando la clase XDocument del espacio de nombres System.Xml.Linq, y mostrar en un control el texto generado con el método WriteAllText de la clase File, en C# y VB

Basado en el código propuesto por Marcin Juraszek en el artículo «Creating XML file representing folder structure (including subfolders) in C#» del sitio web stackoverflow.

Inicio y selección de directorio

Espacios de nombres que hay que importar.

using System;
using System.Windows.Forms;
using System.Xml.Linq;
using System.IO;

Desde un diálogo de selección de carpeta se elige el directorio cuya estructura deseamos pasar a XML. Este diálogo se muestra con la carpeta especial Escritorio como ítem superior en la jerarquía de carpetas mediante el método RootFolder de la clase FolderBrowserDialog. La ruta a la carpeta elegida se pasa a un control TextBox para ser mostrada en el formulario.

// Instanciar un nuevo FolderBrowserDialog sin botón de crear carpeta nueva
FolderBrowserDialog ExplorarDlg = new FolderBrowserDialog();
ExplorarDlg.ShowNewFolderButton = false;
// Si el usuario selecciona una carpeta, la ruta (SelectedPath) se pasa a TextBoxRuta
DialogResult result = ExplorarDlg.ShowDialog();
if (result == DialogResult.OK)
{
    TextBoxRuta.Text = ExplorarDlg.SelectedPath;
    hayRuta = true;
    // Carpeta raíz del cuadro de diálogo de selección de carpeta: Escritorio arriba del todo
    ExplorarDlg.RootFolder = Environment.SpecialFolder.Desktop;
}

Generación del texto en formato XML

El nombre del directorio seleccionado sin la ruta completa (requerido) se obtiene mediante los métodos SubString y LastIndexOf eliminando lo que hay antes de la última aparición del carácter \ para dejar solamente el nombre de la carpeta.
La clase DirectoryInfo sirve para para obtener información de archivos y carpetas del directorio seleccionado.
La clase XDocument representa un documento XML que se va a obtener desde la función recursiva Directorio2Xml a la que se le pasa como parámetro el directorio inicial (raíz) para que genere toda la estructura de subcarpetas y archivos.
Se utiliza una cadena para el encabezado con la definición del documento XML y al final del texto se añade como última línea el cierre de la etiqueta xml. De esta forma el archivo, aunque básico, queda bien formado y no da errores al ser leído por otros programas. En resumen, el resultado es un objeto String con: encabezado + estructura del directorio en formato XML + cierre de la etiqueta inicial.

// El nombre de la carpeta inicial se obtiene del cuadro de texto con la ruta,
// eliminando lo que hay antes de la última aparición del carácter \
// para dejar solamente el nombre de la carpeta
String nombreCarpeta1 = TextBoxRuta.Text.Substring(TextBoxRuta.Text.LastIndexOf("\\") + 1);
//
// Clase DirectoryInfo para obtener información del directorio inicial (raíz)
DirectoryInfo infoCarpeta1 = new DirectoryInfo(TextBoxRuta.Text);
// XDocument representa un documento XML que se va a obtener desde la función Directorio2Xml 
// a la que se le pasa como parámetro el directorio inicial (raíz)
XDocument XDocumento = new XDocument(Directorio2Xml(infoCarpeta1));
// Cadena para contener el texto XML devuelto al terminar la función Directorio2Xml
String TextoXml;
TextoXml = XDocumento.ToString();
//
// Cadenas para colocar al principio del texto la definición del documento XML
String nodoCabecera = "<xml version=\"1.0\" encoding=\"UTF-8\">";
// Escribir al principio del cuadro de texto la línea con nodoCabecera y después el texto XML completo 
// terminado con </xml> para cerrar bien esa etiqueta
TextBoxXml.Text = nodoCabecera + "\r\n" + TextoXml + "\r\n" + "</xml>";
//
// Cadena para contener todo el contenido actual del cuadro de texto
String XmlCompleto = TextBoxXml.Text;

El nombre del archivo XML se crea con: ruta al Escritorio + nombre del directorio inicial + extensión xml. El método WriteAllText de la clase File escribe en ese archivo el contenido de la cadena .

// Ruta a la carpeta Escritorio del usuario
String archivoDesktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
// El nombre del archivo es el del directorio raíz con extensión .xml guardado en el Escritorio
archivoDesktop += "\\" + nombreCarpeta1 + ".xml";
// File.WriteAllText crea un archivo nuevo, escribe el contenido en el archivo y lo cierra. 
// Si el archivo de destino ya existe, se sobrescribe
File.WriteAllText(archivoDesktop, TextBoxXml.Text);

Función recursiva Directorio2Xml

Se trata de una función recursiva que recorre el directorio elegido, las subcarpetas y los archivos que contiene añadiendo al texto xml:

  • como elementos xml (XElement) las carpeta y los archivos
  • como atributos (XAttribute) los nombres de carpetas y archivos.
// Los elementos XML son carpetas y archivos y el atributo de ambos es nombre
XElement elementoXml = new XElement("carpeta", new XAttribute("nombre", directorio.Name));
// recorrer archivos del directorio
foreach (var archivo in directorio.GetFiles())
    elementoXml.Add(new XElement("archivo", new XAttribute("nombre", archivo.Name)));
// recorrer subcarpetas del directorio
foreach (var subCarpeta in directorio.GetDirectories())
    elementoXml.Add(Directorio2Xml(subCarpeta));
// Devuelve la información recopilada en formato XML
return elementoXml;

Error al compilar

La compilación (en C# siempre y en VB cuando la configuración Release está activa) se interrumpe en la función Directorio2Xml con el mensaje: «Error CS0161 ‘Form1.Directorio2Xml(DirectoryInfo)’: no todas las rutas de acceso de código devuelven un valor«. Se puede evitar lanzando con throw la excepción InvalidOperationException en lugar de capturarla con catch o, sólo en VB, depurando con la configuración Debug.

catch (Exception)
{                
	throw new InvalidOperationException();
	}

Puedes descargar un archivo ZIP con la aplicación en C# o en VB.

3 comentarios en «XML con estructura de directorio en C# y VB»

    • Antes usaba como bloque independiente Syntax Highlighter Evolved que funciona bien y queda bien estéticamente pero descubrí Code Syntax Block de Marcus Kazmierczak que no añade bloque nuevo sino que amplia la funcionalidad del bloque de código integrado en Gutenberg y es el que uso ahora, con un archivo de estilo para Prism creado por Andrew Lock con los colores de Visual Studio (https://andrewlock.net) y modificado por mí.

      Responder

Responder a Alberto Cancelar la respuesta