重建应用程序时文档目录路径更改

Document directory path change when rebuild application

我从 url 下载视频文件并将其保存在具有以下路径的文档目录中:

  let destination: DownloadRequest.DownloadFileDestination = { _, _ in
      let pathComponent = "pack\(self.packID)-\(selectRow + 1).mp4"
      let directoryURL: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
      let folderPath: URL = directoryURL.appendingPathComponent("Downloads", isDirectory: true)
      let fileURL: URL = folderPath.appendingPathComponent(pathComponent)
      return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
    }

我的视频已成功下载并播放。 但是有一个问题,当我在 Xcode 中重建应用程序并尝试播放我下载的最后一个视频时,视频没有显示,而当我下载一个新视频时,这个保存并成功播放。

我看过每个视频包路径,它们是不同的。

1 - 文件:///Users/myMac/Library/Developer/CoreSimulator/Devices/EAC2F4CE-EA09-46C0-B403-1CE9E24B6822/data/Containers/Data/Application/1D2C1F7B-E627-4898-91C1-D0AF8D5E0F1E/Documents/Downloads/pack7-1.mp4

2 - 文件:///Users/myMac/Library/Developer/CoreSimulator/Devices/EAC2F4CE-EA09-46C0-B403-1CE9E24B6822/data/Containers/Data/Application/F950E9A5-C9F3-4B8C-BCF5-647EEC233CEE/Documents/Downloads/pack7-3.mp4

现在,我的问题是,当我们从 App Store 更新应用程序时,是否意味着重新安装?此路径是否更改?

如何解决这个问题?

iOS 8 以后,Absolute url 应用程序的沙箱会在您每次重新启动应用程序时发生变化。因此,您永远不应该保存视频的绝对值 url。每次重新启动应用程序时,保存视频名称并重新创建 url。

  let pathComponent = "pack\(self.packID)-\(selectRow + 1).mp4"
  let directoryURL: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
  let folderPath: URL = directoryURL.appendingPathComponent("Downloads", isDirectory: true)
  let fileURL: URL = folderPath.appendingPathComponent(pathComponent)

一旦您 fileURL 查找该文件,您将找到在上次启动时下载的文件。

iOS 每次用户启动应用程序时都会为应用程序创建一个新的沙盒。因此绝对 URL 会非常。但是 iOS 将像以前一样负责设置沙盒中的所有文件夹和内容。因此,尽管 SandBox 的基础 url 发生变化,但所有内容的相对 url 将保持不变。

因此建议永远不要将绝对 url 保存到任何文件夹 :) 希望对您有所帮助

我建议使用书签。 查看以下文章中的 使用书签定位文件 部分:https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/AccessingFilesandDirectories/AccessingFilesandDirectories.html#//apple_ref/doc/uid/TP40010672-CH3

编辑:

链接文档的一些相关部分,以防万一:

Important: Although they are safe to use while your app is running, file reference URLs are not safe to store and reuse between launches of your app because a file’s ID may change if the system is rebooted. If you want to store the location of a file persistently between launches of your app, create a bookmark as described in Locating Files Using Bookmarks.

我有一个使用大量文件处理的应用程序,因此我在 NSURL 类别中创建了以下方法来 return 给定 URL 的书签数据.

- (NSData*)defaultBookmark
{
    NSError* error = nil;
    NSData* bookmarkData =  [self bookmarkDataWithOptions:NSURLBookmarkCreationSuitableForBookmarkFile
                           includingResourceValuesForKeys:nil
                                            relativeToURL:nil
                                                    error:&error];
    if (error != nil)
    {
        NSLog(@"error creating bookmark for url '%@': %@", self, error);
    }
    return bookmarkData;
}

要从书签数据创建 NSURL 对象,请使用类似的东西:

    NSError* error = nil;
    BOOL isStale = NO;
    NSURL* url = [NSURL URLByResolvingBookmarkData:bookmarkData
                                           options:NSURLBookmarkResolutionWithoutUI
                                     relativeToURL:nil
                               bookmarkDataIsStale:&isStale
                                             error:&error];
    if (error != nil || url == nil)
    {
        NSLog(@"Error restoring url from bookmark: %@", error);
    }
    else
    {
        // use url to load file
        ...
    }

关于已接受的答案,有一点不清楚的是,当您想从文档目录中获取文件时,您实际上是如何搜索文件 的。我们开始吧:

要保存文件(例如图片):

func saveImage(with imageName: String) {
    guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {return}
    guard let data = image.jpegData(compressionQuality: 1) else {return}
    let url = documentsDirectory.appendingPathComponent(imageName)
    do {
        try data.write(to: url)
    } catch {
        print("Error saving image")
    }
    
}

要获取文件:

func fetchImage(with imageName: String) -> UIImage? {
    let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
    if let path = paths.first {
        let imageURL = URL(fileURLWithPath: path).appendingPathComponent(imageName)
        let data = try! Data(contentsOf: imageURL)
        if let image = UIImage(data: data) {
            return image
        }
    }
    return nil
}

所以再说一遍:我们的想法不是保存文件的完整路径,因为当您在重启后尝试从该路径获取文件时,这是行不通的。您应该做的是保存文件的名称(上例中的 imageName)。然后搜索具有该名称的文件。

我遇到了同样的问题。这个解决方案对我有用,它是其他堆栈溢出帖子放在一起的:

保存视频:

 func saveVideo(videoURL: URL)
  {
    let videoData = NSData(contentsOf: videoURL)

    // *** Get documents directory path *** //
    let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0]
    // *** Append video file name, save this name somewhere, like core data *** //
    let fileName = UUID().uuidString
   
    let dataPath = paths.appending("/\(fileName).mp4")
    
    if exercise.videoUrls != nil{
        exercise.videoUrls!.append("/\(fileName).mp4")
        try! viewContext.save()
        
    } else {exercise.videoUrls =  ["/\(fileName).mp4"]}

    // *** Write video file data to path *** //
    videoData?.write(toFile: dataPath, atomically: true)
    
}

加载视频:

func loadVideoFromDiskWith(fileName: String) -> URL? {
    
    let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
    
    let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
    let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
    
    if let dirPath = paths.first {
        let videoUrl = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
        
        return videoUrl
        
    }
    
    return nil
}