iOS文件路径在每次启动/重新运行应用程序时都会更改

iOS文件路径在每次启动/重新运行应用程序时都会更改,ios,swift,file-manager,Ios,Swift,File Manager,每次启动应用程序时,我都会遇到更改文件路径的问题。 我在应用程序包中有一个文件(“AppConstant.json”),这个文件需要复制到应用程序文档目录中。我正在文档目录上创建的用户文件夹“MyFolder”中成功保存“AppConstant.json”文件 但问题是,当我第二次重新启动应用程序时,它没有显示相同的路径。我也在使用relativepath,但它仍然无法使用 这是密码 //调用目录 let stringAppConstant = copyFileFromBundleToDocum

每次启动应用程序时,我都会遇到更改文件路径的问题。 我在应用程序包中有一个文件(“AppConstant.json”),这个文件需要复制到应用程序文档目录中。我正在文档目录上创建的用户文件夹“MyFolder”中成功保存“AppConstant.json”文件

但问题是,当我第二次重新启动应用程序时,它没有显示相同的路径。我也在使用relativepath,但它仍然无法使用

这是密码 //调用目录

let stringAppConstant = copyFileFromBundleToDocumentDirectory(resourceFile: "AppConstant", resourceExtension: "json")
//保存或获取退出文件路径

func copyFileFromBundleToDocumentDirectory(resourceFile: String, resourceExtension: String) -> String 
  {
        var stringURLPath = "Error_URLPath"
        let fileManager = FileManager.default
        let docURL = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
        let destFolderPath = URL(string:docURL)?.appendingPathComponent("MyFolder")
        let fileName = "\(resourceFile).\(resourceExtension)"
        guard let newDestPath = destFolderPath, let sourcePath = Bundle.main.path(forResource: resourceFile, ofType: ".\(resourceExtension)"), let fullDestPath = NSURL(fileURLWithPath: newDestPath.absoluteString).appendingPathComponent(fileName) else {
            return stringURLPath
        }

       if !fileManager.fileExists(atPath: newDestPath.path) {
            do {
                try fileManager.createDirectory(atPath: newDestPath.path,withIntermediateDirectories: true, attributes: nil)
                print("Created folder successfully in :::", newDestPath.path)
            } catch {
                print("Error in creating folder :::",error.localizedDescription);
            }
        }
        else {
            print("Folder is already exist!")
        }
        if fileManager.fileExists(atPath: fullDestPath.path) {
            print("File is exist in ::: \(fullDestPath.path)")
            stringURLPath = fullDestPath.path
        }
        else {
            do {
                try fileManager.copyItem(atPath:  sourcePath, toPath: fullDestPath.path)
                print("Saved file successfully in :::", fullDestPath.path)
                stringURLPath = fullDestPath.path
            } catch {
                print("Error in creating file ::: \(error.localizedDescription)")
            }
        }
        return stringURLPath
    }
请帮助我,我需要在沙盒中保存路径的位置。这是我实现的正确方法吗

我在设备和模拟器中运行,重新启动时两个路径都不同 这是首次启动的路径: /var/mobile/Containers/Data/Application/81B568A7-0932-4C3E-91EB-9DD62416DFE8/Documents/MyFolder/AppConstant.json

重新启动应用程序我将获得新路径: /var/mobile/Containers/Data/Application/3DAABAC3-0DF5-415B-82A5-72B204311904/Documents/MyFolder/AppConstant.json

注意:我创建了一个示例项目,我使用了相同的代码,它正在工作。但在现有项目中,它不起作用。我只对样本和项目使用相同的bundle id和profile。检查文件添加的参考、设置、版本都相同。

有什么想法吗?

编辑1: 嗨,我创建了一个新项目,并使用了我在main中发布的相同代码,它正在工作。但在实际项目中,它不起作用

不确定项目中到底发生了什么,请尝试调试它。这也是发展的一部分。:)

如果您急于在本周末修复此问题,请尝试使用以下代码段

// collect data from bundle
let constFileURL = Bundle.main.url(forResource: "AppConst", withExtension: "json")!
let data = try! Data(contentsOf: constFileURL)

// try to write data in document directory
do {
    let constFileURL = try saveFileInDocumentDirectory(filePath: "MyFolder/AppConst.json", data: data)
    // use your `constFileURL`
} catch (let error as FileOperationError) {
    switch error {
    case .fileAlreadyExists(let url):
        let data = try! Data(contentsOf: url)
        print(String(data: data, encoding: .utf8))
    case .IOError(let error):
        print("IO Error \(error)")
    }
} catch {
    print("Unknown Error \(error)")
}

// Helpers
enum FileOperationError: Error {
    case fileAlreadyExists(url: URL)
    case IOError(Error)
}
func saveFileInDocumentDirectory(filePath: String, data: Data) throws -> URL {
    
    // final destination path
    let destURLPath = fullURLPathOf(filePath, relativeTo: .documentDirectory)
    // check for file's existance and throw error if found
    guard FileManager.default.fileExists(atPath: destURLPath.path) == false else {
        throw FileOperationError.fileAlreadyExists(url: destURLPath)
    }
    // Create Intermidiate Folders
    let intermidiateDicPath = destURLPath.deletingLastPathComponent()
    if FileManager.default.fileExists(atPath: intermidiateDicPath.path) == false {
        do {
            try FileManager.default.createDirectory(at: intermidiateDicPath, withIntermediateDirectories: true, attributes: nil)
        } catch {
            throw FileOperationError.IOError(error)
        }
    }
    
    // File Writing
    do {
        try data.write(to: destURLPath, options: .atomic)
    } catch {
        throw FileOperationError.IOError(error)
    }
    return destURLPath
}
func fullURLPathOf(_ relativePath: String, relativeTo dic:FileManager.SearchPathDirectory ) -> URL {
    return FileManager.default.urls(for: dic, in: .userDomainMask).first!.appendingPathComponent(relativePath)
}
原始答案 如果文件操作成功,为什么不返回
“MyFolder/\(fileName)”
?如果以后需要访问该路径,则始终可以使用
FileManager
api进行访问

let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let constFilePath = docDir.appendingPathComponent("MyFolder/\(fileName)")

// Access const file data
do { 
  let fileData = try Data(contentsOf: constFilePath)

  // Use you data for any further checking

} catch {
  // Error in reading file data
  print("Error in file data access : \(error)")
}


容器路径定期更改的行为是正常的

这些线

let destFolderPath = URL(string:docURL)?.appendingPathComponent("MyFolder")
let fileName = "\(resourceFile).\(resourceExtension)"
guard let newDestPath = destFolderPath, let sourcePath = Bundle.main.path(forResource: resourceFile, ofType: ".\(resourceExtension)"), let fullDestPath = NSURL(fileURLWithPath: newDestPath.absoluteString).appendingPathComponent(fileName) else {
    return stringURLPath
}
包含很多错误

  • URL(string
    是文件路径的错误API,它是
    URL(fileURLWithPath)
  • path(forResource:ofType:)
    的第二个参数不能有前导点
  • API
    absoluteString
    作为
    URL(fileURLWithPath
  • 不是真正的错误,但不要在Swift中使用
    NSURL

强烈建议始终使用
URL
相关API连接路径并从
FileManager
获取文档文件夹。此外,最好的做法是让方法
抛出真正的错误,而不是返回无意义的文字字符串。并且
NSSearchPathForDirectoriesInDomains
已过时不应在Swift中使用

func copyFileFromBundleToDocumentDirectory(resourceFile: String, resourceExtension: String) throws -> URL
{
    let sourceURL = Bundle.main.url(forResource: resourceFile, withExtension: resourceExtension)!
    
    let fileManager = FileManager.default
    let destFolderURL = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("MyFolder")
    let fullDestURL = destFolderURL.appendingPathComponent(resourceFile).appendingPathExtension(resourceExtension)
    
    if !fileManager.fileExists(atPath: destFolderURL.path) {
        try fileManager.createDirectory(at: destFolderURL, withIntermediateDirectories: true, attributes: nil)
        print("Created folder successfully in :::", destFolderURL.path)
        try fileManager.copyItem(at: sourceURL, to: fullDestURL)
        print("Saved file successfully in :::", fullDestURL.path)
    } else {
        print("Folder already exists!")
        if fileManager.fileExists(atPath: fullDestURL.path) {
            print("File exists in ::: \(fullDestURL.path)")
        } else {
            try fileManager.copyItem(at: sourceURL, to: fullDestURL)
            print("Saved file successfully in :::", fullDestURL.path)
        }
    }
    return fullDestURL
}

有助于缩小范围的问题-当你说“不显示相同的路径”时,你是指fullDestPath?另外,你是在模拟器中运行,还是在实际设备上运行?当你“再次启动”时,你是以相同的方式启动,还是以不同的方式启动(例如,从Xcode调试一次启动而不是另一次启动)?嗨@Corbell,我更新了我的问题。我启动了设备和模拟器,两者的行为都相同。下次我启动相同的方法调用方法时,您如何处理
copyFileFromBundleToDocumentDirectory
的返回值?如果您存储它以稍后访问该文件,则可能是问题所在,因为它包含绝对path not relative.Hi@GlebA.,在启动应用程序(首次启动-首次安装)时,我将文件保存在文档目录中,之后我需要使用相同的文件(已保存在文档目录中)以供进一步使用。那么,如何获取“相对路径”。请猜此语句是错误的
let sourcePath=Bundle.main.path(forResource:resourceFile,类型:“.\(resourceExtension)”)
可以替换为
let sourcePath=Bundle.main.path(forResource:resourceFile,类型:resourceExtension)
Hi无论如何都要解决这个问题,现在每次启动时都要创建一个新路径,如果文件已经存在,那么我需要确切的路径,不想再重新创建文件夹和文件。任何ideaHi@Sauvik,我的fileData总是为零(让fileData=try?Data(contentsOf:constFilePath)),因为文件在中不可用path@Prasanth只需使用
do try catch
检查编辑的代码段,您能检查您得到的错误吗?您好,我得到了文件“AppConstant.json”无法打开,因为没有这样的文件。我犯了一个错误,而不是使用
。documentDirectory
,我使用了
。applicationSupportDirectory
。您现在可以试试吗?Hi@vadian,现在我也遇到了同样的错误,每次它创建一个新的路径和文件。同时,在我创建的示例项目中,它现在正在工作。我给出了ame bundle ID、应用程序名称和配置文件也相同。我是否要添加其他内容?我认为应用程序沙盒帐户或设置路径中存在一些问题-不确定,因为相同的代码(由您提供)在新的示例测试项目容器路径(UUID)中起作用更改,但容器的内容不得更改。永远不要保存完整路径,始终使用相对路径和
.documentDirectory
Hi@vadian,我希望问题出现在其他地方,因为相同的代码在示例项目中工作。我真的需要查找。使用相对路径也不工作。谢谢