csv4cj 库
介绍
csv 文件的仓颉操作工具,支持 csv 文件的读写、解析,支持中文。
1 仓颉语言支持 csv 文件的读取、解析
场景:
- OHOS, Linux, windows平台下可读取和解析csv 文件,支持中文
- 支持对 csv 文件格式的配置 约束: 性能:支持版本几何性能持平 可靠性: NA
1.1 csv支持不同格式的解析
CSV内容解析格式
1.1.1 主要接口
public class CSVParseFormat {
/*
* 默认的解析格式
*/
public static prop let DEFAULT: CSVParseFormat
/*
* 设置解析格式的转义字符
*
* 参数 escapeCharacter - 转义字符
*
* 返回值 CSVParseFormat- 返回对象本身
*/
public func setEscapeCharacter(escapeCharacter: Rune): CSVParseFormat
/*
* 读取解析格式的转义字符
*
* 返回值 Rune - 解析格式的转义字符
*/
public func getEscapeCharacter(): Rune
/*
* 设置是否将第一行做为标题行
*
* 参数 firstLineAsHeader - 是否第一行将第一行做为标题行
*
* 返回值 CSVParseFormat- 返回对象本身
*/
public func setFirstLineAsHeader(firstLineAsHeader: Bool): CSVParseFormat
/*
* 读取是否将第一行做为标题行的设置
*
* 返回值 Bool - 是否将第一行做为标题行
*/
public func getFirstLineAsHeader(): Bool
/*
* 设置解析格式的列标题
*
* 参数 headerList - 表示列标题的集合
*
* 返回值 CSVParseFormat- 返回对象本身
*/
public func setHeader(headerList: Collection<String>): CSVParseFormat
/*
* 读取解析格式的列标题数组
*
* 返回值 ArrayList<String> - 解析格式的列标题数组
*/
public func getHeader(): ArrayList<String>
/*
* 设置是否忽略空行
*
* 参数 ignoreEmptyLines - 是否忽略空行
*
* 返回值 CSVParseFormat- 返回对象本身
*/
public func setIgnoreEmptyLines(ignoreEmptyLines: Bool): CSVParseFormat
/*
* 读取是否忽略空行的设置
*
* 返回值 Bool - 返回是否忽略空行的设置
*/
public func getIgnoreEmptyLines(): Bool
/*
* 设置是否忽略内容前后的空白字符
*
* 参数 ignoreSurroundingSpaces - 是否忽略内容前后的空白字符
*
* 返回值 CSVParseFormat- 返回对象本身
*/
public func setIgnoreSurroundingSpaces(ignoreSurroundingSpaces: Bool): CSVParseFormat
/*
* 读取是否忽略内容前后的空白字符设置
*
* 返回值 Bool - 是否忽略内容前后的空白字符的设置
*/
public func getIgnoreSurroundingSpaces(): Bool
/*
* 设置解析格式的引用字符
*
* 参数 quoteCharacter - 引用字符
*
* 返回值 CSVParseFormat- 返回对象本身
*/
public func setQuoteCharacter(quoteCharacter: Rune)
/*
* 读取解析格式的引用字符
*
* 返回值 Rune - 解析格式的引用字符
*/
public func getQuoteCharacter(): Rune
/*
* 设置是否跳过标题行
*
* 参数 skipHeaderRecord - 是否跳过标题行
*
* 返回值 CSVParseFormat- 返回对象本身
*/
public func setSkipHeaderRecord(skipHeaderRecord: Bool): CSVParseFormat
/*
* 读取是否跳过标题行设置
*
* 返回值 Bool - 是否跳过标题行的设置
*/
public func getSkipHeaderRecord(): Bool
/*
* 设置是否去除尾部分隔符
*
* 参数 trailingDelimiter - 是否去除尾部分隔符
*
* 返回值 CSVParseFormat- 返回对象本身
*/
public func setTrailingDelimiter(trailingDelimiter: Bool): CSVParseFormat
/*
* 读取是否去除尾部分隔符的设置
*
* 返回值 Bool - 是否去除尾部分隔符的设置
*/
public func getTrailingDelimiter(): Bool
/*
* 设置解析格式的分隔符
*
* 参数 delimiter - 分隔符
*
* 返回值 CSVParseFormat- 返回对象本身
*/
public func setDelimiter(delimiter: String): CSVParseFormat
/*
* 读取解析格式的分隔符
*
* 返回值 String - 解析格式的分隔符
*/
public func getDelimiterString(): String
/*
* 设置解析格式的注释符
*
* 参数 commentMarker - 注释符
*
* 返回值 CSVParseFormat- 返回对象本身
*/
public func setCommentMarker(commentMarker: Rune): CSVParseFormat
/*
* 读取解析格式的注释符
*
* 返回值 Rune - 解析格式的注释符
*/
public func getCommentMarker(): Rune
}
/*
* 判断当前 Option<T> 是否无值
*
* 参数 item - Option 值
*
* 返回值 Bool - Option 无值返回 true 否则返回 false
*/
public func isNone<T>(item: Option<T>): Bool
/*
* 判断当前 Option<T> 是否有值
*
* 参数 item - Option 值
*
* 返回值 Bool - Option 有值返回 true 否则返回 false
*/
public func isSome<T>(item: Option<T>): Bool
1.1.2 示例
import std.collection.*
import csv4cj.*
main() {
let x: Rune = '|'
let f: CSVParseFormat = CSVParseFormat.DEFAULT.setEscapeCharacter(x)
println("${f.getEscapeCharacter()}")
let h: Array<String> = ["hello"]
f.setHeader(h)
println("${f.getHeader().toString()}")
f.setIgnoreEmptyLines(true)
println("${f.getIgnoreEmptyLines()}")
f.setIgnoreSurroundingSpaces(true)
println("${f.getIgnoreSurroundingSpaces()}")
let c: Rune = '"'
f.setQuoteCharacter(c)
println("${f.getQuoteCharacter().toString()}")
f.setTrailingDelimiter(true)
println("${f.getTrailingDelimiter()}")
let c1: Rune = '#'
f.setCommentMarker(c1)
println("${f.getCommentMarker().toString()}")
f.setDelimiter("---")
println("${f.getDelimiterString()}")
return 0
}
1.2 CSV解析器
1.2.1 主要接口
public class CSVParser <: Iterable<CSVRecord> {
/*
* 主构造函数
*
* 参数 reader - csv内容读取对象
* 参数 format - 内容解析配置
*/
public CSVParser(reader: CSVReader, format: CSVParseFormat)
/*
* 解析下一条记录, 解析失败则抛 Exception 异常
*
* 返回值 :Option<CSVRecord> - 下一条记录
*/
public func nextRecord(): Option<CSVRecord>
/*
* 获取标题和序号的HashMap,其中key为标题,value为序号
*
* 返回值 :HashMap<String, Int64> - 标题的HashMap
*/
public func getHeaderDict(): HashMap<String, Int64>
/*
* 获取标题的注释列表
*
* 返回值 :ArrayList<String> - 标题的注释列表
*/
public func getHeaderComment(): ArrayList<String>
/*
* 获取当前解析的行序号
*
* 返回值 :Int64- 行序号
*/
public func getCurrentLineNumber(): Int64
/*
* 获取行的迭代器
*
* 返回值 :Iterator<CSVRecord>- 行迭代器
*/
public func iterator(): Iterator<CSVRecord>
/*
* 获取解析后的CSVRecord对象列表
*
* 返回值 :ArrayList<CSVRecord>- 解析后的CSVRecord对象列表
*/
public func getRecords(): ArrayList<CSVRecord>
/*
* 解析当前所有记录
*
* 返回值 :ArrayList<CSVRecord>- 解析后的CSVRecord对象列表
*/
public func parseRecordsToEnd(): ArrayList<CSVRecord>
}
/*
* 定义 Constants 常量类
*/
public class Constants{
// 反斜线
public static let BACKSLASH: Rune
// 退格
public static let BACKSPACE: Rune
// 逗号
public static let COMMA: Rune
// 井号
public static let COMMENT_CHAR: Rune
// 回车
public static let CR: Rune
// 换行
public static let LF: Rune
//双引号
public static let DOUBLE_QUOTE_CHAR: Rune
// 换页
public static let FF: Rune
// 空格
public static let SP: Rune
// 制表符
public static let TAB: Rune
// 空字符
public static let DISABLED: Rune: Rune
// 管道符号
public static let PIPE: Rune
//记录分隔符
public static let RS: Rune
// 回车换行字符串
public static let CRLF: String
// 换行字符串
public static let LF_STRING: String
// 逗号字符串
public static let COMMA_STRING: String
// 回车字符串
public static let CR_STRING: String
// 空字符串
public static let EMPTY: String
}
1.2.2 示例
示例 test.csv 文件如下:
id,name,age,remark
30020,biboo,28,middle school student
30021,张飞,45,三国演义男4号𥻗𪧘
#这是第3行的注释,里面有转义的tab键和引用符号
30022,关\t羽,48,著名的武财神αβγ
30023,刘备,50,"胳膊比较长,善于编草鞋"
示例代码如下:
import std.fs.*
import stdx.serialization.serialization.*
import stdx.encoding.json.*
import std.collection.*
import std.posix.*
import csv4cj.*
main() {
let path: String = getcwd()
println("自定义输出:")
customPrintingDemo("${path}/test.csv")
parseRecordsToEnd()
return 0
}
func parseRecordsToEnd(): Unit {
let csvContent =
###"Dan Simmons,Hyperion,"1989"
# Comment Line 1
# Comment Line 2
# Comment Line 3
Douglas Adams,The Hitchhiker's "Guide" to the Galaxy,1979
Douglas John,The Hitchhiker's "Guide" to the Mars,1979"###
let format = CSVParseFormat.DEFAULT
let csvReader = CSVReader(StringStream(csvContent))
let csvParser = CSVParser(csvReader, format)
var csvRecordList = csvParser.parseRecordsToEnd()
}
//自定义输出格式
func customPrintingDemo(fileName: String) {
//创建文件
let fileStream = File(fileName, OpenMode.Read)
if (fileStream.canRead()) {
//创建字符读取的解析流
let stream = UTF8ReaderStream(fileStream)
let reader = CSVReader(stream)
//创建格式化的解析参数
let format: CSVParseFormat = CSVParseFormat.DEFAULT.setSkipHeaderRecord(true).setFirstLineAsHeader(false)
//创建解析器
let csvParser = CSVParser(reader, format)
println(csvParser.getHeaderComment().toString())
println(csvParser.getCurrentLineNumber())
//遍历每一行解析记录
for (csvRecord in csvParser) {
let rowNo = csvRecord.getRecordNumber()
//使用表头标题获取对应列的值
let id = csvRecord.get("id", csvParser.getHeaderDict()) ?? ""
let name = csvRecord.get("name", csvParser.getHeaderDict()) ?? ""
//使用列序号获取对应列的值
let age = csvRecord.get(2)
let remark = csvRecord.get(3)
if (let Some(comment) = csvRecord.getComment()) {
println("RowNo:${rowNo}|Id:${id}|name:${name}|age:${age}|remark:${remark}|comment:${comment}")
} else {
println("RowNo:${rowNo}|Id:${id}|name:${name}|age:${age}|remark:${remark}")
}
}
fileStream.close()
}
}
1.3 csv逐行解析
读取CSV内容的类
1.3.1 主要接口
public class CSVReader{
/*
* 构造函数
*
* 参数 reader - 实现了CharReader接口的按字符读取对象
*/
public init(reader: CharReader)
/*
* 获取最后读取的字符
*
* 返回值 :Option<Rune> - 最后读取的字符
*/
public func getLastChar(): Option<Rune>
/*
* 是否到了流的结束位置
*
* 返回值 :Bool - 是否是流的结束位置
*/
public func getIsEndOfStream(): Bool
/*
* 获取当前行号
* 当未开始读取内容或者开始读取但是内容为空,返回0
* 当开始读取第一行内容并且内容不为空时,返回1
* 当读取完第一行的换行或者回车换行时,返回1
* 当开始读取第二行并且读取到内容时,返回2,以此类推
* 调用readLine函数不影响行号,该函数主要用来读取注释使用
* 返回值 :Int64 - 当前行号
*/
public func getCurrentLineNumber(): Int64
/*
* 读取下一个字符
*
* 返回值 :Option<Rune> - 下一个字符
*/
public func read(): Option<Rune>
/*
* 读取后面的字符到字符数组buf,最大读取字符数量为buf的size
*
* 参数 buf - 存储读取内容的字符数组
*
* 返回值 :Int64 - 成功读取的字符数
*/
public func read(buf: Array<Rune>): Int64
/*
* 读取后面的字符到字符数组buf,最大读取字符数量为count,存储到buf时,从offset位置开始
*
* 参数 buf - 存储读取内容的字符数组
* 参数 offset - buf开始存储读取内容的位置
* 参数 count - 最大读取字符数量
*
* 返回值 :Int64 - 成功读取的字符数
*/
public func read(buf: Array<Rune>, offset: Int64, count: Int64): Int64
/*
* 读取一行
*
* 返回值 :Option<String> - 读取的内容
*/
public func readLine(): Option<String>
/*
* 读取后面的字符到字符数组buf,最大读取字符数量为buf的size,本次读取不改变流的当前位置
*
* 返回值 :Int64 - 成功读取的字符数
*/
public func lookAhead(buf: Array<Rune>): Int64
/*
* 查看下一个字符,该动作不会改变要读取的流的当前位置
*
* 返回值 :Option<Rune> - 要读取的下一个字符
*/
public func lookAhead(): Option<Rune>
}
/*
* 定义 CharReader 接口
*/
public interface CharReader {
/*
* 读取一个字符,该动作将会改变要读取的流的当前位置
*
* 返回值 Option<Rune> - 读取的字符
*/
func read(): Option<Rune>
/*
* 读取后面的字符到字符数组buf,读取的最大数量为buf的size
* 该动作不会改变要读取的流的当前位置
*
* 参数 buf - 存储读取出字符的字符数组对象
*
* 返回值 Int64 - 成功读取的字符数量
*/
func lookAhead(buf: Array<Rune>): Int64
/*
* 查看下一个字符
* 该动作不会改变要读取的流的当前位置
*
* 返回值 Option<Rune> - 要读取的下一个字符
*/
func lookAhead(): Option<Rune>
}
/*
* 从字符串中读取字符的类,该类实现了CharReader接口
*/
public class StringStream <: CharReader {
/*
* 主构造函数
*
* 参数 value - 要读取的字符串
*/
public StringStream(value: String)
/*
* 从字符串读取下一个字符
*
* 返回值 Option<Rune> - 读取的字符
*/
public func read(): Option<Rune>
/*
* 从字符串读取后面的字符到字符数组buf,读取的最大数量为buf的size
* 该动作不会改变要读取的字符串的当前位置
*
* 参数 buf - 存储读取出字符的字符数组对象
*
* 返回值 Int64 - 成功读取的字符数量
*/
public func lookAhead(buf: Array<Rune>): Int64
/*
* 查看下一个字符
* 该动作不会改变要读取的字符串的当前位置
*
* 返回值 Option<Rune> - 要读取的下一个字符
*/
public func lookAhead(): Option<Rune>
}
1.3.2 示例
示例 test.csv 文件如下:
id,name,age,remark
30020,biboo,28,middle school student
30021,张飞,45,三国演义男4号𥻗𪧘
#这是第3行的注释,里面有转义的tab键和引用符号
30022,关\t羽,48,著名的武财神αβγ
30023,刘备,50,"胳膊比较长,善于编草鞋"
示例代码如下:
import std.fs.*
import std.collection.*
import std.posix.*
import csv4cj.*
main() {
let path: String = getcwd()
let fileStream = File("${path}/test.csv", OpenMode.Read)
if (fileStream.canRead()) {
let s = UTF8ReaderStream(fileStream)
let r = CSVReader(s)
var arr: Array<Rune> = Array<Rune>(1024, item: Rune(0))
println(r.read(arr, 0, 10))
r.getCurrentLineNumber()
println(r.getIsEndOfStream())
fileStream.close()
}
testReadLine()
return 0
}
func testReadLine(): Unit {
var content = ""
var readerStream = StringStream(content)
var reader = CSVReader(readerStream)
var line = reader.readLine()
if (isNone(line)) {
println("none")
}
println(isReadLineMatch("abc", "abc"))
println(isReadLineMatch("你好\n仓颉", "你好"))
println(isReadLineMatch("cangjie\r仓颉", "cangjie"))
println(isReadLineMatch("Hello\r\n仓颉", "Hello"))
}
func isReadLineMatch(content: String, matchValue: String): Bool {
var readerStream = StringStream(content)
var reader = CSVReader(readerStream)
var line = reader.readLine()
if (let Some(value) = line) {
return value == matchValue
}
return false
}
1.4 中文支持
使用UTF8编码进行内容读取的类,调用方需要保证文件的正确编码格式,否则可能得不到期望的解析结果
1.4.1 主要接口
public class UTF8ReaderStream <: CharReader{
/*
* 构造函数
*
* 参数 s - 要读取的文件,调用方需要保证文件的正确编码格式,否则可能得不到期望的解析结果
*/
public init(s: File)
/*
* 读取下一个字符
*
* 返回值 :Option<Rune> - 下一个字符
*/
public func read(): Option<Rune>
/*
* 读取后面的字符到字符数组buf,最大读取字符数量为buf的size,本次读取不改变流的当前位置
*
* 返回值 :Int64 - 成功读取的字符数
*/
public func lookAhead(buf: Array<Rune>): Int64
/*
* 查看下一个字符,该动作不会改变要读取的流的当前位置
*
* 返回值 :Option<Rune> - 要读取的下一个字符
*/
public func lookAhead(): Option<Rune>
}
1.4.2 示例
示例 test.csv 文件如下:
id,name,age,remark
30020,biboo,28,middle school student
30021,张飞,45,三国演义男4号𥻗𪧘
#这是第3行的注释,里面有转义的tab键和引用符号
30022,关\t羽,48,著名的武财神αβγ
30023,刘备,50,"胳膊比较长,善于编草鞋"
示例代码如下:
import std.fs.*
import std.collection.*
import std.posix.*
import csv4cj.*
main() {
let path: String = getcwd()
let fileStream = File("${path}/test.csv", OpenMode.Read)
if (fileStream.canRead()) {
let s = UTF8ReaderStream(fileStream)
s.lookAhead(Array<Rune>(1024,item:Rune(0)))
let format = CSVParseFormat.DEFAULT
let csvReader = CSVReader(s)
let csvParser = CSVParser(csvReader, format)
var csvRecord = csvParser.nextRecord()
let outFormat = CSVOutFormat.DEFAULT.setQuoteMode(QuoteMode.None)
let csvPrint = CSVPrinter(outFormat)
let sb = StringBuilder()
if (let Some(record) = csvRecord) {
csvPrint.print(record, sb)
csvRecord = csvParser.nextRecord()
}
fileStream.close()
}
return 0
}
2 仓颉语言支持将结构化的csv数据输出成cvs文件
场景:
- OHOS, Linux, windows平台下支持将结构化的 csv 记录输出 csv 文件,支持中文 约束:
- 性能:支持版本几何性能持平 可靠性: NA
2.1 CSV输出格式
2.1.1 主要接口
public class CSVOutFormat {
/*
* 默认的输出格式
*/
public static prop let DEFAULT: CSVOutFormat
/*
* 设置输出格式的转义字符
*
* 参数 escapeCharacter - 转义字符
*
* 返回值 CSVOutFormat - 返回对象本身
*/
public func setEscapeCharacter(escapeCharacter: Rune): CSVOutFormat
/*
* 读取输出格式的转义字符
*
* 返回值 Rune - 输出格式的转义字符
*/
public func getEscapeCharacter(): Rune
/*
* 设置输出格式的列标题
*
* 参数 headerList - 表示列标题的数组
*
* 返回值 CSVOutFormat - 返回对象本身
*/
public func setHeader(headerList: Array<String>): CSVOutFormat
/*
* 读取输出格式的列标题数组
*
* 返回值 Array<String> - 输出格式的列标题数组
*/
public func getHeader(): Array<String>
/*
* 设置是否忽略空行
*
* 参数 ignoreEmptyRecord - 是否忽略空行
*
* 返回值 CSVOutFormat - 返回对象本身
*/
public func setIgnoreEmptyRecord(ignoreEmptyRecord: Bool): CSVOutFormat
/*
* 读取是否忽略空行的设置
*
* 返回值 Bool - 返回是否忽略空行的设置
*/
public func getIgnoreEmptyRecord(): Bool
/*
* 设置是否忽略内容前后的空白字符
*
* 参数 trim - 是否忽略内容前后的空白字符
*
* 返回值 CSVOutFormat - 返回对象本身
*/
public func setTrim(trim: Bool): CSVOutFormat
/*
* 读取是否忽略内容前后的空白字符设置
*
* 返回值 Bool - 是否忽略内容前后的空白字符的设置
*/
public func getTrim(): Bool
/*
* 设置输出格式的引用字符
*
* 参数 quoteCharacter - 引用字符
*
* 返回值 CSVOutFormat - 返回对象本身
*/
public func setQuoteCharacter(quoteCharacter: Rune)
/*
* 读取输出格式的引用字符
*
* 返回值 Rune - 输出格式的引用字符
*/
public func getQuoteCharacter(): Rune
/*
* 设置输出格式的列值引用模式
*
* 参数 quoteMode - 引用模式
*
* 返回值 CSVOutFormat - 返回对象本身
*/
public func setQuoteMode(quoteMode: QuoteMode): CSVOutFormat
/*
* 读取输出格式的列值引用模式
*
* 返回值 QuoteMode - 输出格式的列值引用模式
*/
public func getQuoteMode(): QuoteMode
/*
* 设置输出格式的分隔符
*
* 参数 delimiter - 分隔符
*
* 返回值 CSVOutFormat - 返回对象本身
*/
public func setDelimiter(delimiter: String): CSVOutFormat
/*
* 读取输出格式的分隔符
*
* 返回值 String - 输出格式的分隔符
*/
public func getDelimiterString(): String
/*
* 设置输出格式的注释符
*
* 参数 commentMarker - 注释符
*
* 返回值 CSVOutFormat - 返回对象本身
*/
public func setCommentMarker(commentMarker: Rune): CSVOutFormat
/*
* 读取输出格式的注释符
*
* 返回值 Rune - 输出格式的注释符
*/
public func getCommentMarker(): Rune
/*
* 读取记录分隔标志,一般是回车换行
*
* 返回值 String - 记录分隔标志
*/
public func getRecordSeparator(): String
/*
* 设置使用引用模式的列的序号数组
*
* 参数 quotedColsIndex - 使用引用模式的列的序号数组
*
* 返回值 CSVOutFormat - 返回对象本身
*/
public func setQuotedColsIndex(quotedColsIndex: Array<Int64>): CSVOutFormat
/*
* 读取使用引用模式的列的序号数组
*
* 返回值 Array<Int64> - 使用引用模式的列的序号数组
*/
public func getQuotedColsIndex(): Array<Int64>
}
/*
* 列值的引用模式枚举
*/
public enum QuoteMode {
// 引用所有列
All |
// 引用指定的列
CfgCols |
// 引用包含特殊字符的列
SpecialValue |
//不引用,如果有特殊字符就转义
None
}
2.1.2 示例
import std.collection.*
import csv4cj.*
main() {
let x: Rune = '|'
let f: CSVOutFormat = CSVOutFormat.DEFAULT.setEscapeCharacter(x)
println("${f.getEscapeCharacter()}")
let h: Array<String> = ["hello"]
f.setHeader(h)
println("${f.getHeader().toString()}")
f.setIgnoreEmptyRecord(true)
println("${f.getIgnoreEmptyRecord()}")
let c: Rune = '"'
f.setQuoteCharacter(c)
println("${f.getQuoteCharacter().toString()}")
f.setTrim(true)
println("${f.getTrim()}")
let c1: Rune = '#'
f.setCommentMarker(c1)
println("${f.getCommentMarker().toString()}")
f.setDelimiter("---")
println("${f.getDelimiterString()}")
let a: Array<Int64> = [1,2]
f.setQuotedColsIndex(a)
println("${f.getQuotedColsIndex().toString()}")
let q: QuoteMode = CfgCols
f.setQuoteMode(q)
return 0
}
2.2 将解析出的csv结果转为json
CSV记录
2.2.1 主要接口
public class CSVRecord <: Iterable<String> & Serializable<CSVRecord> {
/*
* 构造函数
*
* 参数 values - 列值数组
* 参数 comment - 注释
*/
public init(values: Array<String>, comment: Option<String>)
/*
* 构造函数
*
* 参数 values - 列值列表
* 参数 comment - 注释
*/
public init(values: ArrayList<String>, comment: Option<String>)
/*
* 构造函数
*
* 参数 values - 列值数组
*/
public init(values: Array<String>)
/*
* 构造函数
*
* 参数 values - 列值列表
*/
public init(values: ArrayList<String>)
/*
* 构造函数
*/
public init()
/*
* 获取给定序号对应的列值
*
* 参数 index - 列序号
*
* 返回值 :String- 给定序号对应的列值
*/
public func get(index: Int64):String
/*
* 获取给定类标题对应的列值
*
* 参数 header - 列标题
* 参数 headerDict - 列标题和列序号组成的字典
*
* 返回值 :String- 给定列标题对应的列值
*/
public func get(header: String, headerDict: HashMap<String, Int64>):String
/*
* 获取列值迭代器
*
* 返回值 Iterator<String> - 迭代器
*/
public func iterator(): Iterator<String>
/*
* 获取行序号,当行序号没有设置时返回1
*
* 返回值 Int64 - 行序号
*/
public func getRecordNumber():Int64
/*
* 获取注释
*
* 返回值 String - 注释
*/
public func getComment(): Option<String>
/*
* 获取记录列的数量
*
* 返回值 :Int64 - 列的数量
*/
public func size():Int64
/*
* 获取记录的列值字符串列表
*
* 返回值 :Array<String> - 列值字符串列表
*/
public func getValues(): Array<String>
/*
* 记录序列化
*
* 返回值 :DataModel - 序列化后的对象
*/
public func serialize(): DataModel
/*
* 对给定的对象反序列化得到CSVRecord对象,参数不是 DataModelStruct 类型抛 Exception 异常
*
* 参数 dm - 反序列对象
*
* 返回值 CSVRecord- 反序列化得到的CSVRecord对象
*/
static public func deserialize(dm: DataModel): CSVRecord
}
2.2.2 示例
import stdx.serialization.serialization.*
import stdx.encoding.json.*
import std.collection.*
import std.posix.*
import csv4cj.*
main() {
testInit()
testSerializeDeserialize()
return 0
}
func testInit(): Unit {
var csvRecord = CSVRecord()
let values = ["1", "a", "cangjie", "开发"]
csvRecord = CSVRecord(values)
let valueList = ArrayList<String>(values)
csvRecord = CSVRecord(valueList)
csvRecord = CSVRecord(valueList,"")
csvRecord.size()
csvRecord.iterator()
}
func testSerializeDeserialize(): Unit {
var csvRecord = CSVRecord(["1", "a", "cangjie", "开发"], "注释")
let josnValue = csvRecord.serialize().toJson()
let jsonString = josnValue.toJsonString()
let newRecord = CSVRecord.deserialize(DataModel.fromJson(josnValue))
}
2.3 CSV格式的输出对象
CSV格式的输出对象
2.3.1 主要接口
public class CSVPrinter {
/*
* 主构造函数
*
* 参数 format - 内容输出配置
*/
public CSVPrinter(format: CSVOutFormat)
/*
* 输出记录到out对象
*
* 参数 csvRecord - 要输出的记录
* 参数 out - 输出的目的对象
*/
public func print(csvRecord: CSVRecord, out: Appendable): Unit
/*
* 输出记录到out对象,包括注释
*
* 参数 csvRecord - 要输出的记录
* 参数 out - 输出的目的对象
*/
public func printWithComment(csvRecord: CSVRecord, out: Appendable): Unit
/*
* 输出配置的标题行到out对象
*
* 参数 out - 输出的目的对象
*/
public func printHeader(out: Appendable): Unit
/*
* 输出注释到out对象
*
* 参数 comment - 要输出的注释
* 参数 out - 输出的目的对象
*/
public func printComment(comment: Option<String>, out: Appendable): Unit
/*
* 输出回车换行到out对象
*
* 参数 out - 输出的目的对象
*/
public func printLine(out: Appendable): Any
/*
* 输出values和回车换行到out对象
*
* 参数 values - 要输出的列表对象
* 参数 out - 输出的目的对象
*/
public func printLine(values: Iterable<String>, out: Appendable): Unit
/*
* 输出values到out对象
*
* 参数 values - 要输出的列表对象
* 参数 out - 输出的目的对象
*/
public func print(values: Iterable<String>, out: Appendable): Unit
}
/*
* 定义 Appendable 接口
*/
public interface Appendable {
/*
* 把字符串str写入或者追加到末尾,由具体实现决定
*
* 参数 str - 要追加的字符串
*
* 返回值 Any - 返回对象本身
*/
func append(str: String): Any
/*
* 把字符chr写入或者追加到末尾,由具体实现决定
*
* 参数 chr - 要追加的字符
*
* 返回值 Any - 返回对象本身
*/
func append(chr: Rune): Any
}
/*
*为 StringBuilder 扩展 Appendable 接口
*/
extend StringBuilder <: Appendable {}
/*
*为 Console 扩展 Appendable 接口
*/
extend Console <: Appendable {
/*
* 输出字符串str到控制台
*
* 参数 str - 要输出的字符串
*
* 返回值 Console - 返回对象本身
*/
public func append(str: String) :Console
/*
* 输出字符chr到控制台
*
* 参数 chr - 要输出的字符
*
* 返回值 Console - 返回对象本身
*/
public func append(chr: Rune) :Console
}
2.3.2 示例
import stdx.serialization.serialization.*
import stdx.encoding.json.*
import std.collection.*
import std.io.*
import std.posix.*
import csv4cj.*
main() {
println("Csv输出:")
csvPrint()
printHeader()
printSpecialCols()
PrintWithNoneMode()
printWithComment()
return 0
}
public func printWithComment(): Unit {
let csvRecord = CSVRecord(["1", "taobao", "小米", "200斤"], "注释\r\n第二行")
let format = CSVOutFormat.DEFAULT
let csvPrint = CSVPrinter(format)
let sb = StringBuilder()
csvPrint.printWithComment(csvRecord, sb)
}
func printHeader() {
let header = ["姓名", "年龄", "学号", "成绩"]
let outFormat = CSVOutFormat.DEFAULT.setHeader(header)
let csvPrint = CSVPrinter(outFormat)
let output = Console()
csvPrint.printHeader(output)
csvPrint.printLine(output)
csvPrint.printLine(["赵林", "15", "06", "89"], output)
csvPrint.printLine(["李帅", "16", "15", "92"], output)
csvPrint.print(["唐明", "15", "36", "61"], output)
}
func printSpecialCols(): Unit {
let format = CSVOutFormat.DEFAULT.setQuoteMode(QuoteMode.CfgCols).setQuotedColsIndex([1, 2])
let csvPrint = CSVPrinter(format)
let sb = StringBuilder()
csvPrint.print(["abc,", "1\\2,3", "a\tb", ","], sb)
}
func PrintWithNoneMode(): Unit {
let format = CSVOutFormat.DEFAULT.setQuoteMode(QuoteMode.None)
let csvPrint = CSVPrinter(format)
let sb = StringBuilder()
csvPrint.print(["abc", "a\r\nb\nc", "a\tb", ","], sb)
var csvRecord = CSVRecord(["1", "a", "cangjie", "开发"], "注释")
csvPrint.print(csvRecord, sb)
}
//按照csv格式输出
func csvPrint() {
let csvContent =
###"# Comment before header\\n
author,title,publishDate\\r
Dan Simmons|,Hyperion,"1989"
# Comment Line 1
# Comment Line 2|
# Comment Line 3|
Douglas ||Adams,The Hitchhiker's \"Guide\" to the Galaxy,1979
你好"###
//创建字符串流
let readerStream = StringStream(csvContent)
let reader = CSVReader(readerStream)
//创建格式化的解析参数
let format: CSVParseFormat = CSVParseFormat.DEFAULT
//创建解析器
let csvParser = CSVParser(reader, format)
let recordList = csvParser.getRecords()
let outFormat = CSVOutFormat.DEFAULT.setQuoteMode(All).setDelimiter("|")
let outFormat2 = CSVOutFormat.DEFAULT.setQuoteMode(QuoteMode.None).setDelimiter("||")
let sbOut = StringBuilder()
let csvPrint = CSVPrinter(outFormat)
let csvPrint2 = CSVPrinter(outFormat2)
var firstLine = true
//遍历每一行解析记录
for (csvRecord in recordList) {
if (firstLine) {
firstLine = false
csvPrint.print(csvRecord, sbOut)
csvPrint2.print(csvRecord, sbOut)
} else {
csvPrint.printLine(sbOut)
csvPrint2.printLine(sbOut)
csvPrint.print(csvRecord, sbOut)
csvPrint2.print(csvRecord, sbOut)
}
}
println(sbOut.toString())
}
示例:
示例 test.csv 文件如下:
id,name,age,remark
30020,biboo,28,middle school student
30021,张飞,45,三国演义男4号𥻗𪧘
#这是第3行的注释,里面有转义的tab键和引用符号
30022,关\t羽,48,著名的武财神αβγ
30023,刘备,50,"胳膊比较长,善于编草鞋"
示例 test_extra.csv 文件如下:
id𪧘𪧘name𪧘𪧘age𪧘𪧘remark
30020𪧘𪧘biboo𪧘𪧘28𪧘𪧘middle school student
α这是第3行的注释,里面有转义的tab键和引用符号
30022𪧘𪧘关\t羽𪧘𪧘 48 𪧘𪧘著名的武财神
示例代码如下:
import std.fs.*
import stdx.serialization.serialization.*
import stdx.encoding.json.*
import std.collection.*
import std.posix.*
import csv4cj.*
main() {
let path: String = getcwd()
if (path.isEmpty()) {
println("请指定要解析的文件路径")
return 1
}
println("自定义输出:")
customPrintingDemo("${path}/test.csv")
println("Json输出:")
serialPrintingDemo("${path}/test_extra.csv")
println("Csv输出:")
csvPrint()
return 0
}
//自定义输出格式
func customPrintingDemo(fileName: String) {
//创建文件流
let fileStream = File(fileName, OpenMode.Read)
if (fileStream.canRead()) {
//创建字符读取的解析流
let stream = UTF8ReaderStream(fileStream)
let reader = CSVReader(stream)
//创建格式化的解析参数
let format: CSVParseFormat = CSVParseFormat.DEFAULT.setSkipHeaderRecord(true).setFirstLineAsHeader(true)
//创建解析器
let csvParser = CSVParser(reader, format)
//遍历每一行解析记录
for (csvRecord in csvParser) {
let rowNo = csvRecord.getRecordNumber()
//使用表头标题获取对应列的值
let id = csvRecord.get("id",csvParser.getHeaderDict()) ?? ""
let name = csvRecord.get("name",csvParser.getHeaderDict()) ?? ""
//使用列序号获取对应列的值
let age = csvRecord.get(2)
let remark = csvRecord.get(3)
if (let Some(comment) = csvRecord.getComment()) {
println(
"RowNo:${rowNo}|Id:${id}|name:${name}|age:${age}|remark:${remark}|comment:${comment}")
} else {
println("RowNo:${rowNo}|Id:${id}|name:${name}|age:${age}|remark:${remark}")
}
}
fileStream.close()
}
}
//Json格式输出
func serialPrintingDemo(fileName: String) {
//创建文件流
let fileStream = File(fileName, OpenMode.Read)
if (fileStream.canRead()) {
//创建字符读取的解析流
let stream = UTF8ReaderStream(fileStream)
let reader = CSVReader(stream)
//创建格式化的解析参数
let format: CSVParseFormat = CSVParseFormat.DEFAULT.setCommentMarker('α').setDelimiter("𪧘𪧘")
//创建解析器
let csvParser = CSVParser(reader, format)
let recordList = csvParser.getRecords()
//遍历每一行解析记录
for (csvRecord in recordList) {
println(csvRecord.serialize().toJson())
CSVRecord.deserialize(csvRecord.serialize())
}
fileStream.close()
}
}
//按照csv格式输出
func csvPrint() {
let csvContent =
###"# Comment before header
author,title,publishDate
Dan Simmons,Hyperion,"1989"
# Comment Line 1
# Comment Line 2
# Comment Line 3
Douglas Adams,The Hitchhiker's \"Guide\" to the Galaxy,1979
Douglas John,The Hitchhiker's \"Guide\" to the Mars,1979"###
//创建字符串流
let readerStream = StringStream(csvContent)
let reader = CSVReader(readerStream)
//创建格式化的解析参数
let format: CSVParseFormat = CSVParseFormat.DEFAULT
//创建解析器
let csvParser = CSVParser(reader, format)
let recordList = csvParser.getRecords()
let outFormat = CSVOutFormat.DEFAULT
let sbOut = StringBuilder()
let csvPrint = CSVPrinter(outFormat)
var firstLine = true
//遍历每一行解析记录
for (csvRecord in recordList) {
if (firstLine) {
firstLine = false
csvPrint.print(csvRecord, sbOut)
} else {
csvPrint.printLine(sbOut)
csvPrint.print(csvRecord, sbOut)
}
}
println(sbOut.toString())
}