CSVImporter 1.9.1

CSVImporter 1.9.1

测试已测试
语言语言 SwiftSwift
许可协议 MIT
发布最新版本2018年11月
SPM支持 SPM

Cihat Gündüz 维护。



  • 作者:
  • Cihat Gündüz

Build Status Codebeat Status Version: 1.9.1 Swift: 4.2 Platforms: iOS | tvOS | macOS | Linux License: MIT

安装使用问题贡献许可协议

CSVImporter

轻松逐行导入 CSV 文件。

理由

“为什么还需要另一个 CSVImporter?”你可能问。“已经有 SwiftCSVCSwiftV 了,”你可能会说。事实是,这些框架对 较小的 CSV 文件 工作得很好。但是一旦你有一个真正 大的 CSV 文件(或者 可能 会这样,因为你可以允许用户导入他们想要的任何 CSV 文件),那么这些解决方案可能会给一些用户带来 延迟和内存问题

另一方面,CSVImporter 同时支持 异步操作(防止延迟)并且是逐行读取您的 CSV 文件(防止内存问题)。除此之外,它使用简单,并提供漂亮的回调,以指示失败、进度、完成,甚至如果你希望的话,还可以进行 数据处理

安装

目前推荐通过在 macOS 上使用 Carthage 或在 Linux 上使用 Swift Package Manager 来安装此库。《CocoaPods》可能也可以工作,但尚未经过测试。

当然,您也可以通过下载或使用 git 子模块将此框架手动包含到项目中。

使用方法

请查看 UsageExamples.playground 和 Tests/CSVImporterTests/CSVImporterSpec.swift 文件以获取提供的完整功能列表。要运行它,请从 .xcworkspace 内打开 Playground。

基本 CSV 导入

首先创建一个 CSVImporter 实例,并指定 CSV 行内数据的类型。默认数据类型是 String 对象的数组,看起来像这样

let path = "path/to/your/CSV/file"
let importer = CSVImporter<[String]>(path: path)
importer.startImportingRecords { $0 }.onFinish { importedRecords in
    for record in importedRecords {
        // record is of type [String] and contains all data in a line
    }
}

注意,在创建 CSVImporter 对象时,您可以在路径旁指定一个 **替代分隔符**。如果没有指定,则默认为 ,

异步与回调

CSVImporter 默认使用异步工作,因此不会阻塞主线程。如您所见,当完成导入后,将调用 onFinish 方法使用结果。还有针对失败情况的 onFail(例如,当给定的路径不包含 CSV 文件时),onProgress 会定期调用并提供已处理的行数(例如,用于进度指示器)。您可以像以下这样连锁调用它们

importer.startImportingRecords { $0 }.onFail {

    print("The CSV file couldn't be read.")

}.onProgress { importedDataLinesCount in

    print("\(importedDataLinesCount) lines were already imported.")

}.onFinish { importedRecords in

    print("Did finish import with \(importedRecords.count) records.")

}

默认情况下,实际导入工作在 .utility 全球后台队列中完成,回调在 main 队列中调用。这样,繁重的工作是异步完成的,但回调允许您更新界面。如果您需要不同的行为,您可以在创建 CSVImporter 对象时自定义队列,如下所示

let path = "path/to/your/CSV/file"
let importer = CSVImporter<[String]>(path: path, workQosClass: .background, callbacksQosClass: .utility)

异步导入

如果知道文件足够小或者阻塞UI不是问题,也可以使用同步导入方法来导入数据。只需调用 importRecords 而不是 startImportingRecords,你将直接收到最终结果(与使用 startImportingRecords 时在 onFinish 闭包中相同的 uygulama内内容)。

let importedRecords = importer.importRecords { $0 }

注意,此方法没有任何选项可以通知进度或失败 - 你只得到结果。检查结果数组是否为空以识别潜在失败。

简单的数据映射

如上所述,默认类型为 [String],但您可以提供所需的任何类型。例如,假设您有一个这样的类

class Student {
  let firstName: String, lastName: String
  init(firstName: String, lastName: String) {
    self.firstName = firstName
    self.lastName = lastName
  }
}

而且您的CSV文件看起来像下面这样

Harry,Potter
Hermione,Granger
Ron,Weasley

然后您可以将映射器指定为闭包而不是上面的例子中的 { $0 },如下所示

let path = "path/to/Hogwarts/students"
let importer = CSVImporter<Student>(path: path)
importer.startImportingRecords { recordValues -> Student in

    return Student(firstName: recordValues[0], lastName: recordValues[1])

}.onFinish { importedRecords in

    for student in importedRecords {
        // Now importedRecords is an array of Students
    }

}

头结构支持

最后但并非最不重要的是,一些CSV文件的数据结构在第一行中指定,如下所示

firstName,lastName
Harry,Potter
Hermione,Granger
Ron,Weasley

在这种情况下,CSV导入器可以自动将每个记录作为一个字典提供,如下所示

let path = "path/to/Hogwarts/students"
let importer = CSVImporter<[String: String]>(path: path)
importer.startImportingRecords(structure: { (headerValues) -> Void in

    print(headerValues) // => ["firstName", "lastName"]

}) { $0 }.onFinish { importedRecords in

    for record in importedRecords {
        print(record) // => e.g. ["firstName": "Harry", "lastName": "Potter"]
        print(record["firstName"]) // prints "Harry" on first, "Hermione" on second run
        print(record["lastName"]) // prints "Potter" on first, "Granger" on second run
    }

}

注意:如果记录值计数与第一行值计数不匹配,则记录将被忽略。

贡献

请参阅文件 CONTRIBUTING.md

许可证

本库采用MIT 许可证发布。详见 LICENSE 文件获取详细信息。