IOS: не удается сохранить файл в папке "Поддержка приложений", но может быть в "Документах",
Я могу загрузить и сохранить двоичный файл в папке "Документы" с настраиваемым именем отлично.
Если я просто изменил URL-адрес в папку "Поддержка приложений" вместо папки "Документы", он не сможет записать на этот URL-адрес, что его не существует.
Здесь код построения URL:
- ( NSURL * ) getSaveFolder
{
NSURL * appSupportDir = nil;
NSURL * appDirectory = nil;
NSArray * possibleURLs = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSAllDomainsMask];
if ( [possibleURLs count] >= 1 )
{
appSupportDir = [possibleURLs objectAtIndex:0];
}
if ( appSupportDir != nil)
{
NSString * appBundleID = [[NSBundle mainBundle] bundleIdentifier];
appDirectory = [appSupportDir URLByAppendingPathComponent:appBundleID];
}
return appSupportDir;
}
Здесь сохраненный код:
- ( void ) writeOutDataToFile:( NSData * )data
{
NSURL * finalURL = [self.rootPathURL URLByAppendingPathComponent:self.aFileName];
[data writeToURL:finalURL atomically:YES];
}
Если я изменил NSArray на:
NSArray * possibleURLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
тогда он сохраняет штраф.
Я читал файлы Apple Docs on File и не могу исправить это - что мне не хватает?
Ответы
Ответ 1
В отличие от каталога Documents
каталог Application Support
по умолчанию не существует в песочнице приложений. Вам нужно создать его, прежде чем вы сможете его использовать.
И гораздо более простой способ получить ссылку на каталог:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *appSupportDirectory = paths.firstObject;
Ответ 2
Если кто-то не знает, как это сделать, что описывает rmaddy:
NSString *appSupportDir = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject];
//If there isn't an App Support Directory yet ...
if (![[NSFileManager defaultManager] fileExistsAtPath:appSupportDir isDirectory:NULL]) {
NSError *error = nil;
//Create one
if (![[NSFileManager defaultManager] createDirectoryAtPath:appSupportDir withIntermediateDirectories:YES attributes:nil error:&error]) {
NSLog(@"%@", error.localizedDescription);
}
else {
// *** OPTIONAL *** Mark the directory as excluded from iCloud backups
NSURL *url = [NSURL fileURLWithPath:appSupportDir];
if (![url setResourceValue:@YES
forKey:NSURLIsExcludedFromBackupKey
error:&error])
{
NSLog(@"Error excluding %@ from backup %@", url.lastPathComponent, error.localizedDescription);
}
else {
NSLog(@"Yay");
}
}
}
Ответ 3
Я столкнулся с той же проблемой и решил использовать более сжатый подход:
let fileManager = NSFileManager.defaultManager()
let urls = fileManager.URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask) as! [NSURL]
if let applicationSupportURL = urls.last {
fileManager.createDirectoryAtURL(applicationSupportURL, withIntermediateDirectories: true, attributes: nil, error: nil)
}
Это работает, потому что createDirectoryAtURL
с помощью withIntermediateDirectories: true
создает папку только в том случае, если она не существует.
Ответ 4
Здесь приведен код Swift для iOS, который может записать файл двоичных данных в каталог поддержки приложения. Части этого были вдохновлены ответом chrysAllwood.
/// Method to write a file containing binary data to the "application support" directory.
///
/// - Parameters:
/// - fileName: Name of the file to be written.
/// - dataBytes: File contents as a byte array.
/// - optionalSubfolder: Subfolder to contain the file, in addition to the bundle ID subfolder.
/// If this is omitted no extra subfolder is created/used.
/// - iCloudBackupForFolder: Specify false to opt out from iCloud backup for whole folder or
/// subfolder. This is only relevant if this method call results in
/// creation of the folder or subfolder, otherwise it is ignored.
/// - Returns: Nil if all OK, otherwise text for a couple of non-Error errors.
/// - Throws: Various errors possible, probably of type NSError.
public func writeBytesToApplicationSupportFile(_ fileName : String,
_ dataBytes : [UInt8],
optionalSubfolder : String? = nil,
iCloudBackupForFolder : Bool = true)
throws -> String? {
let fileManager = FileManager.default
// Get iOS directory for "application support" files
let appSupportDirectory =
fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first
if appSupportDirectory == nil {
return "Unable to determine iOS application support directory for this app."
}
// Add "bundle ID" as subfolder. This is recommended by Apple, although it is probably not
// necessary.
if Bundle.main.bundleIdentifier == nil {
return "Unable to determine bundle ID for the app."
}
var mySupportDirectory =
appSupportDirectory!.appendingPathComponent(Bundle.main.bundleIdentifier!)
// Add an additional subfolder if that option was specified
if optionalSubfolder != nil {
mySupportDirectory = appSupportDirectory!.appendingPathComponent(optionalSubfolder!)
}
// Create the folder and subfolder(s) as needed
if !fileManager.fileExists(atPath: mySupportDirectory.path) {
try fileManager.createDirectory(atPath: mySupportDirectory.path,
withIntermediateDirectories: true, attributes: nil)
// Opt out from iCloud backup for this subfolder if requested
if !iCloudBackupForFolder {
var resourceValues : URLResourceValues = URLResourceValues()
resourceValues.isExcludedFromBackup = true
try mySupportDirectory.setResourceValues(resourceValues)
}
}
// Create the file if necessary
let mySupportFile = mySupportDirectory.appendingPathComponent(fileName)
if !fileManager.fileExists(atPath: mySupportFile.path) {
if !fileManager.createFile(atPath: mySupportFile.path, contents: nil, attributes: nil) {
return "File creation failed."
}
}
// Write the file (finally)
let fileHandle = try FileHandle(forWritingTo: mySupportFile)
fileHandle.write(NSData(bytes: UnsafePointer(dataBytes), length: dataBytes.count) as Data)
fileHandle.closeFile()
return nil
}
Ответ 5
Один лайнер - создаст при необходимости тоже:
[[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil]
Ответ 6
Версия Swift 4.2
let fileManager = FileManager.default
let urls = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask)
if let applicationSupportURL = urls.last {
do{
try fileManager.createDirectory(at: applicationSupportURL, withIntermediateDirectories: true, attributes: nil)
}
catch{
print(error)
}
}