Acceso al sistema de archivos en Xamarin.iOS

Download SampleDescargar el ejemplo

Puede usar Xamarin.iOS y las System.IO clases de la biblioteca de clases base (BCL) de .NET para acceder al sistema de archivos iOS. La clase File le permite crear, eliminar y leer archivos, mientras que la clase Directory le permite crear, eliminar o enumerar el contenido de directorios. También puede usar Stream subclases, que pueden proporcionar un mayor grado de control sobre las operaciones de archivo (como la compresión o la búsqueda de posición dentro de un archivo).

iOS impone algunas restricciones sobre lo que una aplicación puede hacer con el sistema de archivos para conservar la seguridad de los datos de una aplicación y para proteger a los usuarios de aplicaciones malintables. Estas restricciones forman parte del espacio aislado de aplicaciones: un conjunto de reglas que limita el acceso de una aplicación a archivos, preferencias, recursos de red, hardware, etc. Una aplicación se limita a leer y escribir archivos dentro de su directorio principal (ubicación instalada); no puede acceder a los archivos de otra aplicación.

iOS también tiene algunas características específicas del sistema de archivos: ciertos directorios requieren un tratamiento especial con respecto a las copias de seguridad y las actualizaciones, y las aplicaciones también pueden compartir archivos entre sí y la aplicación Archivos (desde iOS 11) y a través de iTunes.

En este artículo se describen las características y restricciones del sistema de archivos de iOS e incluye una aplicación de ejemplo que muestra cómo usar Xamarin.iOS para ejecutar algunas operaciones sencillas del sistema de archivos:

A sample of iOS executing some simple file system operations

Acceso general a archivos

Xamarin.iOS permite usar las clases de .NET System.IO para las operaciones del sistema de archivos en iOS.

En los fragmentos de código siguientes se muestran algunas operaciones de archivo comunes. Los encontrarás a continuación en el archivo SampleCode.cs , en la aplicación de ejemplo de este artículo.

Trabajar con directorios

Este código enumera los subdirectorios del directorio actual (especificado por el parámetro "./"), que es la ubicación del ejecutable de la aplicación. La salida será una lista de todos los archivos y carpetas que se implementan con la aplicación (que se muestran en la ventana de la consola mientras se depura).

var directories = Directory.EnumerateDirectories("./");
foreach (var directory in directories) {
      Console.WriteLine(directory);
}

Lectura de archivos

Para leer un archivo de texto, solo necesita una sola línea de código. En este ejemplo se mostrará el contenido de un archivo de texto en la ventana Salida de la aplicación.

var text = File.ReadAllText("TestData/ReadMe.txt");
Console.WriteLine(text);

serialización XML

Aunque trabajar con el espacio de nombres completo System.Xml está fuera del ámbito de este artículo, puede deserializar fácilmente un documento XML desde el sistema de archivos mediante streamReader como este fragmento de código:

using (TextReader reader = new StreamReader("./TestData/test.xml")) {
      XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
      var xml = (MyObject)serializer.Deserialize(reader);
}

Para obtener más información, consulte la documentación de System.Xml y serialización. Consulte la documentación de Xamarin.iOS en el enlazador; a menudo, tendrá que agregar el [Preserve] atributo a las clases que pretende serializar.

Creación de archivos y directorios

En este ejemplo se muestra cómo usar la Environment clase para acceder a la carpeta Documentos donde podemos crear archivos y directorios.

var documents =
 Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments); 
var filename = Path.Combine (documents, "Write.txt");
File.WriteAllText(filename, "Write this text into a file");

La creación de un directorio es un proceso similar:

var documents =
 Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var directoryname = Path.Combine (documents, "NewDirectory");
Directory.CreateDirectory(directoryname);

Para obtener más información, consulte la referencia de api de System.IO.

Serialización de JSON

Json.NET es un marco JSON de alto rendimiento que funciona con Xamarin.iOS y está disponible en NuGet. Agregue el paquete NuGet al proyecto de aplicación mediante Agregar NuGet en Visual Studio para Mac:

Adding the NuGet package to the applications project

A continuación, agregue una clase para que actúe como modelo de datos para la serialización o deserialización (en este caso Account.cs):

using System;
using System.Collections.Generic;
using Foundation; // for Preserve attribute, which helps serialization with Linking enabled

namespace FileSystem
{
    [Preserve]
    public class Account
    {
        public string Email { get; set; }
        public bool Active { get; set; }
        public DateTime CreatedDate { get; set; }
        public List<string> Roles { get; set; }

        public Account() {
        }
    }
}

Por último, cree una instancia de la Account clase , serialícela en datos json y escríbala en un archivo:

// Create a new record
var account = new Account(){
    Email = "monkey@xamarin.com",
    Active = true,
    CreatedDate = new DateTime(2015, 5, 27, 0, 0, 0, DateTimeKind.Utc),
    Roles = new List<string> {"User", "Admin"}
};

// Serialize object
var json = JsonConvert.SerializeObject(account, Newtonsoft.Json.Formatting.Indented);

// Save to file
var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var filename = Path.Combine (documents, "account.json");
File.WriteAllText(filename, json);

Para obtener más información sobre cómo trabajar con datos json en una aplicación .NET, consulte la documentación de Json.NET.

Consideraciones especiales

A pesar de las similitudes entre las operaciones de archivos de Xamarin.iOS y .NET, iOS y Xamarin.iOS difieren de .NET de algunas maneras importantes.

Hacer que los archivos de proyecto sean accesibles en tiempo de ejecución

De forma predeterminada, si agrega un archivo al proyecto, no se incluirá en el ensamblado final y, por tanto, no estará disponible para la aplicación. Para incluir un archivo en el ensamblado, debe marcarlo con una acción de compilación especial, denominada Contenido.

Para marcar un archivo para su inclusión, haga clic con el botón derecho en los archivos y elija Contenido de acción > de compilación en Visual Studio para Mac. También puede cambiar la acción de compilación en la hoja Propiedades del archivo.

Distinción entre mayúsculas y minúsculas

Es importante comprender que el sistema de archivos de iOS distingue mayúsculas de minúsculas. La distinción entre mayúsculas y minúsculas significa que los nombres de archivo y directorio deben coincidir exactamente: README.txt y readme.txt se considerarían nombres de archivo diferentes.

Esto podría resultar confuso para los desarrolladores de .NET que están más familiarizados con el sistema de archivos de Windows, que no distingue mayúsculas de minúsculas : los archivos, los archivos y los archivos harían referencia al mismo directorio.

Advertencia

El simulador de iOS no distingue mayúsculas de minúsculas. Si el uso de mayúsculas y minúsculas de nombre de archivo difiere entre el propio archivo y las referencias a él en el código, es posible que el código siga funcionando en el simulador, pero se producirá un error en un dispositivo real. Esta es una de las razones por las que es importante implementar y probar en un dispositivo real al principio y a menudo durante el desarrollo de iOS.

Separador de ruta de acceso

iOS usa la barra diagonal '/' como separador de ruta de acceso (que es diferente de Windows, que usa la barra diagonal inversa '\').

Debido a esta diferencia confusa, se recomienda usar el System.IO.Path.Combine método , que se ajusta para la plataforma actual, en lugar de codificar de forma dura un separador de ruta de acceso determinado. Este es un paso sencillo que hace que el código sea más portátil para otras plataformas.

Espacio aislado de aplicaciones

El acceso de la aplicación al sistema de archivos (y otros recursos, como las características de red y hardware) está limitado por motivos de seguridad. Esta restricción se conoce como espacio aislado de aplicaciones. En términos del sistema de archivos, la aplicación se limita a crear y eliminar archivos y directorios en su directorio principal.

El directorio principal es una ubicación única en el sistema de archivos donde se almacenan la aplicación y todos sus datos. No puede elegir (ni cambiar) la ubicación del directorio principal de la aplicación; sin embargo, iOS y Xamarin.iOS proporcionan propiedades y métodos para administrar los archivos y directorios dentro.

La agrupación de aplicaciones

El paquete de aplicaciones es la carpeta que contiene la aplicación. Se distingue de otras carpetas al tener el sufijo .app agregado al nombre del directorio. La agrupación de aplicaciones contiene el archivo ejecutable y todo el contenido (archivos, imágenes, etc.) necesarios para el proyecto.

Cuando navega a la agrupación de aplicaciones en Mac OS, aparece con un icono diferente al que ve en otros directorios (y el sufijo .app está oculto); sin embargo, es solo un directorio normal que el sistema operativo muestra de forma diferente.

Para ver la agrupación de aplicaciones para el código de ejemplo, haga clic con el botón derecho en el proyecto en Visual Studio para Mac y seleccione Mostrar en Finder. A continuación, vaya al directorio bin/ donde debe encontrar un icono de aplicación (similar a la captura de pantalla siguiente).

Navigate through the bin directory to find an application icon similar to this screenshot

Haga clic con el botón derecho en este icono y elija Mostrar contenido del paquete para examinar el contenido del directorio Paquete de aplicaciones. El contenido aparece igual que el contenido de un directorio regular, como se muestra aquí:

The contents of the app bundle

La agrupación de aplicaciones es lo que se instala en el simulador o en el dispositivo durante las pruebas y, en última instancia, es lo que se envía a Apple para su inclusión en app Store.

Directorios de aplicaciones

Cuando la aplicación se instala en un dispositivo, el sistema operativo crea un directorio principal para la aplicación y crea un número de directorios dentro del directorio raíz de la aplicación que están disponibles para su uso. Desde iOS 8, los directorios accesibles para el usuario NO se encuentran dentro de la raíz de la aplicación, por lo que no puede derivar las rutas de acceso para la agrupación de aplicaciones de los directorios de usuario o viceversa.

Estos directorios, cómo determinar su ruta de acceso y sus propósitos se enumeran a continuación:

 

Directorio Descripción
[ApplicationName].app/ En iOS 7 y versiones anteriores, este es el ApplicationBundle directorio donde se almacena el ejecutable de la aplicación. La estructura de directorios que crea en la aplicación existe en este directorio (por ejemplo, imágenes y otros tipos de archivo que ha marcado como Recursos en el proyecto de Visual Studio para Mac).

Si necesita acceder a los archivos de contenido dentro de la agrupación de aplicaciones, la ruta de acceso a este directorio está disponible a través de la NSBundle.MainBundle.BundlePath propiedad .
Documentos/ Use este directorio para almacenar documentos de usuario y archivos de datos de la aplicación.

El contenido de este directorio se puede poner a disposición del usuario a través del uso compartido de archivos de iTunes (aunque esto está deshabilitado de forma predeterminada). Agregue una UIFileSharingEnabled clave booleana al archivo Info.plist para permitir que los usuarios accedan a estos archivos.

Incluso si una aplicación no habilita inmediatamente el uso compartido de archivos, debe evitar colocar archivos que deben ocultarse a los usuarios de este directorio (como archivos de base de datos, a menos que quiera compartirlos). Siempre que los archivos confidenciales permanezcan ocultos, estos archivos no se exponen (y potencialmente se mueven, modifican o eliminan por iTunes) si el uso compartido de archivos está habilitado en una versión futura.

Puede usar el Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments) método para obtener la ruta de acceso al directorio Documentos de la aplicación.

ITunes realiza una copia de seguridad del contenido de este directorio.
Biblioteca/ El directorio Biblioteca es un buen lugar para almacenar archivos que el usuario no crea directamente, como bases de datos u otros archivos generados por la aplicación. El contenido de este directorio nunca se expone al usuario a través de iTunes.

Puede crear sus propios subdirectorios en Biblioteca; sin embargo, ya hay algunos directorios creados por el sistema que debe tener en cuenta, incluidas las preferencias y las cachés.

ITunes realiza una copia de seguridad del contenido de este directorio (excepto el subdirectorio Caches). Se realizará una copia de seguridad de los directorios personalizados que cree en biblioteca.
Biblioteca/Preferencias/ Los archivos de preferencias específicos de la aplicación se almacenan en este directorio. No cree estos archivos directamente. En su lugar, use la NSUserDefaults clase .

ITunes realiza una copia de seguridad del contenido de este directorio.
Biblioteca/cachés/ El directorio Caches es un buen lugar para almacenar archivos de datos que pueden ayudar a la ejecución de la aplicación, pero que se pueden volver a crear fácilmente. La aplicación debe crear y eliminar estos archivos según sea necesario y poder volver a crear estos archivos si es necesario. iOS 5 también puede eliminar estos archivos (en situaciones de almacenamiento bajo), pero no lo hará mientras se ejecuta la aplicación.

ITunes no realiza una copia de seguridad del contenido de este directorio, lo que significa que no estarán presentes si el usuario restaura un dispositivo y es posible que no estén presentes después de instalar una versión actualizada de la aplicación.

Por ejemplo, en caso de que la aplicación no pueda conectarse a la red, puede usar el directorio Caches para almacenar datos o archivos para proporcionar una buena experiencia sin conexión. La aplicación puede guardar y recuperar estos datos rápidamente mientras espera respuestas de red, pero no es necesario realizar copias de seguridad y se puede recuperar o volver a crear fácilmente después de una restauración o actualización de versión.
Tmp/ Las aplicaciones pueden almacenar archivos temporales que solo son necesarios durante un breve período en este directorio. Para ahorrar espacio, los archivos deben eliminarse cuando ya no sean necesarios. El sistema operativo también puede eliminar archivos de este directorio cuando una aplicación no se está ejecutando.

ITunes no realiza una copia de seguridad del contenido de este directorio.

Por ejemplo, el directorio tmp puede usarse para almacenar archivos temporales que se descargan para mostrar al usuario (como avatares de Twitter o datos adjuntos de correo electrónico), pero que se podrían eliminar una vez que se hayan visto (y descargado de nuevo si son necesarios en el futuro).

En esta captura de pantalla se muestra la estructura de directorios en una ventana del buscador:

This screenshot shows the directory structure in a Finder window

Acceso a otros directorios mediante programación

Los ejemplos de archivos y directorios anteriores a los que se ha accedido al Documents directorio. Para escribir en otro directorio, debe construir una ruta de acceso mediante la sintaxis ".." como se muestra aquí:

var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var library = Path.Combine (documents, "..", "Library");
var filename = Path.Combine (library, "WriteToLibrary.txt");
File.WriteAllText(filename, "Write this text into a file in Library");

La creación de un directorio es similar:

var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var library = Path.Combine (documents, "..", "Library");
var directoryname = Path.Combine (library, "NewLibraryDirectory");
Directory.CreateDirectory(directoryname);

Las rutas de acceso a los Caches directorios y tmp se pueden construir de la siguiente manera:

var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var cache = Path.Combine (documents, "..", "Library", "Caches");
var tmp = Path.Combine (documents, "..", "tmp");

Uso compartido con la aplicación Archivos

iOS 11 introdujo la aplicación Files : un explorador de archivos para iOS que permite al usuario ver e interactuar con sus archivos en iCloud y también almacenados por cualquier aplicación que lo admita. Para permitir que el usuario acceda directamente a los archivos de la aplicación, cree una nueva clave booleana en el archivo LSSupportsOpeningDocumentsInPlace Info.plist y establézcalo trueen , como aquí:

Set LSSupportsOpeningDocumentsInPlace in Info.plist

El directorio Documentos de la aplicación ahora estará disponible para navegar en la aplicación Archivos. En la aplicación Archivos, vaya a On My i Teléfono (En mi i Teléfono y cada aplicación con archivos compartidos estará visible. Las capturas de pantalla siguientes muestran el aspecto de la aplicación de ejemplo FileSystem:

iOS 11 Files appBrowse my iPhone filesSample app files

Uso compartido de archivos con el usuario a través de iTunes

Los usuarios pueden acceder a los archivos del directorio Documentos de la aplicación editando Info.plist y creando una aplicación que admita el uso compartido de iTunes (UIFileSharingEnabled) en la vista Origen , como se muestra aquí:

Adding the Application supports iTunes sharing property

Se puede acceder a estos archivos en iTunes cuando el dispositivo está conectado y el usuario elige la Apps pestaña. Por ejemplo, en la captura de pantalla siguiente se muestran los archivos de la aplicación seleccionada compartida a través de iTunes:

This screenshot shows the files in selected app shared via iTunes

Los usuarios solo pueden acceder a los elementos de nivel superior de este directorio a través de iTunes. No pueden ver el contenido de ningún subdirectorio (aunque pueden copiarlos en su equipo o eliminarlos). Por ejemplo, con los archivos GoodReader, PDF y EPUB se pueden compartir con la aplicación para que los usuarios puedan leerlos en sus dispositivos iOS.

Los usuarios que modifican el contenido de su carpeta Documentos pueden causar problemas si no son cuidadosos. La aplicación debe tener esto en cuenta y ser resistente a las actualizaciones destructivas de la carpeta Documentos.

El código de ejemplo de este artículo crea un archivo y una carpeta en la carpeta Documentos (en SampleCode.cs) y habilita el uso compartido de archivos en el archivo Info.plist . En esta captura de pantalla se muestra cómo aparecen en iTunes:

This screenshot shows how the files appear in iTunes

Consulte el artículo Trabajar con imágenes para obtener información sobre cómo establecer iconos para la aplicación y para cualquier tipo de documento personalizado que cree.

Si la UIFileSharingEnabled clave es false o no está presente, el uso compartido de archivos es, de forma predeterminada, deshabilitada y los usuarios no podrán interactuar con el directorio Documentos.

Copia de seguridad y restauración

Cuando iTunes realiza una copia de seguridad de un dispositivo, todos los directorios creados en el directorio principal de la aplicación se guardarán excepto los directorios siguientes:

  • [ApplicationName].app : no escriba en este directorio, ya que está firmado y, por tanto, debe permanecer sin cambios después de la instalación. Puede contener recursos a los que accede desde el código, pero no requieren copia de seguridad, ya que se restaurarían al volver a descargar la aplicación.
  • Biblioteca o cachés : el directorio de caché está pensado para los archivos de trabajo que no es necesario realizar una copia de seguridad.
  • tmp : este directorio se usa para los archivos temporales que se crean y eliminan cuando ya no son necesarios, o para los archivos que iOS elimina cuando necesita espacio.

La copia de seguridad de una gran cantidad de datos puede tardar mucho tiempo. Si decide que necesita realizar una copia de seguridad de cualquier documento o datos concretos, la aplicación debe usar las carpetas Documentos y biblioteca. En el caso de los datos o archivos transitorios que se pueden recuperar fácilmente de la red, use las memorias caché o el directorio tmp.

Nota:

iOS "limpiará" el sistema de archivos cuando un dispositivo se ejecute críticamente bajo en el espacio en disco. Este proceso quitará todos los archivos de la carpeta Library/Caches y tmp de las aplicaciones que no se están ejecutando actualmente.

Cumplir con las restricciones de copia de seguridad de iOS 5 iCloud

Nota:

Aunque esta directiva se introdujo por primera vez con iOS 5 (que parece hace mucho tiempo), la guía sigue siendo relevante para las aplicaciones en la actualidad.

Apple introdujo la funcionalidad de copia de seguridad de iCloud con iOS 5. Cuando se habilita iCloud Backup, se realiza una copia de seguridad de todos los archivos del directorio principal de la aplicación (excepto los directorios de los que no se realiza una copia de seguridad normalmente, por ejemplo, la agrupación de aplicaciones, Cachesy tmp) en los servidores de iCloud. Esta característica proporciona al usuario una copia de seguridad completa en caso de que su dispositivo se pierda, robe o dañe.

Dado que iCloud solo proporciona 5 Gb de espacio libre a cada usuario y para evitar el uso innecesario del ancho de banda, Apple espera que las aplicaciones solo realicen copias de seguridad de los datos esenciales generados por el usuario. Para cumplir con las directrices de almacenamiento de datos de iOS, debe limitar la cantidad de datos de los que se realiza una copia de seguridad mediante la conformidad con los siguientes elementos:

  • Almacene solo los datos generados por el usuario o los datos que no se puedan volver a crear, en el directorio Documentos (que se realiza una copia de seguridad).
  • Almacene cualquier otro dato que pueda volver a crearse o volver a descargarse fácilmente en Library/Caches o tmp (que no se realiza una copia de seguridad y podría "limpiarse").
  • Si tiene archivos que podrían ser adecuados para la Library/Caches carpeta o tmp , pero no desea que se "limpie", almacénelos en otro lugar (como Library/YourData) y aplique el atributo "no hacer una copia de seguridad" para evitar que los archivos usen el ancho de banda de copia de seguridad de iCloud y el espacio de almacenamiento. Estos datos siguen usando espacio en el dispositivo, por lo que debe administrarlos cuidadosamente y eliminarlos siempre que sea posible.

El atributo "do not back up" se establece mediante la NSFileManager clase . Asegúrese de que la clase es using Foundation y llame de esta manera SetSkipBackupAttribute :

var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var filename = Path.Combine (documents, "LocalOnly.txt");
File.WriteAllText(filename, "This file will never get backed-up. It would need to be re-created after a restore or re-install");
NSFileManager.SetSkipBackupAttribute (filename, true); // backup will be skipped for this file

Cuando SetSkipBackupAttribute no true se realizará una copia de seguridad del archivo, independientemente del directorio en el que se almacene (incluso en el Documents directorio). Puede consultar el atributo mediante el GetSkipBackupAttribute método y puede restablecerlo llamando al SetSkipBackupAttribute método con false, de la siguiente manera:

NSFileManager.SetSkipBackupAttribute (filename, false); // file will be backed-up

Uso compartido de datos entre aplicaciones iOS y extensiones de aplicaciones

Dado que las extensiones de aplicación se ejecutan como parte de una aplicación host (en lugar de su aplicación contenedora), el uso compartido de datos no se incluye automáticamente, por lo que se requiere trabajo adicional. Los grupos de aplicaciones son el mecanismo que iOS usa para permitir que diferentes aplicaciones compartan datos. Si las aplicaciones se han configurado correctamente con los derechos y el aprovisionamiento correctos, pueden acceder a un directorio compartido fuera de su espacio aislado normal de iOS.

Configurar un grupo de aplicaciones

La ubicación compartida se configura mediante un grupo de aplicaciones, que se configura en la sección Certificados, Identificadores y perfiles de iOS Centro de desarrollo. También se debe hacer referencia a este valor en cada archivo Entitlements.plist del proyecto.

Para obtener información sobre cómo crear y configurar un grupo de aplicaciones, consulte la guía Funcionalidades del grupo de aplicaciones.

Archivos

La aplicación iOS y la extensión también pueden compartir archivos mediante una ruta de acceso de archivo común (dado que se han configurado correctamente con los derechos y el aprovisionamiento correctos):

var FileManager = new NSFileManager ();
var appGroupContainer =FileManager.GetContainerUrl ("group.com.xamarin.WatchSettings");
var appGroupContainerPath = appGroupContainer.Path

Console.WriteLine ("Group Path: " + appGroupContainerPath);

// use the path to create and update files
...

Importante

Si la ruta de acceso de grupo devuelta es null, compruebe la configuración de los derechos y el perfil de aprovisionamiento y asegúrese de que son correctos.

Actualizaciones de la versión de la aplicación

Cuando se descarga una nueva versión de la aplicación, iOS crea un nuevo directorio principal y almacena la nueva agrupación de aplicaciones en ella. Después, iOS mueve las siguientes carpetas de la versión anterior de la agrupación de aplicaciones al nuevo directorio principal:

  • Documentos
  • Library

Otros directorios también se pueden copiar y colocar en el nuevo directorio principal, pero no se garantiza que se copien, por lo que la aplicación no debe depender de este comportamiento del sistema.

Resumen

En este artículo se mostró que las operaciones del sistema de archivos con Xamarin.iOS son similares a cualquier otra aplicación .NET. También introdujo el espacio aislado de la aplicación y examinó las implicaciones de seguridad que provoca. A continuación, ha explorado el concepto de una agrupación de aplicaciones. Por último, enumera los directorios especializados disponibles para la aplicación y explica sus roles durante las actualizaciones y copias de seguridad de la aplicación.