{"id":3996,"date":"2010-07-11T12:12:24","date_gmt":"2010-07-11T10:12:24","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=3996"},"modified":"2010-07-11T16:43:50","modified_gmt":"2010-07-11T14:43:50","slug":"gestione-dei-file-nelle-nostre-applicazione-iphone","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/gestione-dei-file-nelle-nostre-applicazione-iphone\/","title":{"rendered":"Gestione dei file nelle nostre applicazione iPhone"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/07\/gestione-file-applicazioni-iphone-devapp.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/07\/gestione-file-applicazioni-iphone-devapp.png\" alt=\"gestione file applicazioni iphone devapp\" title=\"gestione-file-applicazioni-iphone-devapp\" width=\"135\" height=\"114\" class=\"alignleft size-full wp-image-4003\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/07\/gestione-file-applicazioni-iphone-devapp.png 269w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/07\/gestione-file-applicazioni-iphone-devapp-150x127.png 150w\" sizes=\"auto, (max-width: 135px) 100vw, 135px\" \/><\/a> La gestione di file \u00e8 una caratteristica di primaria importanza nelle applicazioni che intendono salvare il proprio stato o esportare i loro contenuti (generalmente in forma testuale).<\/p>\n<p>A causa delle restrizioni imposte per motivi di sicurezza sull&#8217; iPhoneOS non \u00e8 possibile vedere l&#8217;intero filesystem ma solo ci\u00f2 che \u00e8 all&#8217;interno del filesystem riservato alla vostra applicazione (sandbox), ci\u00f2 porta all&#8217;impossibilit\u00e0 di usufruire direttamente dei dati utente (musica, video) o delle altre applicazioni.<\/p>\n<p>Innanzitutto \u00e8 importante conoscere il contenuto della home-directory comune a tutte le applicazioni in modo da tenere &#8220;in ordine&#8221; i file della nostra app&#8230;<\/p>\n<p><!--more--><\/p>\n<p>L&#8217;home-directory \u00e8 composta generalmente da quattro principali directory:<\/p>\n<ul>\n<li><em>NomeApplicazione<\/em>: ha il nome dell&#8217;applicazione e contiene eseguibile, NIB, localizzazioni, ecc&#8230; (non potete effettuare operazioni di I\/O)<\/li>\n<li><em>&#8220;Library&#8221;<\/em>: \u00e8 la cartella genitore di <em>&#8220;Preferences&#8221;<\/em> e la lettura\/scrittura avviene attraverso l&#8217;uso delle API<\/li>\n<li><em>&#8220;Documents&#8221;<\/em>: di default \u00e8 vuota ed \u00e8 gestibile a proprio piacimento<\/li>\n<li><em>&#8220;tmp&#8221;<\/em>: come suggerisce il nome \u00e8 la cartella dei file temporanei, potrete utilizzarla a vostro piacimento ma \u00e8 importante ricordare che non viene presa in considerazione da iTunes e che bisogna ricordarsi di svuotarne il contenuto (buona norma \u00e8 svutarlo alla chiusura dell&#8217;app)<\/li>\n<\/ul>\n<p>Un consiglio di particolare importanza \u00e8 quello di lasciar perdere le prime due directory e utilizzare solo le altre&#8230;<\/p>\n<p>Ora passiamo a parlare un po pi\u00f9 nella pratica di come potr\u00e0 avvenire l&#8217;accesso al filesystem; per lo scopo utilizzeremo la classe <em><strong><a href=\"http:\/\/developer.apple.com\/iphone\/library\/documentation\/Cocoa\/Reference\/Foundation\/Classes\/NSFileManager_Class\/Reference\/Reference.html\" target=\"_blank\">NSFileManager<\/a><\/strong><\/em> (per maggiori info vi rimando alla documentazione ufficiale).<\/p>\n<h4>Visualizzare il contenuto di una directory<\/h4>\n<p>Per lo scopo useremo la classe <em><strong>NSFileManager<\/strong><\/em> e il suo metodo <strong>directoryContentsAtPath:<\/strong><br \/>\nQuesto ha come ritorno la lista dei nomi di file e directory nel percorso dato, questi sono restituiti all&#8217;interno di un NSArray di NSString.<br \/>\n<em>Il consiglio \u00e8 di utilizzare una UITableView che avr\u00e0 come lunghezza la dimensione dell&#8217;array e come contenuto l&#8217;array stesso (i-esima cella =&gt; i-esimo elemento dell&#8217;NSArray).<\/em><\/p>\n<h4>Attributi di un file<\/h4>\n<p>Precedentemente abbiamo visto come ottenere il contenuto di una precisa directory ma, come avrete sicuramente notato, file e cartelle non sono distinguibili in quanto rappresentate entrambe una una NSString contenente il loro nome. Appunto per questo ricorreremo al metodo <strong><em>fileExistsAtPath:isDirectory:<\/em> <\/strong>(sempre di <em>NSFileManager<\/em>), <em>isDirectory<\/em> \u00e8 un puntatore a un boolean (BOOL) che avr\u00e0 i valori YES se il percorso \u00e8 una directory.<\/p>\n<h4>Lettura di un file<\/h4>\n<p>Per la lettura di un file ci rifaremo al concetto di flusso che considera i byte del file all&#8217;interno di uno stream che viene sequenzialmente letto (in questo modo non dovremmo necessariamente caricare tutto il file in memoria e perci\u00f2 avremo evitato di dover leggere solo file di piccole dimensioni).<\/p>\n<p>La classe che andremo ad utilizzare sar\u00e0 una sottoclasse di<em><strong> <a href=\"http:\/\/developer.apple.com\/iphone\/library\/documentation\/Cocoa\/Reference\/Foundation\/Classes\/NSStream_Class\/Reference\/Reference.html\" target=\"_blank\">NSStream<\/a><\/strong><\/em> denominata <em><strong>NSInputStream<\/strong><\/em>.<\/p>\n<p>Possiamo riassumere le operazioni da eseguire in:<\/p>\n<ul>\n<li>creare un buffer di memoria contenente i byte letti dal flusso (stream);<\/li>\n<li>leggere ciclicamente (es. con un ciclio <em>while<\/em>) i blocchi di byte (con dimensione inferiore alla dimensione del flusso);<\/li>\n<li>operare sui byte (per esempio scriverli di seguito in un UITextView dopo averli opportunamente convertiti in stringhe);<\/li>\n<li>chiudere il flusso quando i byte sono terminati.<\/li>\n<\/ul>\n<p>L&#8217;esempio del terzo punto \u00e8 proprio quello che andremo ad affrontare&#8230;<\/p>\n<p>Come riportiamo i byte nel UITextView ?<\/p>\n<p>Penso che un codice esprima molto pi\u00f9 di 1000 parole:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void) appendText: (NSString*) text {\r\ntextView.text = [NSString stringWithFormat: @\"%@%@\", textView.text, text];\r\n}\r\n<\/pre>\n<p>La stringa in rosso rappresenta ci\u00f2 che dobbiamo aggiungere mentre <em>textView.text<\/em> \u00e8 il testo dell&#8217;UITextView.<\/p>\n<p>Naturalmente non possiamo dare in input al metodo direttamente il blocco di byte letto ma dobbiamo prima convertirlo, anche in questo caso riporteremo la parte di codice necessria all&#8217;operazione:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nNSString *bufferString = [[NSString alloc] initWithBytesNoCopy:buffer length:bufferLength encoding:NSUTF8StringEncoding freeWhenDone: NO];\r\n[self appendText:bufferString];\r\n<\/pre>\n<p><em>&#8220;<span style=\"color: #ff0000;\">bufferString<\/span>&#8221; <\/em>sar\u00e0 il testo in input ad <em>appendText<\/em> (che nel metodo in questione chiamiamo semplicemente <span style=\"color: #ff0000;\"><em>text<\/em><\/span>) mentre <span style=\"color: #008000;\"><em>buffer<\/em><\/span> sar\u00e0 il gruppo di byte letti.<\/p>\n<p><em>NSUTF8StringEncoding <\/em>\u00e8 utilizzabile solo per file di testo semplici.<\/p>\n<h4>Creazione e Scrittura di un file<\/h4>\n<p>Per la creazione del file useremo <em><strong>createFileAtPath:<\/strong><\/em> di <em>NSFileManager.<\/em><\/p>\n<p>Per la scrittura di questo useremo il concetto di flusso ma invece che considerarlo in input sar\u00e0 in output (cio\u00e8 verso il file creato); per questo scopo useremo il metodo <em><strong>write:maxLength:<\/strong><\/em> di <strong><em>NSOutputStream<\/em><\/strong> (sottoclasse di <em>NSStream<\/em>).<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void) createAndSave {\r\n\r\n[asyncOutputStream release];\r\n[outData release];\r\n\r\noutData = [[textView.text dataUsingEncoding: NSUTF8StringEncoding] retain];\r\n\r\noutRange.location = 0;\r\n\r\nNSString *newFile [parentDirectoryPath\r\nstringByAppendingPathComponent: fileName.text];\r\n\r\n[[NSFileManager defaultManager] <strong>createFileAtPath<\/strong>:newFile contents:nil attributes:nil];\r\n\r\nasyncOutputStream = [[NSOutputStream alloc] initToFileAtPath: newFIle append: NO];\r\n\r\n[asyncOutpuntStream setDelegate: self];\r\n[asyncOutpuntStream scheduleInRunLoop:[NSRunLoop runLoop] forMode: NSDefaultRunLoopMode];\r\n[asyncOutpuntStream open];\r\n}\r\n<\/pre>\n<p><em><span style=\"color: #0000ff;\">textView<\/span><\/em> sar\u00e0 UITextView che conterr\u00e0 il testo del file<\/p>\n<p><em><span style=\"color: #ff0000;\">fileName<\/span><\/em> sar\u00e0 UITextField che conterr\u00e0 il nome del file<\/p>\n<p><em><strong>asyncOutputStream<\/strong><\/em> indica che il flusso dei dati avviene in maniera asincrona (ci\u00f2 pu\u00f2 avvenire anche nel caso della lettura); in questo modo l&#8217;app non resta in blocco per tutta la durata del flusso ma opera solo quando il flusso ha dei byte disponibili.<\/p>\n<p><em><strong>outData<\/strong><\/em> conterr\u00e0 il testo dell&#8217;UITextView convertito in NSData in modo da essere compatibile con il flusso<br \/>\nNel file header (.h) saranno necessarie le variabili d&#8217;istanza:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nNSData *outData;\r\nNSRange *outRange;\r\nNSOutputStream *asyncOutputStream;\r\n<\/pre>\n<p>Queste servono per coordinare il metodo e il callback&#8230;<\/p>\n<p>E&#8217; importante ricordare che la scrittura nel flusso generer\u00e0 degli eventi, i pi\u00f9 importanti sono:<\/p>\n<ul>\n<li><em><strong>NSStreamEventHasSpaceAvaible:<\/strong><\/em> indica che il flusso \u00e8 pronto<\/li>\n<li><em><strong>NSStreamEventErrorOccurred<\/strong><\/em>: indica che si \u00e8 verificato un errore (potete ad esempio visualizzare un <em>UIAlertView<\/em>)<\/li>\n<\/ul>\n<p>Quando il primo caso si verificher\u00e0 siamo pronti  a impostare il buffer da passare a <em>write:maxLength<\/em> di <em>NSOutputStream<\/em><\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n[outputStream write: buffer maxLength: 1]\r\n<\/pre>\n<p>in questo caso la lunghezza \u00e8 pari a 1 ma pu\u00f2 essere modificata.<\/p>\n<p><em>outputStream<\/em> \u00e8 il nostro NSOuputStream:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\nNSOutputStream *outputStream = (NSOutputStream*) stream;\r\n<\/pre>\n<p>Mentre <em>stream<\/em> \u00e8 un NSStream* in input:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n-(void)stream:(NSStream*)stream handelEvent:(NSStreamEvent)event { ... }\r\n<\/pre>\n<p style=\"text-align: right;\">\n<p style=\"text-align: right;\"><em>Buona programmazione a tutti e arrivederci al prossimo articolo&#8230;<\/em><\/p>\n<p style=\"text-align: right;\"><strong><em>Cinaglia Pietro<\/em><\/strong><em><strong> <\/strong><\/em><\/p>\n<p style=\"text-align: right;\"><em><strong> <\/strong><a href=\"http:\/\/www.unicz.net\/blog\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" title=\"www.unicz.net\/blog\" src=\"http:\/\/www.unicz.net\/blog\/mini-banner.png\" alt=\"www.unicz.net\/blog\" width=\"126\" height=\"44\" \/><\/a><br \/>\n<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Uno sguardo su come leggere\/creare file e directory utilizzando il concetto di flusso di byte e i metodi delle classi messe a disposizione dalla iPhone SDK&#8230;<\/p>\n","protected":false},"author":334,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[8],"tags":[314,322,317,320,321,316,318,315,319,323,242],"class_list":["post-3996","post","type-post","status-publish","format-standard","hentry","category-guide-varie","tag-cinaglia-pietro","tag-createfileatpath","tag-directory-iphone","tag-directorycontentsatpath","tag-fileexistsatpathisdirectory","tag-gestione-file-iphone","tag-io-xcode","tag-iphone-sdk","tag-nsfilemanager","tag-nsoutputstream","tag-tutorial-xcode"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3996","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/334"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=3996"}],"version-history":[{"count":9,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3996\/revisions"}],"predecessor-version":[{"id":4007,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/3996\/revisions\/4007"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=3996"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=3996"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=3996"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}