利用sparksql对两张表进行join,报错:
检查表中字段:
发现两张表内都存在stuID。
折腾了好久也没弄好,后来不甘心,将数据转为txt格式,没想到同样的代码 跑通了。
这可太amazing了,打开两个文档反复对比了一下。并没有什么不同,直到身边的大神让我查看一下文件的编码才发现端倪:
## 预览文件
head -n 1 xxx.txt | od -c
linux 下的od命令可以查看 这篇博客
结果显示:
发现csv文件的第一行第一列开头比txt多了三个字符,原因就在这:
再次打印 csv的列名,并查看每个的长度:
var headerName = data.columns
println("headName========",headerName.toList)
for (x<- headerName){
println("输出名称为:", x, " 输出长度为: ", x.length)
println("逐次输出:~~~~~~~~~~~~~~~~~~")
for(i<-0 until x.length){
println("第", "个字符是::::", x(i).toByte)
}
println("@@@@@@@@@@@@@@结束@@@@@@@@@@@@")
}
发现 csv文件读取的第一个列名stuID本来长度为5,结果打印结果为6。出现隐藏字符,对隐藏字符进行打印发现是空字符,并且byte为-1。
所以才导致多表join时,找不到 a.stuID。到此,终于弄清楚了问题所在。
查阅了相关资料发现,是叫做BOM(Byte Order Mark),直接顺序标记,出现在文本文件的头部,Unicode编码标准中用于标识文件是采用哪种格式的编码。没有BOM 则表示是默认的ASCII
BOM主要用途是记录哪种编码格式。
找到问题,解决起来就容易了很多。
随后查阅到spark2.x已经可以通过对应api 正常读取csv文件:
val data = spark.read.format("csv")
.option("sep", ",")
.option("header", true)
.option("nullValue", "")
.csv(p.input_pt)
这样就不会有问题了。
附:
本文用到的csv文件和txt文件的下载地址 密码:wg35
拓展: spark将字符(Char)与字节编码(Byte)的相互转化
字符转字节:toByte
字节转字符:toChar
var s = "abc"
for (x <- 0 until s.length){
println(s(x).toByte)
println(s(x).toByte.toChar.toString)
}
println(100.toChar)
println(("-1".toByte.toChar)==(-1.toChar))
结果:
s: String = abc
97
a
98
b
99
c
d
true