核心数据:大文件上的“允许外部存储”性能

3li*_*3li 5 core-data ios swift

我试图了解Allows External Storage核心数据属性的行为,并看看它是否能让我免于手动在文件系统中存储文件。我想看看它在处理非常大的文件时表现如何。为此,我创建了一个虚拟项目并使用 Core Data 存储了一个大文件 (2 GB)。然后,我在获取和处理数据时监控了内存使用情况,令我惊讶的是,它没有超过 48 MB!这是为什么?它是否以块的形式获取数据?如果是这样,怎么办?该结构是否Data具有允许 Core Data 执行此操作的 API?

我所做的更多细节:

  1. File创建一个只有两个属性的实体:(fileName字符串)和data(数据)。

在此输入图像描述

  1. 检查Allows External Storage属性的属性data
  2. 在实体中存储了 2 GB 文件File。我将此代码放入viewDidLoad方法中来执行此操作。

    do {
        // Store file
        let fileURL = Bundle.main.url(forResource: "RawData/LargeFile", withExtension: nil)!
        let file = File(context: AppDelegate.viewContext)
        file.name = fileName
        file.data = try Data(contentsOf: fileURL)
        try AppDelegate.viewContext.save()
    
    } catch {
        print(error.localizedDescription)
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 关闭应用程序,然后使用新代码重新启动它,以viewDidLoad获取和处理大文件的数据。

    let fileData = File.files(named: name).first!.data!
    DispatchQueue.global(qos: .userInteractive).async {
        let result = self.process(data: fileData)
        print("The result: \(result)") 
    }
    
    Run Code Online (Sandbox Code Playgroud)
    • filesFile 类的静态方法返回 File 实体中的所有文件。

    这里是 process 方法,它逐字节循环数据,读取和异或,然后返回结果。它实际上可以是任何方法,这里重要的是读取数据的所有字节。

    private func process(data: Data) -> UInt8 {
        print("Processsing \(data.count) bytes")
        var accumulator: UInt8 = 0
        for byte in data {
            accumulator ^= byte
        }
        return accumulator
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 我监控了内存使用情况。

我很确定它与 Core Data 有关,而不是因为从磁盘 ( )Data加载时执行相同的步骤将导致 3+ GB 内存使用(另外,为什么要额外使用 1 GB?)。dataData(contentsOf: URL)

最后,是否有任何理由不使用该Allows External Storage功能,而是手动将文件存储在文件系统中?我知道这个问题已经被讨论过很多次了;但我读到的大多数建议使用手动方式的观点都提到了 Core Data 的性能问题,尽管我的小实验表明 Core Data 表现良好。

任何帮助,将不胜感激!

Jon*_*ose 2

一般来说,关系数据库不擅长存储和检索大量数据。任何大于一兆字节的内容都不应该存储在数据库中。核心数据使问题变得更糟。如果您直接访问数据库,则只能获取特定的列,但是当核心数据将行转换为对象,将列转换为属性时,您无法控制所获取的内容。当您将属性设置为Allows External StorageCore-data 时,会将大量数据存储在文件系统中,并且仅在您访问该属性时加载它。这对于许多情况来说都很棒,因为它很简单并且可以极大地提高性能。

问题在于,访问此类属性可能会产生加载大文件的巨大意外成本,而仅访问属性并不清楚该成本。相反,如果您存储了文件名并明确执行了从磁盘加载文件的第二步,那么加载数据时就会很清楚。另外,如果可以从互联网恢复这些数据(例如,它们是从 imageURL 下载的图像),那么最好在核心数据之外管理该数据,因为您可以管理缓存,而这在核心数据中很难做到。