72 votes

Comment obtenir un chemin d'accès accessible en écriture sur l'iPhone ?

Je poste cette question parce que j'avais rédigé une réponse complète pour un autre post, quand j'ai découvert qu'elle ne s'appliquait pas à l'original, mais j'ai pensé qu'elle était trop utile pour être gaspillée. C'est pourquoi j'en ai fait un wiki communautaire, afin que d'autres puissent étoffer la question et la (les) réponse(s). Si vous trouvez la réponse utile, veuillez voter pour la question - étant donné qu'il s'agit d'un wiki communautaire, je ne devrais pas recevoir de points pour ce vote, mais cela aidera d'autres personnes à la trouver.

Comment puis-je obtenir un chemin dans lequel l'écriture de fichiers est autorisée sur l'iPhone ? Vous pouvez (à tort) écrire n'importe où sur le Simulateur, mais sur l'iPhone, vous n'êtes autorisé à écrire que dans des emplacements spécifiques.

186voto

Il existe trois types de chemins inscriptibles : le premier est celui des documents, dans lequel vous stockez les éléments que vous souhaitez conserver et mettre à la disposition de l'utilisateur via iTunes (à partir de la version 3.2) :

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

Deuxièmement, et de manière très similaire au répertoire Documents, il y a le dossier Library, dans lequel vous stockez les fichiers de configuration et les bases de données accessibles en écriture que vous souhaitez également conserver, mais que vous ne voulez pas que l'utilisateur puisse manipuler via iTunes :

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libraryDirectory = [paths objectAtIndex:0];

Notez que même si l'utilisateur ne peut pas voir les fichiers dans iTunes en utilisant un appareil antérieur à la version 3.2 (l'iPad), la constante NSLibraryDirectory est disponible depuis l'iPhoneOS 2.0, et peut donc être utilisée pour les versions visant la version 3.0 (ou même plus anciennes si vous continuez à le faire). Par ailleurs, l'utilisateur ne pourra rien voir à moins que vous ne signaliez une application comme autorisant les utilisateurs à modifier des documents, donc si vous utilisez Documents aujourd'hui, tout va bien tant que vous changez d'emplacement lors de la mise à jour pour la prise en charge des documents de l'utilisateur.

Enfin, il existe un répertoire de cache, dans lequel vous pouvez placer des images dont vous ne vous souciez pas qu'elles existent à long terme ou non (le téléphone peut les supprimer à un moment donné) :

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [paths objectAtIndex:0];
BOOL isDir = NO;
NSError *error;
if (! [[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&isDir] && isDir == NO) {
    [[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:NO attributes:nil error:&error];
}

Notez que vous devez créer le répertoire Caches à cet endroit, donc lorsque vous écrivez, vous devez vérifier et créer à chaque fois ! C'est un peu pénible, mais c'est comme ça.

Ensuite, lorsque vous avez un chemin accessible en écriture, il vous suffit d'y ajouter un nom de fichier, comme suit :

NSString *filePath =  [documentsDirectory stringByAppendingPathComponent:@"SomeDirectory/SomeFile.txt"];

o

NSString *filePath =  [cachePath stringByAppendingPathComponent:@"SomeTmpFile.png"];

Utilisez ce chemin pour lire ou écrire.

Notez que vous pouvez créer des sous-répertoires dans l'un ou l'autre de ces chemins accessibles en écriture, que l'une des chaînes de l'exemple ci-dessus utilise (en supposant que l'une d'entre elles ait été créée).

Si vous essayez d'écrire une image dans la photothèque, vous ne pouvez pas utiliser les appels au système de fichiers pour le faire - au lieu de cela, vous devez avoir une UIImage en mémoire, et utiliser la fonction UIImageWriteToSavedPhotosAlbum() défini par UIKit. Vous n'avez aucun contrôle sur le format de destination ou les niveaux de compression, et vous ne pouvez pas joindre d'EXIF de cette manière.

5voto

smallduck Points 799

Merci à Kendall et Dave, ci-dessus, et j'ai pensé qu'il était utile de soulever cet amendement. Lors de l'utilisation pour un code de débogage unique, j'ai utilisé cette astuce de Mike Ash NSBlog pour éliminer les variables temporaires isDir & error, minimisant ainsi le nombre de lignes et rendant la verbosité presque supportable :

NSFileHandle *dumpFileHandle = nil;
#ifdef DEBUG
    NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    if (![[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&(BOOL){0}])
        [[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:YES attributes:nil error:&(NSError*){nil}];
    NSString *dumpPath = [cachePath stringByAppendingPathComponent:@"dump.txt"];
    [[NSFileManager defaultManager] createFileAtPath:dumpPath contents:nil attributes:nil];
    [(dumpFileHandle = [NSFileHandle fileHandleForWritingAtPath:dumpPath]) truncateFileAtOffset:0];
#endif

if (dumpFileHandle) [dumpFileHandle writeData:blah];

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X