【问题标题】:FileManager can't locate PDF directory in Xcode projectFileManager 在 Xcode 项目中找不到 PDF 目录
【发布时间】:2021-01-11 17:54:06
【问题描述】:

我正在尝试使用 SwiftUI 列出存储在我的 Xcode 项目中的文件夹中的所有 PDF,但是在尝试了我在这里找到的许多不同方法后,我无法使其正常工作。

目前我正在使用文件管理器列出项目,但是当我尝试打印或列出找到的项目时,它返回 nil

我已通过将 PDF 拖入 Xcode 项目来添加它们。我还确保它们位于我的 复制捆绑资源 中,因此我可以使用 FileManager。见下文:

这是我的 Xcode 结构,我正在尝试列出 PDF 中的所有项目。正如您在下面看到的,PDF 存储在 "/Swift/Products/Detail/Tab5/PDF" 中的主文件夹结构之外,因此当尝试使用 Bundle.main.bundlePath 列出文件时,它会查看products.app.

这是我尝试使用 FileManager 查找文件夹内所有 PDF 的代码:

struct ProductTab5View: View {
    
    @State var files = getFiles()

    var body: some View {
        VStack{
            ForEach(0..<files.count, id: \.self) { item in
                 Text(files[item])
             }
        }
    }
}

func getFiles() -> Array<String>{
    // Get  document directory url
    let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    var files: [String] = []
    
    do {
        // Get the directory contents urls (including subfolders urls)
        let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil)
        print(directoryContents)
        // filter  directory contents:
        let pdfFiles = directoryContents.filter{ $0.pathExtension == "pdf" }
        let pdfFileNames = pdfFiles.map{ $0.deletingPathExtension().lastPathComponent }
        files.append(contentsOf: pdfFileNames)

    } catch {
        print(error)
    }
    return files
}

【问题讨论】:

  • 请在最终构建的应用程序包中添加该 pdf 文件所在位置的屏幕截图。
  • @Asperi 我已经更新了显示捆绑资源的帖子。这是你的意思吗?

标签: ios swift xcode swiftui


【解决方案1】:

通过这种方式,资源被平面复制到根应用程序包中,而不是像在提供的代码快照中尝试的用户的 Documents (并且没有为您创建 PDF 子目录)。

所以解决方案就是迭代内部 pdf 文件,比如

func getFiles() -> Array<String> {
    return Bundle.main.urls(forResourcesWithExtension: "pdf", subdirectory: nil)?
        .compactMap { $0.lastPathComponent } ?? []
}

使用 Xcode 12.1 / iOS 14.1 测试

【讨论】:

  • 如此简单!伟大的。我忘了提到我正在使用 swiftUI,不过我假设你可以从我的代码中看到这一点。我想在一个 VStack 中列出这些,我想在我的代码中使用@State 来做。这是正确的方法吗?调用 getFiles 函数?
【解决方案2】:

您当前的代码存在一些潜在问题。

首先是这一行:

FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first

除非您已经完成了将所有这些文件添加到应用程序的文档目录中的过程,否则没有理由相信这些文件会在那里。换句话说:您的 Xcode 项目与您应用的文档目录相同。将应用程序的文档目录视为您可以存储由应用程序管理的用户创建或下载的内容的地方,而不是 Xcode 本身。

接下来要检查的是是否所有这些文件都真正添加到了您的目标中。检查目标的“构建阶段”->“复制捆绑资源”部分,看看它们是否出现在那里。

如果他们这样做,您可以使用 FileManager,但您必须访问正确的目录,该目录位于主捆绑包内,而不是应用程序的用户文档目录。

以下答案对此进行了详细说明(包括确保创建文件夹引用):Getting a list of files in the Resources folder - iOS

要点是这样的:

if let files = try? FileManager.default.contentsOfDirectory(atPath: Bundle.main.bundlePath) { //may need to dig into subdirectories
   for file in files {
            //manipulate the file
        }
    }

然后使用 FileManager 列出该路径中的文档。

请注意,您还可以通过执行以下操作以递归方式获取所有文件(包括子目录):

let url = URL(fileURLWithPath: Bundle.main.bundlePath)
if let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) {
    for case let fileURL as URL in enumerator {
        print(fileURL)
    }
}

通过在调试过程中使用上述代码,您应该可以深入了解您的目录结构在您的包中的真实情况。一旦你弄清楚了,将前面的代码示例调整为:

if let files = try? FileManager.default.contentsOfDirectory(atPath: Bundle.main.bundlePath + mySubPath) {
   for file in files {
            //manipulate the file
        }
    }

一旦您填写mySubPath,它将只为您提供您想要的一个子目录中的文件。注意,如果你想要递归搜索,你可以使用上面的代码示例。

您最终可能希望排除非文件项——有关 Swift 中递归目录列表的更多详细信息,请参阅此答案:listing all files in a folder recursively with swift

【讨论】:

  • 谢谢@jn_pdx。我已手动将这些文件添加到应用程序的文档目录中。检查捆绑资源后,我可以看到 pdf 在那里。您能否更新链接,因为它似乎不起作用?希望这能回答我的问题。
  • 感谢您的链接,但我真的很难理解这一点。如何挖掘子目录?如果我运行你的代码,它确实会返回 PDF 文件夹,但也会返回捆绑包中的一堆其他东西 Info.plist 例如。
  • 只需附加您的 PDF 目录名称。 FileManager.default.contentsOfDirectory(atPath: Bundle.main.bundlePath + "/PDF") 或任何它
  • 我建议你 print(Bundle.main.bundlePath) 这样你就可以看到它给了你什么——然后你可以在 Finder 或终端中探索该目录(假设你在 Mac 或模拟器)并查看如何需要向该字符串附加更多信息才能到达正确的子目录
  • 谢谢,当我打印(Bundle.main.bundlePath)时,它指向我的应用程序名称Products.app(正如您在原始帖子中的层次结构中看到的那样。如果我添加+ "/Swift/PDF" 这会给我一个不存在的路径,我知道我可能会让这比现在更困难,但肯定有一种简单的方法可以列出文件夹目录中的所有文件。
猜你喜欢
  • 1970-01-01
  • 2021-01-09
  • 2019-07-02
  • 2013-08-03
  • 2018-05-29
  • 1970-01-01
  • 2021-08-26
  • 2016-01-27
  • 2013-12-27
相关资源
最近更新 更多