Framework .NET 3.5 14 Gestión de archivos y serialización

2,656 views
2,551 views

Published on

Published in: Technology, Design
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,656
On SlideShare
0
From Embeds
0
Number of Embeds
8
Actions
Shares
0
Downloads
41
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • The BinaryFormatter and SoapFormatter classes use a common mechanism to serialize data in two common formats. They both implement the IFormatter interface to provide Serialize and Deserialize methods that can take advantage of classes that implement the ISerializable interface. In fact, both formatter classes are based on the same serialization infrastructure that the .NET Framework class library provides. You can take advantage of this infrastructure to build your own custom formatter classes if you must serialize data in a completely different format. Understanding the IFormatter Interface and the Formatter Class A custom formatter class can implement the methods and properties in the Iformatter interface. This interface defines two methods, Serialize and Deserialize, which have already been described in this module. The IFormatter interface also contains three properties. The following table describes these properties. Property Description Binder This property gets or sets the SerializationBinder object that is used to determine the types for constructing objects when you deserialize a stream. Context This property gets or sets the SerializationContext object that the serialization and deserialization processes use. SurrogateSelector This property makes it possible for one class to take responsibility for serializing and deserializing objects of another class. Such classes are referred to as serialization surrogates. A serialization surrogate is discovered and invoked through an ISurrogateSelector object. This property gets or sets the ISurrogateSelector object that the formatter can use. Two parameters are passed to the Serialize method: a Stream object to send serialized data to and a reference to the object to be serialized down this stream. The Serialize method can perform the following tasks: Determine whether the type of the object is serializable and throw a SerializationException exception if it is not. Call the method that is tagged with the OnSerializingAttribute attribute for each serialized object (if the object has such a method). Create SerializationInfo and StreamingContext objects. Populate the StreamingContext object with information about the current streaming context. If the object that is being serialized implements the ISerializable interface, call the GetObjectData method of this object, passing the SerializationInfo and StreamingContext objects to it. If the object that is being serialized does not implement the ISerializable interface, populate the SerializationInfo object with the data from the object that is being serialized. Write the metadata that identifies the assembly and type of the object that is being serialized to the output stream. Note: When you implement the Serialize method, you can ensure that you serialize not only the data that the object holds, but also enough information to enable the Deserialize method to identify the type of the object and instantiate it. Iterate through the SerializationInfo object and write the data to the output stream. Call the method that is tagged with the OnSerializedAttribute attribute for the object that is being serialized (if the object has such a method). A single parameter is passed to the Deserialize method: a Stream object to provide access to the serialized data. The Deserialize method can perform the following tasks: Read the stream and parse the metadata to determine which assembly to use and which type to construct. Load the assembly and type into memory, and create a new, empty instance of the type that is being deserialized. Create and populate a SerializationInfo object with the data in the serialization stream. Create and populate a StreamingContext object with information about the current streaming context. Call the method that is tagged with the OnDeserializingAttribute attribute for the object that is being serialized (if the object has such a method). Use reflection to determine whether the type implements a deserialization constructor; if it does, create and populate a new instance by using this constructor, passing the SerializationInfo and StreamingContext objects to it. If the type does not provide a deserialization constructor, create and populate the object by using the data from the SerializationInfo object. Call the method that is tagged with the OnDeserializedAttribute attribute for the object that is being deserialized (if the object has such a method). If the type that is being deserialized implements the IDeserializationCallback interface, call the OnDeserialization method of the object. The simplest way to implement a formatter object is to inherit from the Formatter abstract class in the System.Runtime.Serialization namespace. This class provides a default implementation of some key aspects of the serialization process, and contains abstract methods and properties that you override to implement your own functionality. In addition, the System.Runtime.Serialization namespace contains several other helper classes that can assist you to create a custom formatter. These classes include SerializationObjectManager and ObjectManager, FormatterServices, and FormatterConverter. Understanding the SerializationObjectManager and ObjectManager Classes You use the SerializationObjectManager class when you serialize an object. You can create an instance of this class in the Serialize method of a custom formatter. As you start to serialize each object, call the RegisterObject method of the SerializationObjectManager object; this method calls any method that is tagged with the OnSerializingAttribute attribute to be executed for the object that is being serialized.When you have serialized an object, call the RaiseOnSerializedEvent method of the SerializationObjectManager to invoke any method that is tagged with the OnSerializedAttribute attribute in the object that is being serialized. When you implement the Deserialize method of a custom formatter, you can make use of an ObjectManager object. The ObjectManager class has already been described in the previous lesson; its primary function is to enable the deserialization process to track which objects have already been created when you deserialize a complex graph that potentially contains multiple references to the same objects. In the Deserialize method, you can call the RegisterObject method of the ObjectManager class as you deserialize objects. The RegisterObject method expects you to provide a numeric identifier for the object. You can create an instance of the ObjectIDGenerator class and create these identifiers by calling the GetId method. The ObjectIDGenerator class also provides a method that is called HasId, which you can use to determine whether an object that is referenced in the serialization stream has already been deserialized or whether this is a new instance. If you detect a reference to an object that has not yet been deserialized, you can record this reference by using the RecordDelayedFixup and RecordFixup methods of the ObjectManager object. At the end of the deserialization process, you can call the DoFixups method of the ObjectManager class to resolve all object references. The ObjectManager class has another purpose: it can call any method that is marked with the OnDeserializingAttribute attribute before serialization commences. It can also invoke any method that is tagged with the OnDeserializedAttribute attribute and call the OnDeserialization method for deserialized objects that implement the IDeserializationCallback interface. To invoke a method that is tagged with the OnDeserializingAttribute attribute, call the RaiseOnDeserializingEvent method. To invoke a method that is marked with the OnDeserializedAttribute attribute and call the OnDeserialization method, register the object with the ObjectManager object and then call the RaiseDeserializationEvent method. Understanding the FormatterServices Class The FormatterServices class contains static (C#) or Shared (Visual Basic) methods that you can use to obtain information about objects that are being serialized and deserialized. The following table lists the most commonly used methods. Method Description GetSerializableMembers This method returns an array of serializable members for a type. Any members that are tagged with the NonSerializedAttribute attribute are omitted. The Serialize method of a custom formatter class can use this data to ensure that only the correct members of an object are written to the serialization stream. GetTypeFromAssemblyThis method returns the information for a specified type from an assembly. GetUninitializedObject This method creates a new instance of an object by using the specified type. PopulateObjectMembersThis method fills the fields of an uninitialized object with the values that are provided. You can use the PopulateObjectMembers method in conjunction with GetUninitializedObject and GetTypeFromAssembly to construct a new object during the deserialization process. You can assume that your serialization stream contains metadata about the type of each object. Call GetTypeFromAssembly to create a Type object, call GetUninitializedObject to create an instance of this type, and then call PopulateObjectMembers to fill this object with data that is retrieved from the serialization stream. Understanding the IFormatterConverter Interface and the FormatterConverter Class When you serialize and deserialize data, you create a SerializationInfo object that contains the fields that are serialized or deserialized. Each field may require converting into a different format as it is written to or read from the serialization stream. You can create a class that implements the IFormatterConverter interface to parse the data that is held in the SerializationInfo object and perform these conversions. Alternatively, the FormatterConverter class provides a default implementation of the methods in the IFormatterConverter interface. If this default implementation meets your requirements, create an instance of this class when you serialize and deserialize data. You can also inherit from the FormatterConverter class and override any methods that you must modify. Creating a Custom Formatter Class The following code examples illustrate a custom formatter class that serializes data as ordinary text, and show how to implement the Serialize and Deserialize methods (the other methods and properties have been omitted from these examples). Note: These code examples serialize and deserialize only types that contain members that are primitive types or strings. Additionally, the Deserialize method makes use of reflection. The details of reflection are outside the scope of this course, so this method is provided for information only. [Visual C#] class TextFormatter : Formatter { ... public override void Serialize(System.IO.Stream serializationStream, object graph) { Type objectType = graph.GetType(); // Verify that the object is serializable if (objectType.IsSerializable) { // Create the objects and context for serializing the data StreamWriter writer = new StreamWriter(serializationStream); FormatterConverter converter = new FormatterConverter(); SerializationInfo info = new SerializationInfo(objectType, converter); StreamingContext context = new StreamingContext(); // Register the object being serialized and raise the OnSerializing event SerializationObjectManager objectManager = new SerializationObjectManager(context); objectManager.RegisterObject(graph); if (graph is ISerializable) { // If the object implements ISerializable then let it populate the // SerializationInfo object ((ISerializable)graph).GetObjectData(info, context); } else { // Otherwise populate the SerializationInfo object with the data for // each serializable field foreach (FieldInfo field in FormatterServices.GetSerializableMembers(objectType)) { info.AddValue(field.Name, field.GetValue(graph)); } } // Output the metadata describing the object type string metadata = String.Format("Type:{0}", objectType.FullName); writer.WriteLine(metadata); metadata = String.Format("Assembly:{0}", objectType.Assembly); writer.WriteLine(metadata); // Output the data in each field SerializationInfoEnumerator infoEnumerator = info.GetEnumerator(); while (infoEnumerator.MoveNext()) { SerializationEntry entry = infoEnumerator.Current; string data = String.Format("{0}:{1}:{2}", entry.Name, entry.Value, entry.ObjectType.FullName); writer.WriteLine(data); } // Raise the OnSerialized event for the object objectManager.RaiseOnSerializedEvent(); // Flush the stream and ensure that all data is output writer.Flush(); } else { // Throw an exception if the object is not serializable string message = String.Format("{0} is not marked as serializable.", objectType.ToString()); throw new SerializationException(message); } } public override object Deserialize(System.IO.Stream serializationStream) { try { StreamReader reader = new StreamReader(serializationStream); // Read and parse the first two lines of the stream // The first line contains the type, in the format Type:Namespace.Type string line = reader.ReadLine(); string[] data = line.Split(':'); string typeName = data[1]; // The second line contains the metadata for the assembly, // in the format Assembly:<metadata> line = reader.ReadLine(); data = line.Split(':'); string assemblyName = data[1]; // Load the assembly into memory Assembly assembly = Assembly.Load(assemblyName); // Create an empty instance of the type being deserialized Type type = FormatterServices.GetTypeFromAssembly(assembly, typeName); object deserializedObject = FormatterServices.GetUninitializedObject(type); // Create and populate a serializationInfo object with the fields in the stream FormatterConverter converter = new FormatterConverter(); SerializationInfo info = new SerializationInfo(type, converter); // This implementation only recognizes members with types // implemented in the core .NET Framework assembly Assembly systemAssembly = Assembly.ReflectionOnlyLoad( "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); ArrayList objectData = new ArrayList(); while ((line = reader.ReadLine()) != null) { // Each line has the format FieldName:Value:TypeCode data = line.Split(':'); // Get the type of the serialized member Type dataType = systemAssembly.GetType(data[2]); // Add the member to the SerializationInfo collection, // converting it to the correct type info.AddValue(data[0], converter.Convert(data[1], dataType)); // Also save the data in an object array in case you need to // populate the object manually objectData.Add(converter.Convert(data[1], dataType)); } // Create a StreamingContext stating that the data is coming from a file StreamingContext context = new StreamingContext(StreamingContextStates.File); // Create an ObjectManager object and raise the OnDeserializing event // for the object being deserialized ObjectManager manager = new ObjectManager(null, context); manager.RaiseOnDeserializingEvent(deserializedObject); // Determine if the object being deserialized has a deserialization constructor Type serializationInfoType = info.GetType(); Type streamingContextType = context.GetType(); Type[] deserializationConstructorParams = new Type[] {serializationInfoType, streamingContextType}; ConstructorInfo constructor = type.GetConstructor( BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, deserializationConstructorParams, null); // If the object has a deserialization constructor then call it to populate the object if (constructor != null) { Object[] args = new Object[] {info, context}; constructor.Invoke(deserializedObject, args); } // Otherwise populate it manually else { MemberInfo[] members = type.GetFields( BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); FormatterServices.PopulateObjectMembers(deserializedObject, members, objectData.ToArray()); } // Call the OnDeserialization method if the object implements IDeserializationCallback // and raise the OnDeserialized event for the object bool firstTime; manager.RegisterObject(deserializedObject, m_idGenerator.GetId(deserializedObject, out firstTime)); manager.RaiseDeserializationEvent(); // Return the deserialized object return deserializedObject; } catch (Exception e) { string message = String.Format("Unable to deserialize object: {0}", e.Message); throw new SerializationException(message); } } ... } [Visual Basic] Class TextFormatter Inherits Formatter ... Public Overrides Sub Serialize(ByVal serializationStream As System.IO.Stream, _ ByVal graph As Object) Dim objectType As Type = graph.GetType() ' Verify that the object is serializable If objectType.IsSerializable Then ' Create the objects and context for serializing the data Dim writer As New StreamWriter(serializationStream) Dim converter As New FormatterConverter() Dim info As New SerializationInfo(objectType, converter) Dim context As New StreamingContext() ' Register the object being serialized and raise the OnSerializing event Dim objectManager As New SerializationObjectManager(context) objectManager.RegisterObject(graph) If TryCast(graph, ISerializable) IsNot Nothing Then ' If the object implements ISerializable then let it populate the ' SerializationInfo object graph.GetObjectData(info, context) Else ' Otherwise populate the SerializationInfo object with the data for each ' serializable field For Each field As FieldInfo In _ FormatterServices.GetSerializableMembers(objectType) info.AddValue(field.Name, field.GetValue(graph)) Next field End If ' Output the metadata describing the object type Dim metadata As String = String.Format("Type:{0}", _ objectType.FullName) writer.WriteLine(metadata) metadata = String.Format("Assembly:{0}", objectType.Assembly) writer.WriteLine(metadata) ' Output the data in each field Dim infoEnumerator As SerializationInfoEnumerator = info.GetEnumerator() While infoEnumerator.MoveNext() Dim entry As SerializationEntry = infoEnumerator.Current Dim data As String = String.Format("{0}:{1}:{2}", entry.Name, _ converter.ToString(entry.Value), entry.ObjectType.FullName) writer.WriteLine(data) End While ' Raise the OnSerialized event for the object objectManager.RaiseOnSerializedEvent() ' Flush the stream and ensure that all data is output writer.Flush() Else ' Throw an exception if the object is not serializable Dim message As String = _ String.Format("{0} is not marked as serializable.", objectType.ToString()) Throw New SerializationException(message) End If End Sub Public Overrides Function Deserialize( _ ByVal serializationStream As System.IO.Stream) As Object Try Dim reader As New StreamReader(serializationStream) ' Read and parse the first two lines of the stream ' The first line contains the type, in the format Type:Namespace.Type Dim line As String = reader.ReadLine() Dim data() As String = line.Split(":") Dim typeName As String = data(1) ' The second line contains the metadata for the assembly, ' in the format Assembly:<metadata> line = reader.ReadLine() data = line.Split(":") Dim assemblyName As String = data(1) ' Load the assembly into memory Dim assembly As Assembly = assembly.Load(assemblyName) ' Create an empty instance of the type being deserialized Dim type As Type = FormatterServices.GetTypeFromAssembly(assembly, typeName) Dim deserializedObject As Object = _ FormatterServices.GetUninitializedObject(type) ' Create and populate a serializationInfo object with the fields in the stream Dim converter As New FormatterConverter() Dim info As New SerializationInfo(type, converter) ' This implementation only recognizes members with types implemented ' in the core .NET Framework assembly Dim systemAssembly As Assembly = assembly.ReflectionOnlyLoad( _ "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") Dim objectData As New ArrayList() line = reader.ReadLine() While line IsNot Nothing ' Each line has the format FieldName:Value:TypeCode data = line.Split(":") ' Get the type of the serialized member Dim dataType As Type = systemAssembly.GetType(data(2)) ' Add the member to the SerializationInfo collection, ' converting it to the correct type info.AddValue(data(0), converter.Convert(data(1), dataType)) ' Also save the data in an object array in case we need to ' populate the object manually objectData.Add(converter.Convert(data(1), dataType)) line = reader.ReadLine() End While ' Create a StreamingContext stating that the data is coming from a file Dim context = New StreamingContext(StreamingContextStates.File) ' Create an ObjectManager object and raise the OnDeserializing event ' for the object being deserialized Dim manager = New ObjectManager(Nothing, context) manager.RaiseOnDeserializingEvent(deserializedObject) ' Determine if the object being deserialized has a ' deserialization constructor Dim serializationInfoType As Type = info.GetType() Dim streamingContextType As Type = context.GetType() Dim deserializationConstructorParams() As Type = _ {serializationInfoType, streamingContextType} Dim constructor As ConstructorInfo = type.GetConstructor( _ BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.Instance, _ Nothing, deserializationConstructorParams, Nothing) ' If the object has a deserialization constructor then call it ' to populate the object If constructor IsNot Nothing Then Dim args() As Object = {info, context} constructor.Invoke(deserializedObject, args) ' Otherwise populate it manually Else Dim members() As MemberInfo = type.GetFields( _ BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.Instance) FormatterServices.PopulateObjectMembers(deserializedObject, members, _ objectData.ToArray()) End If ' Call the OnDeserialization method if the object implements ' IDeserializationCallback ' and raise the OnDeserialized event for the object Dim firstTime As Boolean manager.RegisterObject(deserializedObject, _ m_idGenerator.GetId(deserializedObject, firstTime)) manager.RaiseDeserializationEvent() ' Return the deserialized object Return deserializedObject Catch e As Exception Dim message As String = String.Format( _ "Unable to deserialize object: {0}", e.Message) Throw New SerializationException(message) End Try End Function ... End Class The following code examples show how to create and use the TextFormatter class to serialize an object as text and store it in a file that is called data.txt. [Visual C#] namespace ProductAssembly { [Serializable] class Product { public int ProductId; public string ProductName; public decimal ProductPrice; } } … ProductAssembly.Product product = new ProductAssembly.Product(); product.ProductId = 1; product.ProductName = "Hammer"; product.ProductPrice = 11.99M; FileStream serializationStream = new FileStream(@"E:\\Democode\\data.txt", FileMode.Create, FileAccess.Write); TextFormatter textWriter = new TextFormatter(); textWriter.Serialize(serializationStream, product); serializationStream.Close(); [Visual Basic] Namespace ProductAssembly <Serializable()> Class Product Public ProductId As Integer Public ProductName As String Public ProductPrice As Decimal End Class End Namespace ... Dim product As New ProductAssembly.Product() product.ProductId = 1 product.ProductName = "Hammer" product.ProductPrice = 11.99 Dim serializationStream As New FileStream("E:\\Democode\\data.txt", FileMode.Create, FileAccess.Write) Dim textWriter As New TextFormatter() textWriter.Serialize(serializationStream, product) serializationStream.Close() The following code example illustrates the data.txt file that the TextFormatter object produces. Type:CustomFormatter.ProductAssembly.Product Assembly:CustomFormatter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null ProductId:1:System.Int32 ProductName:Hammer:System.String ProductPrice:11.99:System.Decimal
  • Framework .NET 3.5 14 Gestión de archivos y serialización

    1. 1. Índice<br />Gestionando el sistema de archivos<br />Leyendo y escribiendo datos mediante Streams<br />Compresión y protección de datos mediante Streams<br />Ampliando la seguridad de las aplicaciones utilizando almacenamiento aislado.<br />Serialización y Deserialización de objetos mediante Runtime Serialization<br />Personalización de los procesos de RuntimeSerialization y Deserialization<br />Serialización y Deserialización de objetos como datos XML<br />Todas las aplicaciones, excepto las más triviales, requieren algún tipo de entrada o salida de datos y, en muchos casos, se efectúa contra archivos.<br />.NET Framework nos provee de un conjunto de clases que nos permiten acceder al sistema de archivos del sistema, navegar por las carpetas, crear y eliminas archivos y leer y escribir en los mismos, implementado mediante un modelo de streaming. <br />Adicionalmente podemos encriptar y comprimir los datos al almacenarlos en un archivo o en memoria.<br />Aunque dado que la gestión de datos en memoria tiene sus limitaciones .NET nos suministra el almacenamiento aislado, para ayudarnos a persistir los datos privados a disco, peor protegidos de programas maliciosos. Esta técnica nos permite asignar un espacio de archivos para un usuario, aplicación o ensamblado, el cual será independiente de cualquier otro usuario, aplicación o ensamblado.<br />Gestión de archivos y Serialización<br />
    2. 2. Gestionando el sistema de archivos<br />Las clases File y FileInfo del espacio de nombres System.IO<br />Leer mediante la clase File<br />Las clases Directory yDirectoryInfo <br />La clase DriveInfo <br />Información de ruta de archivos y carpetas<br />Monitorizar cambios en archivos o carpetas<br />Gestión de archivos y Serialización<br />
    3. 3. Gestión de archivos y Serialización<br />Las clases File y FileInfo<br />Clase File<br />FileInfo class<br />Provee métodos de instancia.<br />Recibe el nombre de archivo como parámetros en el constructor.<br />Tiene propiedades para modificar atributos.<br />Comprueba la autorización en cada llamada<br />Se puede utilizar para realizar mútiples operaciones con un archivo<br />Provee métodos estáticos static (Shared) <br />Recibe el nombre de archivo como un parámetro<br />Tiene métodos para modificar atributos<br />Comprueba la autorización del usuario en cada llamada a método<br />Se puede utilizar para ejecutar una operación aislada con un archivo.<br />Create<br />Delete<br />Exists<br />Encrypt<br />Copy/CopyTo<br />Move/MoveTo<br />Replace<br />Decrypt<br />using System.IO;<br />...<br />File.Copy(@"E:DemocodeMyFile.txt", @"E:DemocodeCopyFile.txt", true);<br />File.SetAttributes(@"E:DemocodeCopyFile.txt", <br /> FileAttributes.ReadOnly | FileAttributes.Hidden);<br />using System.IO;<br />…<br />FileInfo dataFileInfo = new FileInfo(@"E:DemocodeMyFile.txt");<br />dataFileInfo.CopyTo(@"E:DemocodeCopyFile.txt", true);<br />FileInfo copyFileInfo = new FileInfo(@"E:DemocodeCopyFile.txt");<br />copyFileInfo.Attributes = FileAttributes.ReadOnly | FileAttributes.Hidden;<br />
    4. 4. Leer y escribir con la clase File<br />Gestión de archivos y Serialización<br />ReadAllBytes<br />ReadAllLines<br />ReadAllText<br />WriteAllBytes<br />WriteAllLines<br />WriteAllText<br />AppendAllText<br />
    5. 5. Las clases Directory y DirectoryInfo<br />Gestión de archivos y Serialización<br />La clase Directory<br />La clase DirectoryInfo<br />Provee métodos estáticos static (Shared)<br />Recibe el nombre de carpeta como parámetro<br />Incluye métodos que no están disponibles con la clase DirectoryInfo<br />Puede usarse para ejecutar una operación aislada con una carpeta<br />Provee métodos de instancia<br />Recibe el nombre de carpeta en el constructor<br />Incluye el método CreateSubdirectoryque no está en la clase Directory<br />Se usa para ejecutar múltiples operaciones con una carpeta<br />CreateDirectory/Create<br />GetDirectories<br />GetFileSystemEntries/<br />GetFileSystemInfos<br />Delete<br />Move/MoveTo<br />Exists<br />GetFiles<br />
    6. 6. Gestión de archivos y Serialización<br />Las clases Directory y DirectoryInfo<br />Directory class<br />Imports System.IO<br />...<br />Dim currentFolder As String<br />currentFolder = Directory.GetCurrentDirectory()<br />Dim fileAndFolderNames() As String<br />fileAndFolderNames = Directory.GetFileSystemEntries(currentFolder)<br />For Each entry As String In fileAndFolderNames<br />Console.WriteLine("{0}", entry)<br />Next entry<br />DirectoryInfo class<br />Dim backupFolder As New DirectoryInfo("E:Democodebackup")<br />If Not backupFolder.Exists Then<br />backupFolder.Create()<br />End If<br />Dim currentFolderName As String<br />currentFolderName = Directory.GetCurrentDirectory()<br />Dim currentFolder As New DirectoryInfo(currentFolderName)<br />For Each entry As FileInfo In currentFolder.GetFiles()<br />entry.CopyTo(backupFolder.FullName + "" + entry.Name)<br />Next entry<br />
    7. 7. La clase DriveInfo<br />Gestión de archivos y Serialización<br />Provee métodos y propiedades para recuperar información de dispositivos<br />Soporta discos fijos y portátiles, CD/DVD, diskettes y discos de red<br />GetDrives<br />IsReady<br />AvailableFreeSpace<br />DriveFormat<br />DriveType<br />RootDirectory<br />TotalFreeSpace<br />TotalSize<br />VolumeLabel<br />
    8. 8. Obtener información de la ruta de archivos y carpetas<br />Gestión de archivos y Serialización<br />La clase Path<br />Provee campos y métodos estáticos static (Shared) que permiten trocear nombres de archivo y carpetas<br />Siendo consciente de las capacidades y limitaciones del sistema de archivos<br />Tiene métodos para la generación de nombres de archivo únicos y temporales: GetTempFileName , GetRandomFileName <br />GetDirectoryName<br />GetFileName<br />GetPathRoot<br />E:DemocodeTestFolderTestFile.txt<br />E:DemocodeTestFolderTestFile.txt<br />E:DemocodeTestFolderTestFile.txt<br />E:DemocodeTestFolderTestFile.txt<br />E:DemocodeTestFolderTestFile.txt<br />E:DemocodeTestFolderTestFile.txt<br />E:DemocodeTestFolderTestFile.txt<br />GetExtension<br />DirectorySeparator<br />VolumeSeparator<br />
    9. 9. Monitorizar cambios en archivos o carpetas<br />Gestión de archivos y Serialización<br />La clase FileSystemWatcher<br />Monitoriza una carpeta y genera un evento si cambia un archivo o sub-carpeta<br />1<br />Crear un objeto FileSystemWatcher<br />Fijar la propiedad Path en la carpeta a monitorizar<br />Fijar las propiedades Filter y NotifyFilter para indicar los cambios a monitorizar<br />Informar la propiedadIncludeSubDirectory<br />Manejar los eventos Created, Changed,Deleted yRenamed<br />Fijar la propiedad EnableRaisingEvents a True<br />2<br />3<br />4<br />5<br />6<br />Filter: *.txt<br />NotifyFilter: Filename<br />Deleted<br />Created<br />Changed<br />Renamed<br />
    10. 10. Leer y escribir datos mediante Streams<br />¿Qué es un Stream de entrada / salida?<br />La clase FileStream<br />Leer y escribir texto en un Stream<br />Leer y escribir texto binario en un Stream<br />Leer y escribir datos temporales en memoria<br />¿Cómo añadir buffering a un StreamUnbuffered<br />La clase File nos suministra métodos static o Shared para efectuar lecturas y escrituras básicas en archivos.<br />Sin embargo las aplicaciones deben efectuar, normalmente, accesos a los datos más selectivos.<br />.NET Framework implementa un modelo de Streaming que podemos utilizar para acceder a los datos contenidos en los archivos.<br />Algunos de estos Streams permiten accede aleatorio, lo cual habilita la búsqueda de valores concretos para localizar la posición inicial y leer a partir de ahí o la inserción d datos en posiciones distintas del final de archivo.<br />Gestión de archivos y Serialización<br />
    11. 11. ¿Qué es un Stream de entrada/salida?<br />Gestión de archivos y Serialización<br />Un flujo de datos desde un origen a un destino mediante un único canal.<br />Los daos se reciben en el orden en el que se envían.<br />La clase Stream(utilizada mediante FileStream o MemoryStream)<br />Es la clase base par todos los Streams de .NET.<br />Implementa métodos y propiedades que manejan un Stream como una serie de bytes (ReDimwithSetLength).<br />Provee soporte para acceso aleatorio.<br />Utiliza el soporte de hardware, cuando está disponible, para grandes cantidades de datos.<br />Utiliza un puntero interno a la ubicación de los datos en origen.<br />Read<br />Flush<br />Seek<br />ReadByte<br />CanRead<br />Close<br />Write<br />CanWrite<br />Length<br />CanSeek<br />WriteByte<br />Position<br />
    12. 12. La clase FileStream<br />Gestión de archivos y Serialización<br />Es una implementación de la clase Stream para la lectura y escritura de archivos.<br />Se especifica la ruta, el archivo, el modo de apertura, el tipo de acceso, el tamaño de buffer y el acceso compartido en el constructor.<br />Read bytes<br />Write bytes<br />FileStream<br />
    13. 13. Gestión de archivos y Serialización<br />La clase FileStream<br />using System.IO;<br />byte[] firstMessage = newbyte[] { Convert.ToByte('H'), Convert.ToByte('o'), <br /> Convert.ToByte('l'), Convert.ToByte('l'), Convert.ToByte('a') };<br />byte[] secondMessage = newbyte[] { Convert.ToByte(' '), Convert.ToByte('M'), <br /> Convert.ToByte('u'), Convert.ToByte('n'), Convert.ToByte('d'), <br /> Convert.ToByte('o') };<br />using (FileStream file = new FileStream(@"E:DemocodeGreetings.txt",<br />FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))<br />{<br />file.Lock(0, firstMessage.Length + secondMessage.Length);<br />file.Write(firstMessage, 0, firstMessage.Length);<br />file.Write(secondMessage, 0, secondMessage.Length);<br />file.Unlock(0, firstMessage.Length + secondMessage.Length);<br />file.Seek(-3, SeekOrigin.End);<br />byte[] dataRead = new byte[3];<br />file.Read(dataRead, 0, dataRead.Length);<br />Console.WriteLine("Final 3 bytes: {0}{1}{2}",Convert.ToChar(dataRead[0]),<br /> Convert.ToChar(dataRead[1]), Convert.ToChar(dataRead[2]));<br />file.Close();<br />}<br /><ul><li>Final 3 bytes: rld</li></li></ul><li>Leer y escribir texto en un Stream<br />Gestión de archivos y Serialización<br />Las clases StreamReaderyStreamWriter <br />Convierten entre datos de texto y Stream de bytes<br />Dispone de métodos orientados a texto<br />Se utiliza con un objeto FileStreampara leer y escribir datos como texto<br />StreamReader<br />Read<br />Read text<br />ReadLine<br />La clase FileStream proporciona un medio muy rápido para leer y escribir datos como series de bytes.<br />Será necesario efectuar las conversiones entre los datos en bruto y los tipos adecuados (serialización y deserialización).<br />Las clase de .NET que pueden serializar los datos y deserializar series de bytes desde un stream hacia tipos primitivos o string de forma automática son, por ejemplo, StreamReader y StreamWriter.<br />Peek<br />Write<br />FileStream<br />WriteLine<br />Flush<br />Write text<br />StreamWriter<br />
    14. 14. Gestión de archivos y Serialización<br />Leer y escribir texto en un Stream<br />using System.IO;<br />...<br />string customerName = "John";<br />int customerAge = 43;<br />string customerNationality = "British";<br />string data = "";<br />using (StreamWriter writer = new StreamWriter(@"E:DemocodeCustomers.txt"))<br />{<br />writer.WriteLine("Customer Name: {0}", customerName);<br />writer.WriteLine("Age: {0}", customerAge);<br />writer.WriteLine("Nationality: {0}", customerNationality);<br />writer.Close();<br />}<br />using (StreamReader reader = new StreamReader(@"E:DemocodeCustomers.txt"))<br />{<br />data = reader.ReadLine();<br />Console.WriteLine("{0}", data);<br />data = reader.ReadLine();<br />Console.WriteLine("{0}", data);<br />data = reader.ReadLine();<br />Console.WriteLine("{0}", data);<br />reader.Close();<br />}<br />Customer Name: John<br />Age: 43<br />Nationality: British<br />
    15. 15. Leer y escribir datos binarios en un Stream<br />Gestión de archivos y Serialización<br />Las clases BinaryReadery BinaryWriter<br />Convierten entre tipos de .NET Framework y Stream de bytes<br />Dispone de métodos para leer y escribir tipos primitivos<br />Read/WriteChar<br />Read binary data<br />Read/WriteInt32<br />Read/WriteString<br />BinaryReader<br />Read/WriteDouble<br />FileStream<br />…<br />Write binary data<br />BinaryWriter<br />
    16. 16. Leer y escribir datos temporales en memoria<br />Gestión de archivos y Serialización<br />La clase MemoryStream<br />Es una implementación de la clase Stream que accede a la memoria.<br />Incluye métodos que copian datos a un Array u otro Stream.<br />Puede utilizarse con objetos Binary/StreamReadery Binary/StreamWriter para leer y escribir datos de texto o binarios.<br />Similar a FileStream pero almacenando en memoria.<br />ToArray<br />Read binary/text data<br />WriteTo<br />Binary/StreamReader<br />MemoryStream<br />Write binary/text data<br />Binary/StreamWriter<br />
    17. 17. Como añadir Buffering a un Stream Unbuffered<br />Gestión de archivos y Serialización<br />La clase BufferedStream<br />Añade almacenamiento temporal a un Stream que no disponga de él (Stream, NetworkStream o streams personalizados).<br />Actúa como un wrapper arropando un Streamunbuffered<br />Implementa métodos de Stream, pero los datos se almacenan temporalmente hasta que se lancen los métodos Flush o Close o el buffer esté lleno.<br />Se debe especificar el tamaño del buffer en el constructor.<br />Flush<br />BufferedStream<br />Unbuffered Stream<br />
    18. 18. Compresión y protección de datos mediante Streams<br />La clase DeflateStream para compresión de datos.<br />La clase GZipStream para compresión de datos.<br />La clase CryptoStream para encriptado de datos.<br />El modelo de streaming permite también que las aplicaciones transformen los datos que están siendo leídos o escritos de un archivo y .NET dispone de clases que pueden comprimir y encriptar los datos a medida que se procesan.<br />Estas características son muy útiles si se quiere reducir el espacio ocupado por un archivo o protege rel contenido del mismo de miradas indiscretas.<br />Gestión de archivos y Serialización<br />
    19. 19. La clase DeflateStream para compresión de datos<br />Gestión de archivos y Serialización<br />Comprime y descomprime los datos de un Stream de bytes<br />Implementa el algoritmo Deflate<br />No soporta acceso aleatorio produciendo una excepción NotSupportedException<br />Reside en el espacio de nombre System.IO.Compression<br />El tamaño máximo de Stream es de 4 Gb.<br />DeflateStream<br />
    20. 20. Gestión de archivos y Serialización<br />La clase DeflateStream para compresión de datos<br />using System.IO;<br />using System.IO.Compression;<br />// Datos a comprimir<br />string[] data = new string[] { "En un lugar de ola mancha", "de cuyo nombre no me quiero acordar", "vivia, no ha mucho un caballero.."};<br />// Compone un stream para escribir y comprimir<br />using (FileStream file = new FileStream(@"E:DemocodeCompressedData.dat",<br />FileMode.Create, FileAccess.Write)) <br />{<br />using (DeflateStream deflate = new DeflateStream(file,CompressionMode.Compress)) {<br />StreamWriter writer = new StreamWriter(deflate);<br />// Escribe los datos en el stream comprimido<br />foreach (string item in data) <br />{<br />writer.WriteLine(item);<br />}<br /> writer.Close();<br />}<br />}<br />
    21. 21. La clase GZipStream para compresión de datos<br />Gestión de archivos y Serialización<br />Comprime y descomprime datos en un Stream de bytes<br />Implementa el algoritmo Deflate<br />Formatea los datos según la especificación GZIP(Gzip, WinZip, WinRar)<br />GZipStream<br />
    22. 22. La clase CryptoStream para encriptado de datos<br />Gestión de archivos y Serialización<br />Encripta y desencripta datos en un Stream de bytes<br />Aplica una transformación criptográfica especificada por un objeto ICryptoTransform<br />.NET incluye varios proveedores de servicios criptográficos y el espacio de nombres System.Security.Cryptography<br />CryptoStream<br />ICryptoTransform Object<br />
    23. 23. Gestión de archivos y Serialización<br />using System.IO; <br />using System.Security.Cryptography; <br />string[] data = new string[] { "Top", "Secret", "Data" }; <br />FileStream fileWriter = new FileStream(@"E:DemocodeSecretData.bin", FileMode.Create, FileAccess.Write); <br />// Especifica la encriptación DES y genera la clave y el vector<br />DESCryptoServiceProvider dcspWriter = new DESCryptoServiceProvider(); <br />dcspWriter.GenerateKey(); <br />dcspWriter.GenerateIV(); <br />byte[] key = dcspWriter.Key; // Salva la clave<br />byte[] vector = dcspWriter.IV; // Salva el vector<br />// Crea un CryptoStream y encripta los datos<br />ICryptoTransform transformWriter = dcspWriter.CreateEncryptor(); <br />CryptoStream cryptoWriter = new CryptoStream(fileWriter, transformWriter, CryptoStreamMode.Write); <br />StreamWriter writer = new StreamWriter(cryptoWriter); <br />foreach (string item in data) { <br /> writer.WriteLine(item); <br />} <br />writer.Close(); <br />using System.IO; <br />using System.Security.Cryptography; <br />// Lee y desencripta los datos<br />FileStream fileReader = new FileStream(@"E:DemocodeSecretData.bin", FileMode.Open, FileAccess.Read); <br />DESCryptoServiceProvider dcspReader = new DESCryptoServiceProvider(); <br />ICryptoTransform transformReader = dcspReader.CreateDecryptor(key, vector); <br />CryptoStream cryptoReader = new CryptoStream(fileReader, transformReader, CryptoStreamMode.Read); <br />StreamReader reader = new StreamReader(cryptoReader); <br />string line = reader.ReadLine(); <br />while (line != null) { <br /> Console.WriteLine("{0}", line); <br /> line = reader.ReadLine(); <br />} <br />reader.Close(); <br />
    24. 24. Ampliando la seguridad de las aplicaciones utilizando almacenamiento aislado<br />¿Qué es el almacenamiento aislado?<br />¿Cómo gestionar archivos y carpetas en almacenamiento aislado?<br />¿Cómo leer y escribir archivos en almacenamiento aislado?<br />Muy a menudo las aplicaciones deben crear archivos temporales o de configuración de usuario, los cuales pueden contener información sensible.<br />Para pequeñas cantidades de datos que tengan un periodo de vida muy corto, podemos mantener esta información en memoria.<br />Pero no siempre es éste el mejor enfoque para ello.<br />Adicionalmente, podemos querer retener esta información entre ejecuciones de la aplicación.<br />Sin embargo, hay varios consideraciones a tener en cuenta:<br /><ul><li>La aplicación puede no tener suficientes privilegios para crear archivos en disco.
    25. 25. Si la información es confidencial, está claro que no querremos que se almacene en una ubicación genérica, a la disposición de todo el que acceda al ordenador.
    26. 26. De la misma forma, si hay varios ensamblados corriendo en le máquina, es posible que no deseemos que el resto de ensamblados puedan acceder a dicha información. Sobre todo para aquellos procesos descargados de la red.</li></ul>.NET Framework dispone del IsolatedStorage para ayudarnos a solucionar estos problemas.<br />Gestión de archivos y Serialización<br />
    27. 27. ¿Qué es el almacenamiento aislado?<br />Gestión de archivos y Serialización<br />Es un almacenamiento de archivos privativo de un ensamblado y completamente aislado del reservado para otros ensamblados.<br />Isolated storage<br />Los ensamblados sólo requieren el permiso IsolatedStorageFilePermission para crear y acceder al almacenamiento aislado.<br />Privilegios<br />Ámbito del almacenamiento aislado<br />Isolated storage está compuesto de almacenes gestionados en compartimientos de datos<br /><ul><li>Cada usuario tiene su propio compartimiento en Local Settings Application Data Isolated Storage
    28. 28. También hay compartimientos a nivel de máquina
    29. 29. Cada ensamblado tiene su propio almacén en un compartimiento de datos</li></ul>Diferentes ensamblados no pueden acceder fácilmente al almacén de otro.<br /><ul><li>También se pueden aislar diferentes instancias del mismo ensamblado que se ejecuten en diferentes dominios de aplicación.</li></ul>Las aplicaciones ClickOnce pueden crear almacenes a nivel de aplicación<br />
    30. 30. ¿Cómo gestionar archivos y carpetas en almacenamiento aislado?<br />Gestión de archivos y Serialización<br />La clase IsolatedStorageFile<br />Implementa un sistema de archivos en almacenamiento aislado<br />Dispone de métodos para crear y acceder un almacén de IsolatedStorage con un ámbito específico.<br />Contiene métodos para crear y gestionar archivos y carpetas en un almacén IsolatedStorage<br />CreateDirectory<br />GetStore<br />DeleteDirectory<br />GetUserStoreForAssembly<br />GetDirectoryNames<br />GetUserStoreForDomain<br />DeleteFile<br />GetUserStoreForApplication<br />GetFileNames<br />GetMachineStoreForAssembly<br />Remove<br />GetMachineStoreForDomain<br />Close<br />GetMachineStoreForApplication<br />
    31. 31. Gestión de archivos y Serialización<br />¿Cómo gestionar archivos y carpetas en almacenamiento aislado?<br />using System; <br />using System.IO; <br />using System.IO.IsolatedStorage; <br />// Crea una serie de carpetas<br />IsolatedStorageFileisolatedStorage =IsolatedStorageFile.GetUserStoreForDomain(); <br />isolatedStorage.CreateDirectory("PrivateFolder1"); <br />isolatedStorage.CreateDirectory("PrivateFolder2"); <br />isolatedStorage.CreateDirectory("PrivateFolder3"); <br />isolatedStorage.CreateDirectory("TestFolder"); <br />isolatedStorage.Close(); <br />// Lista las carpetas <br />IsolatedStorageFileisolatedStorage = IsolatedStorageFile.GetUserStoreForDomain(); <br />string[] foldernames = isolatedStorage.GetDirectoryNames("Private*"); <br />foreach (string name in foldernames) <br />{ <br /> Console.WriteLine("{0}", name); <br />} <br />isolatedStorage.Close(); <br />// la salida debería parecerse a esto<br />PrivateFolder1 <br />PrivateFolder2 <br />PrivateFolder3 <br />
    32. 32. ¿Cómo leer y escribir archivos en almacenamiento aislado?<br />Gestión de archivos y Serialización<br />La clase IsolatedStorageFileStream<br />Es una clase FileStream para crear, leer y escribir archivos en IsolatedStorage<br />Se utiliza con objetos Binary / StreamReadery Binary / StreamWriter para leer y escribir datos de texto y binarios<br />Se utiliza con objetos DeflateStreamo GZipStream y CryptoStream para comprimir y encriptar datos<br />Read binary/text data<br />Binary/StreamReader<br />IsolatedStorageFileStream<br />Write binary/text data<br />Binary/StreamWriter<br />
    33. 33. Gestión de archivos y Serialización<br />¿Cómo leer y escribir archivos en almacenamiento aislado?<br />using System;<br />using System.IO;<br />using System.IO.IsolatedStorage;<br />// Crea un archivo en almacenamiento aislado<br />string[] data = new string[] { "Private", "User", "Data" };<br />IsolatedStorageFile isolatedStorage = IsolatedStorageFile.GetUserStoreForDomain();<br />isolatedStorage.CreateDirectory("Demodata");<br />IsolatedStorageFileStream fileStream = new<br />IsolatedStorageFileStream(@"DemodataPrivate.txt", FileMode.Create,<br />FileAccess.Write, isolatedStorage);<br />StreamWriter writer = new StreamWriter(fileStream);<br />foreach (string item in data) {<br />writer.WriteLine(item);<br />}<br />writer.Close();<br />isolatedStorage.Close();<br />// Lee el archivo<br />IsolatedStorageFile isolatedStorage = IsolatedStorageFile.GetUserStoreForDomain();<br />IsolatedStorageFileStream fileStream = new<br />IsolatedStorageFileStream(@"DemodataPrivate.txt", FileMode.Open,<br />FileAccess.Read, isolatedStorage);<br />StreamReader reader = new StreamReader(fileStream);<br />string line = reader.ReadLine();<br />while (line != null) {<br />Console.WriteLine("{0}", line);<br />line = reader.ReadLine();<br />}<br />reader.Close();<br />isolatedStorage.Close();<br />The output of this code resembles the following example when it is run on the LON-DEV-05 virtual machine. <br />Private <br />User <br />Data <br />
    34. 34. Serialización y Deserialización<br />Serialización y deserialización de objetos mediante serialización en tiempo de ejecución<br />Personalización de los procesos de serialización y deserialización<br />Serialización y deserialización de objetos como datos XML<br />Las clasesStreamReader, StreamWriter, BinaryReader y BinaryWriter de la BCL nos permiten construir aplicaciones que pueden leer y escribir texto y tipos primitivos de datos utilizando Streams.<br />Sin embargo, en muchos casos es necesario leer y escribir estructuras de datos definidas por nuestras propias clases y estructuras.<br />Además, es posible que deseemos emitir estos datos en un formato diferente al de la codificación estándar que implementen dichas clases, por ejemplo en XML.<br />El proceso de convertir objetos en un formato que pueda ser escrito en un Stream se llama serialización.<br />Y el proceso inverso de conversión desde un Stream a objetos se llama deserialización.<br />Gestión de archivos y Serialización<br />
    35. 35. Serialización y Deserialización de objetos utilizando Runtime Serialization<br />El proceso de serialización<br />Cómo definir un tipo serializable.<br />El proceso de deserialización<br />Como serializa y deserializa los tipos complejos y las colecciones .NET<br />Cuando serializamos un objeto, éste es convertido en una serie de bytes, que después se envían a un Stream.<br />El cuál puede apuntar a un almacenamiento persistente, a una dirección de red o hacia algún otro destino.<br />Gestión de archivos y Serialización<br />
    36. 36. El proceso de serialización<br />Gestión de archivos y Serialización<br />El proceso de convertir un objeto en una serie de bytes<br />Serialización<br />Serialización en tiempo de ejecución<br />Las clases BinaryFormatter(.NET) y SoapFormatter controlan el formato e serialización(Espacios de nombres System.Runtime.Serialization.Formatters.Binary y System.Runtime.Serialization.Formatters.Soap)<br /><ul><li>Ambos implementan el interfaz IFormatter</li></ul>Los objetos a serializar: <br /><ul><li>Deben ser instancias de clases serializables
    37. 37. Pueden implementar el interfaz ISerializable</li></ul>GetObjectData<br />Serialize<br />Binary<br />Deserialize<br />Serialize<br />SOAP<br />Objeto<br />serializable<br />Deserialize<br />
    38. 38. Gestión de archivos y Serialización<br />El proceso de serialización<br />using System.Runtime.Serialization.Formatters.Soap;<br />using System.IO;<br />string message = "The cost of product 99 is:";<br />decimal price = 149.99M;<br />using (FileStream fileStream = new FileStream(@"E:DemocodeSoapData.txt",FileMode.OpenOrCreate, FileAccess.Write))<br />{<br />SoapFormatter soapFormatter = new SoapFormatter();<br />soapFormatter.Serialize(fileStream, message);<br />soapFormatter.Serialize(fileStream, price);<br />soapFormatter.Serialize(fileStream, String.Format("{0} {1}", message, price));<br />fileStream.Close();<br />}<br /><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"<br /> xmlns:SOAPENC=“http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAPENV=“http://schemas.xmlsoap.org/soap/envelope/” <br />xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><br /><SOAP-ENV:Body><br /><SOAP-ENC:string id="ref-1">The cost of product 99 is:</SOAP-ENC:string><br /></SOAP-ENV:Body><br /></SOAP-ENV:Envelope><br /><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd="http://www.w3.org/2001/XMLSchema" <br />xmlns:SOAPENC=“http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAPENV=http://schemas.xmlsoap.org/soap/envelope/<br />xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><br /><SOAP-ENV:Body><br /><xsd:decimal id="ref-1"><br /><flags>131072</flags><br /><hi>0</hi><br /><lo>14999</lo><br /><mid>0</mid><br /></xsd:decimal><br /></SOAP-ENV:Body><br /></SOAP-ENV:Envelope><br /><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance”xmlns:xsd="http://www.w3.org/2001/XMLSchema" <br />xmlns:SOAPENC=“http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAPENV=“http://schemas.xmlsoap.org/soap/envelope/"<br />xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><br /><SOAP-ENV:Body><br /><SOAP-ENC:string id="ref-1">The cost of product 99 is: 149.99</SOAP-ENC:string><br /></SOAP-ENV:Body><br /></SOAP-ENV:Envelope><br />
    39. 39. ¿Cómo definir un tipo serializable?<br />Gestión de archivos y Serialización<br />Aquél marcado con el atributo System.SerializableAttribute<br />Tipo serializable<br />Tipos serializables<br />Todos los campos de instancia se serializan (no static/shared):<br /><ul><li>Public and private</li></ul>Para omitir un campo hay que marcarlo con el atributo NonSerializedAttribute<br />Los tipos de clases base también han de ser serializables<br />Serializable<br />BankCustomer<br />Serializable<br />FirstName<br />Person<br />LastName<br />NonSerialized<br />password<br />NonSerialized<br />creditCardPin<br />bankAccountNumber<br />
    40. 40. Gestión de archivos y Serialización<br />¿Cómo definir un tipo serializable?<br />using System.Runtime.Serialization.Formatters.Soap;<br />using System.IO;<br />using System;<br />...<br />[Serializable]<br />class Data<br />{<br />privatestring privateData = "This is private data";<br />public string publicData = "This is public data";<br />[NonSerialized]<br />private string otherPrivateData = " This data will not be serialized"<br />}<br />...<br />Data data = new Data();<br />using (FileStream fileStream = new FileStream(@"E:DemocodeSoapData.txt",FileMode.OpenOrCreate, FileAccess.Write))<br />{<br />SoapFormatter soapFormatter = new SoapFormatter();<br />soapFormatter.Serialize(fileStream, data);<br />fileStream.Close();<br />}<br /><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd="http://www.w3.<br />org/2001/XMLSchema" xmlns:SOAPENC=“http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAPENV=<br />“http://schemas.xmlsoap.org/soap/envelope/”xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" <br />SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><br /> <SOAP-ENV:Body><br /> <a1:Data id="ref-1”xmlns:a1="http://schemas.microsoft.com/clr/nsassem/SerializationVB/<br /> SerializationVB%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull"><br /> <privateData id="ref-3">This is private data</privateData><br /> <publicData id="ref-4">This is public data</publicData><br /> </a1:Data><br /> </SOAP-ENV:Body><br /></SOAP-ENV:Envelope><br />
    41. 41. El proceso de deserialización<br />Gestión de archivos y Serialización<br />El proceso de construir un objeto a partir de una serie de bytes<br />Deserialización<br />Deserializando datos<br />Llamar al método Deserialize del objeto formatter<br />Asegurarse de que la información del tipo en el stream de serialización es compatible con la versión del objeto en deserialización<br />Utilizar el atributo OptionalFieldAttribute o un binder para solventar los problemas de versiones<br />Deserialize<br />AccountData<br />AccountNumber<br />OptionalField<br />DateOpened<br />Binder<br />Balance<br />Formatter<br />
    42. 42. Como serializa y deserializa .NET los tipos complejos y las colecciones<br />Gestión de archivos y Serialización<br />Serializando y deserializando dependencias<br />Person<br />Formattergenera Ids de referencia<br />El Stream de serialización referencia los objetos mediante esos Ids<br />Formatterutiliza ObjectManager para resolver las dependencias de objetos en la deserialización<br />Y ejecuta inicializaciones adicionales implementando el interfaz IDeserializationCallback<br />Name [string]<br />Father [Person]<br />Mother [Person]<br />Name: Francesca<br />3<br />Father: John<br />Mother: Diana<br />Serialize<br />Ref: 1 <br />Name: John<br />Ref: 2<br />Name: Diana<br />Ref: 3<br />Name: Francesca<br />Father: 1<br />Mother: 2<br />Name: John<br />1<br />Formatter<br />Object<br />Manager<br />2<br />Name: Diana<br />Deserialize<br />
    43. 43. Gestión de archivos y Serialización<br />Como serializa y deserializa .NET los tipos complejos y las colecciones<br /><Serializable()> Class Person<br />Public Name As String<br />Public Father As Person<br />Public Mother As Person<br />End Class<br />Dim mum As New Person()<br />mum.Name = "Diana"<br />Dim dad As New Person()<br />dad.Name = "John"<br />Dim daughter As New Person()<br />daughter.Name = "Francesca"<br />daughter.Mother = mum<br />daughter.Father = dad<br />Using serializationStream AsNew FileStream("E:Democodedaughter.txt", FileMode.Create, FileAccess.Write)<br />Dim soapWriter As New SoapFormatter()<br />soapWriter.Serialize(serializationStream, daughter)<br />serializationStream.Close()<br />End Using<br /><SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance”xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:<br />SOAPENC=“http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAPENV=“http://schemas.xmlsoap.org/soap/envelope/”xmlns:clr="http://<br />schemas.microsoft.com/soap/encoding/clr/1.0" SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><br /><SOAP-ENV:Body><br /><a1:Person id="ref-1”xmlns:a1="http://schemas.microsoft.com/clr/nsassem/Serialization/Serialization%2C%20Version%3D1.0.0.0<br />%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull"><br /><Name id="ref-3">Francesca</Name><br /><Father href="#ref-4"/><br /><Mother href="#ref-5"/><br /></a1:Person><br /><a1:Person id="ref-4”xmlns:a1="http://schemas.microsoft.com/clr/nsassem/Serialization/Serialization%2C%20Version%3D1.0.0.0<br />%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull"><br /><Name id="ref-6">John</Name><br /><Father xsi:null="1"/><br /><Mother xsi:null="1"/><br /></a1:Person><br /><a1:Person id="ref-5”xmlns:a1="http://schemas.microsoft.com/clr/nsassem/Serialization/Serialization%2C%20Version%3D1.0.0.0<br />%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull"><br /><Name id="ref-7">Diana</Name><br /><Father xsi:null="1"/><br /><Mother xsi:null="1"/><br /></a1:Person><br /></SOAP-ENV:Body><br /></SOAP-ENV:Envelope><br />
    44. 44. Personalización de la serialización en tiempo de ejecución<br />Personalizando el proceso de serialización<br />Personalizando el proceso de deserialización<br />Implementación de la clase Custom Formatter<br />Gestión de archivos y Serialización<br />
    45. 45. Personalizando el proceso de serialización<br />Gestión de archivos y Serialización<br />Interfaz ISerializable <br />Implementa el método GetObjectData<br />Alimenta el parámetro SerializationInfo al ser llamado con el método Serialize<br />Eventos de serialización<br />Utiliza el atributo OnSerializingAttribute para marcar un método que se ejecuta antes de que comience la serialización<br />Utiliza el atributo OnSerializedAttribute para marcar un método que se ejecuta cuando la serialización se ha completado<br />Serialize<br />CustomClass<br />GetObjectData<br />OnSerializing<br />Serializing<br />SerializationInfo<br />OnSerialized<br />Serialized<br />Formatter<br />
    46. 46. Personalizando el proceso de deserialización<br />Gestión de archivos y Serialización<br />Requerimientos de una clase personalizada<br />Requiere un constructor de deserialización<br />Alimentar el objeto con los datos del parámetro SerializationInfo<br />Eventos de deserialización<br />Utilizar el atributo OnDeserializingAttribute para marcar un método para que se ejecute antes de que comience la deserialización<br />Y OnDeserializedAttribute para otro método cuando se haya completado<br />CustomClass<br />Deserialize<br />SerializationInfo<br />Deserialization Constructor<br />Deserializing<br />OnDeserializing<br />Deserialized<br />OnDeserialized<br />Formatter<br />
    47. 47. Implementación de la clase Custom Formatter<br />Gestión de archivos y Serialización<br />Implementar IFormatter.Serialize<br />Si el objeto implementa ISerializable, llamar GetObjectData<br />Utilizar la clase de apoyo FormatterServices para recuperar los miembros a serializar<br />Escribir los metadatos del objetos y sus datos al Stream de serialización<br />Utilizar la clase de apoyo SerializationObjectManager para lanzar los eventos de serialización<br />Implementar IFormatter.Deserialize<br />Leer el Stream de serialización y extraer los metadatos y datos<br />Utilizar la clase de apoyo FormatterServices para crear una instancia vacía del objeto<br />Si el objeto dispone de un constructor de deserialización, llamarlo para alimentar al objeto, en caso contrario, cumplimentar la información en el método Deserialize<br />Utilizar un objeto ObjectManager para gestionar las referencias y lanzar los eventos<br />
    48. 48. Serialización y deserialización de objetos como datos XML<br />Cómo serializar un objeto como XML<br />Como la clase XmlSerializer serializa datos complejos<br />Como especificar definición de tipos XML y espacios de nombres<br />Como controlar la serialización XML para un tipo<br />Personalización del proceso de serialización XML<br />Como deserializar un objeto desde un Stream XML<br />Gestión de archivos y Serialización<br />
    49. 49. Cómo serializar un objeto como XML<br />Gestión de archivos y Serialización<br />Uso de la clase XmlSerializer <br />Crear un objeto XmlSerializer y especificar el tipo de objeto a serializar<br />Llamar al método Serialize y enviar los datos a un objeto Stream, TextWritero XmlWriter<br />Requerimientos de un tipo serializable<br />Debe ser un tipo público<br />No necesita el atributo Serializable<br />Debe disponer de un constructor por defecto público (para deserializar)<br />Debe tener acceso público a los campos y propiedades que contiene los datos a serializar<br />Serializable<br /><?xml version="1.0"><br /><BankCustomer xmlns:xsi="... " ><br /> <CustomerName>Fred</CustomerName><br /></BankCustomer><br />Public BankCustomer<br />BankCustomer()<br />CustomerName<br />creditCardPin<br />
    50. 50. Gestión de archivos y Serialización<br />Cómo serializar un objeto como XML<br />using System.Xml.Serialization;<br />publicclass OrderInfo<br />{<br />public string OrderId;<br />public DateTime OrderDate;<br />public decimal Cost;<br />internal int ProfitPercent = 75;<br />}<br />...<br />OrderInfo order = new OrderInfo();<br />order.OrderId = "Order1";<br />order.OrderDate = DateTime.Now;<br />order.Cost = 10.99M;<br />XmlSerializer serializer = new XmlSerializer(typeof(OrderInfo));<br />FileStream xmlStream = new FileStream(@"E:Democodeorder.xml", FileMode.Create, <br /> FileAccess.Write);<br />serializer.Serialize(xmlStream, order);<br />xmlStream.Close();<br /><?xml version="1.0"?><br /><OrderInfo xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance<br /> xmlns:xsd="http://www.w3.org/2001/XMLSchema"><br /><OrderId>Order1</OrderId><br /><Orderdate>2008-04-01T09:39:13.9010496-08:00</Orderdate><br /><Cost>10.99</Cost><br /></OrderInfo><br />
    51. 51. Cómo serializa datos complejos la clase XmlSerializer<br />Gestión de archivos y Serialización<br />Serialización de objetos complejos<br />El formato XML representa las relaciones entre objetos como una estructura jerárquica de datos.<br />Múltiples referencias generan datos duplicados.<br />Serialización de colecciones de objetos<br />Hay que especificar el tipo de los objetos de la colección al crear el objeto XmlSerializer desde el espacio de nombres System.Xml.Serialization<br /><?xml version="1.0"?><br /><ArrayOfAnyType xmlns:xsi=“..."><br /> <anyType xsi:type="Person"><br /> <Name>Diana</Name><br /> <Id>2</Id><br /> </anyType><br /> <anyType xsi:type="Person"><br /> <Name>John</Name><br /> <Id>1</Id><br /> </anyType><br /> <anyType xsi:type="Person"><br /> <Name>Francesca</Name><br /> <Id>3</Id><br /> <Father><br /> <Name>John</Name><br /> <Id>2</Id><br /> </Father><br /> <Mother><br /> <Name>Diana</Name><br /> <Id>1</Id><br /> </Mother><br /> </anyType><br /></ArrayOfAnyType><br /><?xml version="1.0"?><Person xmlns:xsi="... " > <Name>Francesca</Name> <Id>3</Id> <Father> <Name>John</Name> <Id>1</Id> </Father> <Mother><br /> <Name>Diana</Name> <Id>2</Id> </Mother><br /></Person><br />
    52. 52. Como especificar definición de tipos XML y espacios de nombres<br />Gestión de archivos y Serialización<br />Atributo que cambia la definición del tipo de una clase cuando se serializa como XML<br />XmlType<br />Propiedades comunes de XmlType<br />TypeName<br />Namespace<br />Person<br />XmlType(TypeName:="FamilyMember")<br />XmlType(TypeName:="FamilyMember", Namespace:="http://adventure-works.com/personnel")<br />Name<br />Id<br /><?xml version="1.0"?><br /><Person xmlns:xsi="..."><br /> <Name>John</Name><br /> <Id>2</Id><br /></FamilyMember><br /><?xml version="1.0"?><br /><FamilyMember xmlns:xsi="..."><br /> <Name>John</Name><br /> <Id>2</Id><br /></FamilyMember><br /><?xml version="1.0"?><br /><FamilyMember xmlns:xsi="..."><br /> <Name xmlns="http://adventure-works.com/personnel">John</Name><br /> <Id xmlns="http://adventure-works.com/personnel">2</Id><br /></FamilyMember><br />
    53. 53. Como controlar la serialización XML para un tipo<br />Gestión de archivos y Serialización<br />Atributos XML<br />Atributos para campos, propiedades, parámetros de métodos y valores de retorno<br />Atributos para tipos<br />XmlArrayAttribute<br />XmlEnumAttribute<br />XmlAttributeAttribute<br />XmlArrayItemAttribute<br />XmlIgnoreAttribute<br />XmlElementAttribute<br />XmlTextAttribute<br />XmlRootAttribute<br />XmlIncludeAttribute<br />
    54. 54. Como personalizar el proceso de serialización XML<br />Gestión de archivos y Serialización<br />Interfaz IXmlSerializable<br />Implementa el método WriteXml con un único parámetro XmlWriter<br />Escribe XML correctamente formateado mediante los métodos del XmlWriter<br />Public BankCustomer<br />BankCustomer()<br />WriteXml(XmlWriter)<br />CustomerName<br />creditCardPin<br />creditCardPin<br /><?xml version="1.0"><br /><BankCustomer xmlns:xsi="... " ><br /> <CustomerName>Fred</CustomerName><br /><encryptedPin>&^@:%&JA</encryptedPin><br /></BankCustomer><br />
    55. 55. Como deserializar un objeto desde un Stream XML<br />Gestión de archivos y Serialización<br />Uso de la clase XmlSerializer<br />Crear un objeto XmlSerializer y especificar el tipo de objeto a serializar.<br />Llamar al método Deserializey leer datos desde un objeto Stream, TextReader o XmlReader:<br /><ul><li>Generar el objeto llamando al constructor por defecto
    56. 56. Informar sólo los miembros públicos, utilizando los valores leídos de los datos serializados.</li></ul>Asegurarse de que los tipos deserializados corresponden al esquema de los datos serializados.<br />Gestionar los eventos de deserialización para manejar los datos inesperados.<br />Implementar el método ReadXml del interfaz IXmlSerializable para personalizar el proceso de deserialización XML.<br />

    ×