CSV文件和XLS文件有何区别
2018-08-24 本文已影响127人
junpassion
今天在做一个需求时,需要将统计后的结果写入到HDFS上,方便后续业务分析,能够读取到该文件,以邮件附件的形式展示文件的结果。但是发现,最后展示的CSV格式的文件作为邮件附件是没有问题的,但是XLS的文件却出现了很多乱码,如图:
日报乱码.png
iostream.png
日报乱码.png
读取csv、xls文件的方法如下:
val bytes = HdfsUtil.readHdfsFileToByteArray(AttachmentSummary.HDFS_OUTPUT + day +".xls")
val attaches =Map[String, Array[Byte]](s"附件-$day.xls" -> bytes)
其中readHdfsFileToByteArray方法如下,利用InputStreamReader 去读取文件:
val fs: FileSystem = FileSystem.get(CONF)
...
def readHdfsFileToByteArray2(fileName: String): Array[Byte] = {
//val file = new File(fileName)
var reader: InputStreamReader = null
try{
val finput = fs.open(new Path(fileName))
reader = new InputStreamReader(finput)
IOUtils.toByteArray(reader) // use commons.io.IOUtils
} finally {
IOUtils.closeQuietly(reader)
}
}
后来查询相关的资料才发现,csv属于文本文件,而xls是二进制文件,二者有本质区别。
iostream.png
Reader是用来处理字符流的,所以csv文件是没有问题的,但是用来处理字节流是不行的,所以xls文件乱码。
后续改为使用ByteArrayOutputStream直接拷贝一个inputStream,这样xls文件是OK的:
def readHdfsFileToByteArray(fileName: String): Array[Byte] = {
val finput = fs.open(new Path(fileName))
val output = new ByteArrayOutputStream()
try{
IOUtils.copy(finput, output)
output.toByteArray
} finally {
finput.close()
output.close()
}
}
总结:
- 文本文件。像txt,html, csv等格式的文件都属于文本文件。可以使用字符流来处理。
- 二进制文件。像xls,word等文件都是二进制文件。若用流来处理,需使用字节流。
- 字节流操作的基本单元为字节,通常用于处理二进制数据;字符流操作的基本单元为Unicode码元,通常用于处理文本数据。
- 文本文件为了兼容性,最好在写入时,加上BOM头 ByteOrderMark.UTF_8.getBytes,这样打开时,将严格按照指定的编码方式打开,否则不同平台,可能出现乱码。而二进制文件,不存在BOM头一说,只要一个字节写错,整个文件都将乱码。
- 判断某文件是文本还是二进制文件,能用NotePad打开不是乱码的是文本文件,打开全是乱码的则是二进制文件。而且对于文本文件,还可以使用Nodepad来转换格式,加BOM头等操作。