应用场景

Web应用中导入导出报表是一个非常常见的需求,而普通用户使用最多的表格文件都是用Excel保存的。

一般来说,对于数据量较小的导入导出,使用xls/xlsx文件和用户交互是最佳选择,即有相应函数库作为支撑,用户的学习成本也是最低的。但是,对于数据量较大的业务来说就不适用了。因为,大批量数据在导入时,函数库会将表中所有数据载入到内存中,由于xls/xlsx的文件本身在原始数据基础上就包含了一些冗余信息(如格式),加上数据量本身的扩充,导致内存消耗会非常大,在php环境中使用phpExcel这个最热门的库,读取一个5M左右的xls数据就有可能导致512M的php可用内容消耗殆尽。

因此,考虑到以下的应用场景:大数据量交互:导入数据行数在5-10万,列数在10-100,文件大小5M-20M之间

用户依赖:用户只习惯用Excel处理数据

无需表格格式:无论导入导出,用户均对数据表格格式没有要求(边框、底纹、对齐等),仅对数据格式有基本要求(数字、文本、浮点数等)

后端对xls/xlsx大文件的导入性能较差

在这种情况下,考虑csv文件作为数据导入导出的载体,是我认为较为合适的一个选择。相对于xls/xlsx,csv文件的优势如下:体积小,上传速度快

Mysql原生支持Load data infile from csv,可以快速dump数据

用户学习成本不高,只需要告诉用户保存文件时选择csv格式即可

由于文件本身是纯文本,可以在导入前对数据做验证和其他处理,既降低了内存消耗,又提高了读取速度

所以,最近一段时间系统都采用csv进行数据导入导出。但是,最近发现一些导入导出时的问题,主要是出在字符处理上。

问题起因

最开始发现的问题是这样的:首先我在网站上导出一个数据表,其中有一列是“名单”,也就是一些姓名。然后,我再将这个表原样导入,发现其中有些记录中的姓名居然和我导出之前不一样了。比如说,王玥变成了王h;还有堃这个字不见了等等。很快,我就发现这几个问题主要是出现在一些生僻字上,google一番之后得到了答案:字符集不正确。

问题排查

最开始的搜索结果把我引入了数据导入阶段的问题排查环节。一种说法是数据库的字符集不正确,那么无论你的原始数据是怎样的肯定都不会支持这些生僻字。我们知道,中文系统常见字符集有以下几种:utf-8:国标字符集,目前应用最广泛,中文字库也是较全的,不存在生僻字问题。

gb2312:中文字符集,很多人都很熟,然而也是这次背锅的主角,生僻字显示错误或者不显示就是因为字符集是他。

gbk/gb18030:还是中文字符集,对上面的生僻字也支持,因此不会出现问题。

上面看似是三种字符集,其实可以分为两类。utf-8和gbk系列的根本区别在于他们的编码方式不同,即两套完全不一样的16进制编码表示双字节字符(汉字);而gbk和gb2312基本相当于超集和子集的关系,只是字库大小有别,编码方式是一样的。

于是,我检查了数据库编码,以及php的编码,很显然,都是utf-8,因此不存在不支持生僻字的问题。那么问题出在哪儿了呢?

回顾一下现有的业务逻辑,我的导出和导入流程基本是这样的:php读取mysql数据,循环写入csv文件,在写入时用iconv函数从utf-8转换为gbk编码;

打开文件,填入其他需要的数据,保存;

导入数据,其中load data命令已经设置字符集为gbk。

这个时候我就开始百思不得其解了:既然utf-8和gbk都不存在生僻字问题,为什么我就是导入不成功呢?难道是我的转换/导入命令有问题?为了解决这个疑问,我觉得放弃gbk转换,直接使用utf-8进行全程数据交换。于是,重新导出数据后,我先用文本编辑器查看了一下,文件内容正常!但是当我用Excel打开之后……

明明是正常的文件,为什么Excel里变成乱码了呢?

CSV与UTF-8,微软

很显然,Excel对于我的文件编码识别是错误的。第二次google一番之后了解了,csv本身只是纯文本,微软在打开csv文件时,默认都将文件的格式判定为Windows平台的标准格式,即ANSI,所以自然识别不了utf-8的字符。那么怎样才能识别呢?答案很简单,加BOM。

BOM简单的来说就是一个文件头,在文件头部加入0xEF 0xBB 0xBF之后,utf-8就变成了带BOM的文件,再次用Excel打开,果然正常显示了。至此,是否问题已经解决了呢?数据库支持生僻字,导出utf-8文件,加BOM后打开……并没有。因为之后还需要做数据导入,由于额外的文件头存在,导入时会直接报错(因为已经不是原来的纯文本了)。那么,很自然的想到在导入之前去除BOM头。好了,这下导入也可以了。然而,现在又出现几个新的问题:用户在Excel中直接新建一个文件,保存为csv时的格式为ANSI,因此导入时需要判断文件是否是utf-8,确定字符集

在已经是utf-8时,还需要判断是否是带BOM的,那么就需要读取文件做一下检测,并去除BOM。

带BOM文件仅仅是显示正常,如果直接保存,文件中的列分隔符从默认的逗号变成了空格,直接导致文件内容变得完全不可控了。

因此,在当前的技术方案下,需要考虑编码格式、是否有BOM、分隔符判断等……感觉就像是为了补锅砸了一个更大的窟窿,需要花费更多的精力去填。那么,这条路行不通的话,就回到上一节的问题,如果还是将文件转换为gbk,为何还会有生僻字的问题呢?按照研究得到的资料,gbk应该是完全支持这些字符的啊?

原来是Mac的锅

回到最开始我们导出的那个文件。我将文件放到Windows平台打开,发现里面显示的字符是正确的!这时我才想起来,是最近开始在Mac上做导入导出,才发现这个生僻字的问题,难道是Mac系统的字符集有问题?经过第三次google之后,终于找到了本次问题的最终答案:

Excel在打开一个csv文件时,实际上使用了系统默认的字符集和默认分隔符进行了一次数据导入,而过程对用户是隐藏的。而Mac中的默认字符集的中文字库不支持生僻字。

我们可以做一个实验:打开Excel,选择导入数据(不是直接打开csv文件),选择之前的文件,可以看到第一步选择字符集的界面:

可以看到,默认字符集是Mactonish,这是Mac的默认字符集。这个字符集具体是什么,我没有搜索到,但是我把字符集改为第二项Windows(ANSI)之后,生僻字立刻显示正常了。随后,我又使用简体中文的三个字符集(如上图所示)进行测试,发现Simplified Chinese(GB 2312)类型确实是不支持生僻字的,而Simplified Chinese(Mac OS)同样如此,只有Simplified Chinese(Windows, DOS)格式可以支持。

所以,其实不是我的系统不支持生僻字,而是Mac中的Excel在打开csv文件时的文件导入过程改变了字符集,缩小了字库,导致我的生僻字直接丢掉了。既然这样,问题解决就变得比较简单了:对于Windows用户,不用担心本问题的发生,因为默认字符集就支持生僻字;而对于Mac用户,需要注意下载的数据表不要直接打开,选择用导入数据的方式打开,并选择正确的字符集即可。

生僻字问题的总结

综上,虽然我的问题原因相对比较小众,但问题排查过程中对整个导入导出环节的字符集理解过程我觉得还是很有意义的。我的流程中其他环节其实已经避免了生僻字的问题,但其他开发者在做类似流程时可能会忽略或者错误处理这些环节。因此,总结一下,为了避免导入导出时的生僻字问题,需要注意以下几点:检查数据库和后端文件的编码,即数据来源的编码,必须为utf-8或gbk等支持中文生僻字的编码。

导出时,如果为utf-8,则转换成gbk编码。

导入时设定字符集,load data infile加上charset关键字。

非Windows系统打开文件使用数据导入功能,而非直接打开,以便确定字符集,防止错误导入。

至此,生僻字的问题得到完整解决。

导出时的格式问题

这次花了一些时间解决生僻字问题后,我也顺便处理了一些导出数据时的格式控制问题。当然,这些问题都是直接能搜到解决方案的,我在这里只是整理归纳分享一下,希望对有同样问题的人能提供快速帮助。主要问题如下:科学计数法问题:导出数据中存在超过12位的数字时,在Excel中将以科学计数法的形式显示,而这往往不是用户需要的。

前导0问题:导出数据中存在第一位为0的数字时,Excel会忽略掉这个0,将它直接抹去。

逗号问题:默认分隔符是逗号,假如原始数据里也有逗号,则会导致列分隔出错。

为什么会存在这些问题呢?逗号问题的原因显而易见,只要想办法和作为分隔符的逗号区分开就可以了。关于科学计数法和前导0的问题,原因是这样的:csv是纯文本文件,相对于xls来说没有数据类型的信息,所以Excel在打开csv时根据数据的内容自动进行了类型判断。对于一串数字,Excel认为是数字类型,超出12位就会以科学计数法表示;而既然是纯数字,很显然没有以0开头的表示法,所以这个0也就被抹掉了。

解决问题的方法也很简单:加引号。即将文本用=""包裹起来,=在最前,会被Excel识别为一个函数,而双引号包裹表示一个字符串,那么Excel不会对字符串里的内容做任何改动,于是就可以原样输出了。代码如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23此转换函数可以判断字符或数字形式的数字、浮点数、逗号,将需要包裹的文本用=""包裹起来,并对其中的逗号和已经存在的双引号做转义处理。测试数据如下:

1转换后的文本内容如下:

1Excel中显示正常。

转自:Posted by 班登 Dec 6th, 2016 11:32 am php

csv文件 内容转义_保存csv文件时的生僻字处理和格式控制相关推荐

  1. python 对 文件内容 搜索_在txt文件中搜索数据

    如果您设计了数据格式,固定宽度的列不是一个很好的格式.但如果你被他们困住了,他们很容易对付.在 首先,要分析数据:addressbook = [] with open('addressbook.txt ...

  2. php文件读取文件内容,PHP文件系统函数-读取文件内容几种方式

    介绍几种php获取文件内容的方式 介绍读取文件的方式之前,我们先看一下打开文件资源和关闭资源 名字资源绑定到一个流 - fopen 关闭一个已打开的文件指针 - fclose $handle1 = f ...

  3. .rpt文件内容读取java_Java 中读取文件内容的 n 中方式

    前言 刚接触 java 的时候很困惑一个事情 File相对路径,以哪个目录为参照物. 随着 io 模型的发展,java 1.7 的 nio,使用 Path.Paths 和 Files 等来方便 io ...

  4. new blob文件设置编码_前端下载文件amp;下载进度

    前端最基础的就是 HTML+CSS+Javascript.掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些.前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础 ...

  5. Java代码给csv文件加水印_如何给文件加上水印?

    如何给文件加上水印? 修改日期:2020-07-31 11:33:48 这是一款专业的虚拟打印机,使用本软件几乎可以把任何windows程序文件通过打印驱动打印成PDF文件.可以快速将doc.txt. ...

  6. csv格式文件解析失败_理解CSV格式规范(解析CSV必备)

    什么是CSV 逗号分隔值(Comma-Separated Values,CSV),其文件以纯文本形式存储表格数据(数字和文本),文件的每一行都是一个数据记录.每个记录由一个或多个字段组成,用逗号分隔. ...

  7. python写csv文件分隔符问题_导出csv文件时,处理分隔符问题(转)

    CSV文件默认以英文逗号做为列分隔符,换行符作为行分隔符. 如果不提供网页形式只用命令行或二进制程序输出数据到CSV,只需要将数据段按,分割,行按\n分割,写入到一个.csv文件即可. 但有时字段里含 ...

  8. java 文件内容排序_在Java中对2个大型文本文件进行排序的最佳方法是什么?

    我正在构建一个简单的 Java应用程序,涉及从csv文件中读取信息. csv文件中的信息以这种形式出现: "ID","Description" "AB ...

  9. java控制器文件内容替换_如何用Java来进行文件切割和简单的内容过滤的实现

    一 由来 去年由于项目的需求,要将一个任意一个文件制作成一个xml文件,并且需要保持文件内容本身不产生变化,还要能够将这个xml重新还原为原文件.如果小型的文件还好处理,大型的xml,比如几个G的文件 ...

最新文章

  1. 微信七年回顾:历经多少质疑和差评,才配拥有今天的强大
  2. [BTS]使用BizTalk开发应用系统,就是这么简单!
  3. 新版linux安装旧软件下载,Linux下载安装各种版本的firefox
  4. java list 接口_Java 集合 List接口
  5. Python3 爬虫学习笔记 C18【爬虫框架 pyspider — 深入理解】
  6. python能做哪些客户端_发布一个Httpsqs的Python客户端
  7. python引用自己的文件的一切问题
  8. 云小课|MRS基础原理之ClickHouse组件介绍
  9. 经验分享:java批量读取txt文件入库
  10. Rtsp之H265解析
  11. HTML学习笔记(七)
  12. python 时间处理_Python如何进行时间处理
  13. html滑动门原理,HTML+CSS:雪碧图和滑动门制作
  14. 制造业案例 | 美创助力纳爱斯集团三层业务安全审计实践
  15. 成都市金牛区2018年小学入学划片范围
  16. HDS日立 (高中低端)存储
  17. Win32汇编:数组与标志位测试总结
  18. 修改apt-get服务器,云服务器使用sudo apt-get update 失败的原因及解决方法(unubtu下)...
  19. html图片右上角删除按钮,图片右上角删除
  20. 线程有哪些状态?创建、就绪、运行、阻塞和死亡

热门文章

  1. 单词接龙acwing
  2. Storm学习(一)Storm介绍
  3. 【研究生】计算机架构的新黄金时代,两位图灵奖得主最新力作
  4. 数据结构—查找(顺序查找和折半查找)
  5. 用户名+密码控制+php文件存储
  6. FLASH 上传控件传输,服务端保存文件
  7. Xshell输入特别卡顿
  8. [附源码]计算机毕业设计Python的连锁药店销售管理系统(程序+源码+LW文档)
  9. 聊聊GIS中那些坐标系(转)
  10. insmod: error inserting '***.ko': -1 Invalid parameters 真正原因以及解决方法