需求背景

从一个数据库导出一个表的数据,导出文件为CSV文件;需要将数据导入到本地开发环境的数据库里面。CSV文件已经有了,需要解析读CSV文件,并导入进数据库。本文主要研究第一部分,自己写代码解析CSV文件。
Java中可以找到Jar包,工具类,直接使用。也不用自己手工写解析。如果有更成熟的工具,建议直接使用。本文作者写的,只有自己测试过,如果有bug,欢迎留言,不一定及时回。

CSV文件规则

以纯文本形式存储表格数据(数字和文本)。
记录间以换行符分隔;每条记录由字段组成,字段间的分隔符是逗号。
注意:
1、字段中包含有逗号,有换行符,该字段必须用双引号括起来;
2、字段中的双引号用两个双引号表示;
以上提到的逗号和双引号均为半角字符。
如果只是简单的逗号分割,那么就很简单。本文主要研究的就是,有特殊字符作为字段的值,上面注意中的情况出现的情况下,文件的解析。

CSV规则有遗漏的,或者逻辑不完善,能导致歧义的数据案例,评论指出,感谢!

准备测试数据

可以新建一个test.csv文件,用Excel输入值,然后文本打开,观察值。注意包含以下测试案例:

  1. 正常数据
  2. 空数据
  3. 文本有逗号
  4. 文本有引号
  5. 文本中有换行
    例如:

好的测试数据是开发的前提。习惯先准备,罗列测试数据的所有情况,再开发。开发的时候考虑的更全面。开发也可以分类,从解析简单情况开始。

代码

/*** 解析CSV字符行集合* @param lines java 自带的读文件流,按换行符分割的,每行是集合的一个元素* @return 解析完的结果集合;List<List<String>> resList 所有行是一个集合, 每行的所有字段是一个集合。*/public static List<List<String>> spiltCSVString(List<String> lines) {List<String> oneLine = new ArrayList<String>();List<List<String>> resList = new ArrayList<>();if (lines.isEmpty() || lines.size() == 0) {return resList;}String tempStr = "";char specialChar = '\"';char splitChar = ',';boolean specialFlag = false;for (int i = 0; i < lines.size(); i++) {String line = lines.get(i);if (line.indexOf(specialChar) < 0) {oneLine = new ArrayList<String>();for (int j = 0; j < line.toCharArray().length; j++) {if (line.charAt(j) == splitChar) {oneLine.add(tempStr);tempStr = "";continue;} else {tempStr += line.charAt(j);}}if (!"".equals(tempStr)) {oneLine.add(tempStr);tempStr = "";}resList.add(oneLine);} else {if (!specialFlag) oneLine = new ArrayList<String>();for (int j = 0; j < line.toCharArray().length; j++) {if (line.charAt(j) == specialChar) {if (specialFlag) {if (j + 1 < line.toCharArray().length && line.charAt(j + 1) == specialChar) {tempStr += specialChar;} else {oneLine.add(tempStr);tempStr = "";specialFlag = false;}j++;continue;} else {specialFlag = true;continue;}} else if (line.charAt(j) == splitChar && !specialFlag) {oneLine.add(tempStr);tempStr = "";continue;}tempStr += line.charAt(j);}if (!specialFlag) {if (!"".equals(tempStr)) {oneLine.add(tempStr);tempStr = "";}resList.add(oneLine);} else {tempStr += "\r\n";}}}return resList;}

先用熟悉的Java写完,更快,再换成m语言的:


/// 解析CSV文件
/// filePath 文件路径,需要放到服务器上,是服务器上的路径,
/// 返回:每行数据分割后组成一个集合;所有行又放在返回的大集合里面。
/// w ##class(ext.util.String).ParseCSVFile("C:\Users\HuangZhi\Desktop\test.csv")
ClassMethod ParseCSVFile(filePath As String)
{s fileContent = ..readFileContent(filePath);bs contentList = ##class(%ListOfDataTypes).%New()for i=1:1: $ListLength(fileContent){;write !, $ListGet(fileContent, i)d contentList.Insert($ListGet(fileContent, i))};bs resultList = ..ParseCSVString(contentList)   ;b/**for i=1:1: resultList.Count() {s contentList = resultList.GetAt(i)for j=1:1: contentList.Count() {w " || "write contentList.GetAt(j)          }w !,"----------------------------",!}**/q resultList
}/// w ##class(ext.util.String).readFileContent("C:\Users\HuangZhi\Desktop\temp\fileList.txt")
/// filePath 文件路径,需要放到服务器上,是服务器上的路径,
/// 返回的是数字,文件里面的每行内容是数组的元素
ClassMethod readFileContent(filePath)
{s ExistsFlag=##Class(%File).Exists(filePath)q:ExistsFlag'=1 "-1^Error: "_ filePath _"  does not exist !"Set file = ##class(%File).%New(filePath)Set file.Name = filePathSet sc = file.Open("WRS")if $$$ISERR(sc){do file.Close()set file=""Quit "-1^读取文件异常"_$system.Status.GetErrorText(sc)}set fileContent = $lb()set index = 1While('file.AtEnd){Set line = file.ReadLine()set $list(fileContent, index) = lineset index = index + 1}q fileContent
}/// 解析CSV字符
/// csv是逗号分割的,注意:字段中包含有逗号,有换行符,该字段必须用双引号括起来;字段中的双引号用两个双引号表示;以上提到的逗号和双引号均为半角字符。
/// lines 入参是读CSV文件的每一行,按换行符分割后的,注意一定是没有换行符的 集合;
/// 返回:每行数据分割后组成一个集合;所有行又放在返回的大集合里面。
/// w ##class(ext.util.String).ParseCSVString(contentList)
ClassMethod ParseCSVString(lines As %ListOfDataTypes)
{set oneLine = ##class(%ListOfDataTypes).%New()set resList = ##class(%ListOfObjects).%New()Q:'$d(lines) resLists tempStr = "" // 一个字段的值s specialChar = """" //转义字符s splitChar = "," // 分割符s specialFlag = 0 // 是否有需转义的字符:逗号;双引号;换行符;作为内容for i = 1 : 1 : lines.Count() {s line =  lines.GetAt(i)if '(line [ specialChar) {set oneLine = ##class(%ListOfDataTypes).%New()              for j = 1 : 1 : $L(line) {if ($E(line, j) = splitChar) {d oneLine.Insert(tempStr)s tempStr = ""continue} else {s tempStr = tempStr _ $E(line, j)}}if '("" = tempStr) {d oneLine.Insert(tempStr)s tempStr = ""}d resList.Insert(oneLine)                } else {s:'specialFlag oneLine = ##class(%ListOfDataTypes).%New()for j = 1 : 1 : $L(line) {if ($E(line, j) = specialChar) {if (specialFlag) {if ($E(line, j + 1) = specialChar) {s tempStr = tempStr _ specialChar} else {d oneLine.Insert(tempStr)s tempStr = ""s specialFlag = 0}s j = j + 1continue                         } else {s specialFlag = 1  continue                        }} elseif ($E(line, j) = splitChar) && ('specialFlag) {d oneLine.Insert(tempStr)s tempStr = ""continue}s tempStr = tempStr _ $E(line, j)}if 'specialFlag {if '("" = tempStr) {d oneLine.Insert(tempStr)s tempStr = ""}d resList.Insert(oneLine)} else {s tempStr = tempStr _ $C(10,13) ;换行符 the line spacing characters}}}Q resList
}

测试结果


最后使用解析,映射成类对象,保存到数据库。只提供m语言版本:


/// sql 查询,导出的CSV文件,再导入DB; 用于数据转移
/// filePath CSV数据文件
/// className 类名,表名
/// startColumnIndex 开始字段的列索引
/// d ##Class(ext.util.String).ImportCsvFile("C:\Users\HuangZhi\Desktop\data.csv", "websys.AddIns", 2)
ClassMethod ImportCsvFile(filePath, className, startColumnIndex = 1)
{s csvFileList = ##class(ext.util.String).ParseCSVFile(filePath)s propertyList = csvFileList.GetAt(1) // 第一行为类的字段名称的集合    ;bfor i=2:1: csvFileList.Count() {s oneLine = csvFileList.GetAt(i)continue:(('$D(oneLine)) || (oneLine.Count()=0))Set obj = $system.OBJ.New(className)for j=startColumnIndex:1: propertyList.Count() {set $PROPERTY(obj, propertyList.GetAt(j)) = oneLine.GetAt(j)                   }s rtn = obj.%Save()   w:(rtn) !,"success: ",i   ;b}w !,"total: ",csvFileList.Count()
}

这里,表是全量覆盖导入的情况,第一行是表字段名称(类的成员变量的名称)(变量都是基础数据类型,没有对象引用类)。不考虑主键冲突,覆盖更新等情况。如果是具体的某个类,要自己写解析数据映射,保存前的主键检查等等业务逻辑。这里只是一个很抽象的应用举例。

Java 解析CSV文件 CSV解析相关推荐

  1. java 解析csv 乱码_Java采用opencsv解析csv文件以及解析中文乱码问题

    参考资料: opencsv文档 写下本文时最新版的opencsv版本为4.0, maven坐标如下: com.opencsv opencsv 4.0 测试用test.csv id,date,name ...

  2. java 解析csv_java解析CSV文件(getCsvData 解析CSV文件 zipFiles 打成压缩包 exportObeEventDataExcel 前端页面响应)...

    //CSVUtil.class为类名 private static final Logger log = Logger.getLogger(CSVUtil.class); //filepath 可以为 ...

  3. php解析压缩包csv文件,php解析csv文件

    public function actionImport() { //post请求过来的 $fileName = $_FILES['file']['name']; $fileTmpName = $_F ...

  4. 使用go语言对csv文件进行解析处理,导入导出。

    使用的框架是gin 包为"github.com/gocarina/gocsv" 创建csv文件并且导出给前端 import ( "github.com/gocarina/ ...

  5. java对xml文件的解析_Java对XML文件的解析

    XML简介 围绕XML涉及到四方面的技术: 1.数据定义Schema.DTD 2.数据解析DOM.SAX两种解析模型 3.样式风格XSTL,使用XSTL可以将XML文件中存放的内容按照指定的样式显示为 ...

  6. java 输出xml文件_java解析xml文件并输出

    使用java解析xml文件,通过dom4j,代码运行前需先导入dom4j架包. ParseXml类代码如下: import java.io.File; import java.util.ArrayLi ...

  7. Java实现eml文件的解析

    最近在做邮件归档,然后需要解析邮件导出的eml,记录每封邮件的归档时间,发件人.标题.发件时间.归档的目录 以下是一个demo示例:待完成此功能后再优化后续代码 import java.io.File ...

  8. java xsd 解析 xml文件_xsd解析xml

    下面讲述根据xml生成对应序列化反序列化类的过程,xml需要首先转化为xsd,然后再生成为实体类.其中,XSD是XML Schema Definition的缩写. 1.拥有一个xml文件 2.打开vs ...

  9. python解析mht文件_php解析mht文件转换成html的方法

    本篇文章主要介绍php解析mht文件转换成html的方法,感兴趣的朋友参考下,希望对大家有所帮助. php解析mht文件,使用编辑器打开可以看到base64编码所以,mht是可以转换成html的. / ...

最新文章

  1. php调用C代码的方法详解
  2. Oracle job procedure 存储过程定时任务
  3. matlab利用数据求公式,matlab新手,求帮助!主要是如何将数据和公式导入
  4. Python3 定时访问网页
  5. Nagios设置报警间隔
  6. C语言 链表实现学生管理系统(含文件读写操作)
  7. windows 禁用ipv6服务_在 Windows 7 中禁用IPv6协议/IPv6隧道
  8. 如何在Linux上运行Windows软件?
  9. samp服务器信息获取,手把手教你写一个简单的服务器
  10. zabbix之 qq邮件报警
  11. c++删除数组中重复元素_LeetCode题目26:删除排序数组中的重复项
  12. vue的边距怎么设置_Vue项目如何适应浏览器,去除容器控件与浏览器四周的距离...
  13. FisherYates费雪耶兹随机置乱算法
  14. 智能优化算法:鸡群优化算法-附代码
  15. oracle11g安装副武器类,oracle 11g 服务器类
  16. matlab nist接口文件,RefProp流体热物理性质计算程序与Matlab接口
  17. RubyOnRails 文件下载
  18. 实用的视频去水印方法
  19. 100层楼两个玻璃球怎么能够找到玻璃球破碎的那一层
  20. python3 aes cbc模式解密_python3 AES 加解密

热门文章

  1. 第22章 OTP介绍
  2. FPGA_LVDS差分信号简单处理
  3. Acrel-3000电能管理系统在山东泰开变压器有限公司生产车间改造项目的应用-安科瑞苏月婷
  4. 微信音频接口调用demo
  5. AsteRx-m3 Pro+北斗超低功耗的100Hz通用型高精度 GNSS OEM 板卡
  6. RHEL 6.3 U盘安装及简单配置
  7. 安全专家:真实的网络***取证纪实
  8. 【转】sprintf函数用法
  9. java spring 开启SMTP服务发送QQ邮件
  10. 烘培配方分享---含制作步骤