重建应用程序时文档目录路径更改
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
}
我从 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
}