35

我可以使用自定义名称下载二进制文件并将其保存到“文档”文件夹中。

如果我只是将 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 并且无法解决这个问题 - 我错过了什么?

4

6 回答 6

52

如果有人不确定如何执行 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");
        }
    }
}
于 2013-07-02T16:25:44.210 回答
51

Documents目录不同的是,该Application Support目录默认不存在于应用的沙箱中。您需要先创建它,然后才能使用它。

获取目录引用的更简单的方法是:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *appSupportDirectory = paths.firstObject;
于 2013-04-25T01:39:11.193 回答
9

我遇到了同样的问题,并决定使用更简洁的方法:

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)
}

这是有效的,因为createDirectoryAtURLusingwithIntermediateDirectories: true仅在文件夹不存在时才创建该文件夹。

于 2015-08-01T09:13:44.750 回答
5

一个班轮 - 如有必要,也会创建:

[[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil]
于 2019-03-27T04:48:44.200 回答
4

这是一些适用于 iOS 的 Swift 代码,可以将二进制数据文件写入应用程序支持目录。其中部分内容的灵感来自 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
   }
于 2017-02-24T00:27:52.623 回答
1

斯威夫特 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)
        }
    }
于 2019-09-05T13:13:07.697 回答