Gestione di file compressi in Windows Phone con la libreria SharpZipLib

di Matteo Pagani, in Windows Phone,

Recentemente, nello sviluppo di una mia applicazione per Windows Phone, mi sono trovato nella necessità di implementare il supporto al backup dei dati della stessa su Skydrive, così da dare all'utente la possibilità di non perdere nulla anche in caso di ripristino o acquisto di un nuovo device Windows Phone. Si tratta di una procedura piuttosto semplice, grazie al rilascio da parte di Microsoft della Live SDK, una libreria che consente di interagire con tutti i principali servizi Microsoft, tra cui Skydrive (potete approfondire l'argomento in questo articolo).

Dato che, però, ci troviamo su un dispositivo mobile, ho pensato di ottimizzare al massimo l'esperienza utente, cercando di ridurre il più possibile il tempo e la banda necessari per effettuare le operazioni di backup e ripristino: per raggiungere questo obiettivo la soluzione più semplice ed efficace è stata quella di comprimere il file da salvare (nel mio caso, un file XML nel quale vengono serializzati i dati della mia applicazione).

Vediamo come gestire questo scenario, grazie all'aiuto di una libreria open source chiamata SharpZipLib.

Configurare il progetto

Esiste un porting specifico di SharpZipLib per Windows Phone che potete installare tramite NuGet: semplicemente fate click con il tasto destro sul vostro progetto in Visual Studio, scegliete la voce Manage NuGet packages e cercate e installate il pacchetto di nome SharpZipLib-WP7.

A questo punto siete pronti per iniziare a sfruttare le funzionalità di compressione offerte dalla libreria.

Comprimere un file

Partiamo dal presupposto che, all'interno dell'isolated storage della vostra applicazione, abbiate un file che volete comprimere e che si chiami data.txt (nel progetto di esempio che accompagna questo articolo è presente una funzione per copiare un file di esempio dal progetto allo storage). Il primo passo è quello di aggiungere, nel codice della nostra classe, i namespace che contengono classi e metodi della libreria, ovvero

using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;

A questo punto siano in grado di comprimere il nostro file:<pre class="brush: csharp;">private void OnCompressFileClicked(object sender, RoutedEventArgs e)
{
    using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
    {
        using (IsolatedStorageFileStream fileToCompress = storage.OpenFile("data.txt", FileMode.Open, FileAccess.Read))
        {
            using (IsolatedStorageFileStream zipFile = storage.OpenFile("CompressedFile.zip", FileMode.Create, FileAccess.ReadWrite))
            {

                ZipOutputStream file = new ZipOutputStream(zipFile);
                ZipEntry entry = new ZipEntry("data.txt");
                file.PutNextEntry(entry);
                StreamUtils.Copy(fileToCompress, file, new byte[4096]);
                file.CloseEntry();
                file.IsStreamOwner = true;
                file.Close();
            }
        }
    }
}

In questo caso utilizziamo le API di Windows Phone 7 per la gestione dello storage, così da poter riutilizzare questo codice sia all?interno di un?applicazione Windows Phone 7 che Windows Phone 8 (grazie alla retro compatibilità della piattaforma).

Sono tre i passaggi che facciamo sfruttando le API dello storage:

  • Otteniamo l'accesso allo storage vero e proprio, tramite il metodo GetUserStoreForApplication(). In questo modo ci viene restituito un oggetto di tipo IsolatedStorageFile, che ci permette di effettuare le operazioni più comuni (creare cartelle, aprire un file, ecc.).
  • Recuperiamo lo stream del file che vogliamo comprimere (il nostro data.txt): lo facciamo con il metodo OpenFile() offerto dalla classe IsolatedStorageFile, che richiede come parametri il nome del file, la modalità di apertura (in questo caso, FileMode.Open dato che dobbiamo aprire un file già esistente) e la modalità di accesso (in questo caso, FileAccess.Read, in quanto abbiamo la necessità di leggere solamente il contenuto del file). Quello che otterremo è un oggetto di tipo IsolatedStorageFileStream, che contiene il contenuto del file sotto forma di stream.
  • Creiamo, sempre nell'isolated storage, il file compresso: l'operazione è identica a quella vista in precedenza, con la differenza che adesso ci serve uno stream per la scrittura, nel quale andremo a memorizzare il file compresso. Quello che cambia perciò è il nome del file (nell'esempio, CompressedFile.zip), la modalità di apertura (FileMode.Create, dato che il file deve essere creato se non esiste) e la modalità di accesso (FileAccess.ReadWrite, in quanto dovremo scrivere all'interno di questo stream).

Tutte queste operazioni vengono inserite all'interno di un blocco using: in questo modo, una volta terminate, l'accesso ai vari stream sarà automaticamente chiuso, evitando all'applicazione di bloccare e consumare risorse non necessarie. Quello che abbiamo a disposizione, quindi, sono due stream: uno già pieno, con il contenuto del file da comprimere, e uno vuoto, che invece andremo a "riempire" con i dati compressi. A questo punto entrano in gioco le API offerte dalla libreria SharpZipLib: creiamo un nuovo oggetto di tipo ZipOutputStream, che rappresenta il nostro file compresso. Nel costruttore, infatti, dobbiamo passare come parametro lo stream di scrittura (il secondo che abbiamo creato, di nome zipFile). Un file compresso può contenere, al suo interno, più file: ognuno di essi è rappresentato da un oggetto di tipo ZipEntry. La procedura da seguire (e da ripetere per ogni file) è la seguente:

  • Si crea un nuovo oggetto di tipo ZipEntry, specificando il nome del file;
  • Si aggiunge questo oggetto al file zip vero e proprio (tramite il metodo PutNextEntry() esposto dalla classe ZipOutputStream).
  • Si inizia a scrivere il contenuto del file all'interno dello stream: a questo scopo ci viene in aiuto una classe facente parte della libreria chiamata StreamUtils, che offre un metodo chiamato Copy() che consente di copiare il contenuto di uno stream in un altro. In questo modo, siamo in grado di copiare lo stream del file che vogliamo comprimere (l'oggetto fileToCompress) all'interno dello stream che rappresenta il file compresso (l'oggetto file). Il terzo parametro richiesto è il buffer da utilizzare per l'operazione: in questo caso, ne usiamo uno di dimensione 4096 byte.
  • Terminata la procedura, si utilizza il metodo CloseEntry() della classe ZipOutputStream per specificare che l'operazione è terminata e il file è stato aggiunto.

Se si volesse aggiungere un altro file, è sufficiente ripetere questa procedura passando, come primo parametro del metodo StreamUtils.Copy() lo stream del nuovo file da includere all'interno del file compresso.

Una volta terminata la procedura, possiamo liberare le risorse e chiudere lo stream del file compresso invocando il metodo Close().

A questo punto, sfruttando un tool come Windows Phone Power Tools (che consente di esplorare l'isolated storage di un'applicazione installata sull'emulatore o sul telefono), possiamo verificare che sia andato tutto a buon fine: se abbiamo eseguito l'operazione correttamente, troveremo nella root dello storage un file compresso che, al suo interno, conterrà il file (o i file) della nostra applicazione. E' possibile, tramite le proprietà offerte dalle classi ZipOutputStream personalizzare il processo di compressione: ad esempio, tramite il metodo SetLevel() è possibile specificare il livello di compressione, da 0 (minimo) a 9 (massimo), oppure creare un archivio protetto da password assegnando un valore alla proprietà Password.

2 pagine in totale: 1 2

Attenzione: Questo articolo contiene un allegato.

Contenuti dell'articolo

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

Top Ten Articoli

Articoli via e-mail

Iscriviti alla nostra newsletter nuoviarticoli per ricevere via e-mail le notifiche!

In primo piano

I più letti di oggi

In evidenza

Misc