咱们昨天讲过了是如何导出CSV格式的文件,今天就简单唠叨下,CSV格式的文件是如何导入的;前些时候学习了kotlin语言,和java无缝混合开发还挺有意思的,若有Java版需求的请留言.额外再叨扰下,eclipse对kotlin支持不太友好,建议idea.
/**
* 把csv文件转换成对象
* @param clazz 需要转换的对象类
* @param ins csv输入流
* @param columnIndex 列描述所在行从0开始。
* @param dataIndex 数据起始行从0开始。
*/
fun <T> csvMap(clazz: Class<T> , ins: InputStream , columnIndex: Int , dataIndex: Int): List<T> {
try {
var lines = BufferedReader(InputStreamReader(ins , "GBK"))
.use {it.lineSequence().map{String(it.toByteArray(Charsets.UTF_8))}.toList()}
var rows = lines.size
if (rows <= columnIndex || rows <= dataIndex) // do something
//获取对象域名
val columns =lines[columnIndex].split(COMMA_DELIMITER.toRegex()).dropLastWhile
{ it.isEmpty() }.toTypedArray()
var lists = mutableListOf<T>()
var mapper = ModelMapper() // map convert object
lines.drop(dataIndex).forEach {
if (StringUtils.isBlank(it)) return@forEach
val regex = Regex("(\\s)+") //处理空串防止下标越界(""," ")
val dataColumns = it.split(COMMA_DELIMITER)
var collect = dataColumns.stream().map {
it.replace(SPECIAL_SYMBOLS , BLANK_STRING)
}.filter {! it.matches(regex)}.toArray { Array(it) { BLANK_STRING } }
if (collect.isEmpty()) return@forEach
group(columns , collect).let { lists.add(mapper.map(it , clazz)) }
}
return lists
} catch (ex: IOException) {
//do something
}
}
注意:代码块中GBK我是单独写出是要说明这很重要,如果导入文件中包含中文字符不加GBK导入结果会有乱码,这个问题困扰了我很久,后来查了很多文档,才知道在读取文件流时设置中文编码格式.
/**
* 转map
* @param keys 对象域名数组
* @param values 对象数据数组
*/
fun group(keys: Array<String> , values: Array<String>): Map<String , String> = keys.zip(values).toMap()
const val SPECIAL_SYMBOLS = "`"
const val BLANK_STRING = ""
const val COMMA_DELIMITER = ","
测试使用:
fun main(args: Array<String>) {
//获取文件
var list = File("/tmp/测试下载文件7165987925830647393.csv").inputStream()
.use { MapperUtil().csvMap(Test::class.java , it , 0 , 2) }
println("$list")
}
测试使用需要说明的是,创建File时的文件地址是下载CSV格式文件的测试结果略作修改源数据为:
注意: 第一行域名必须显式的存在,我们对下载CSV格式文件的测试使用中代码片段作如下修改:
File file = utils.register("a","测试a", a -> a.getA()).register("b","测试b", a -> Objects.isNull(a.getB()) ? 2 : a.getB())
.exportCsvFile("测试下载文件", list);//注意:文件名长度大于3
测试类:
class Test(var a: String = "" , var b: Int = 0) : Serializable {
override fun toString(): String {
return "Test(a='$a', b=$b)"
}
}
测试结果:
[Test(a='王三', b=1), Test(a='d', b=2), Test(a='', b=3)]
去掉GBK的测试结果:
[Test(a='����', b=1), Test(a='d', b=2), Test(a='', b=3)]