Scala使用Encoder读取CSV至DataFrame时丢失内容的问题
解决CSV解析时记录内容丢失的问题
看起来你遇到的问题是CSV里的嵌套引号导致解析器误判字段边界,把后面的内容弄丢了!我来帮你拆解原因和解决办法:
问题根源
你给出的这条记录里,URL字段的格式是"http://svnbook.red-bean.com/"">Version Control with Subversion..."——这里的问题在于不规范的引号嵌套:字段开头的"在URL末尾的"处被错误地当成了字段结束标记,后面的">Version Control...部分要么被解析成无效字段,要么直接被丢弃,导致你看不到第二段内容。
而且你用case class定义Schema,一旦解析器拆分字段的数量和case class的属性数量不匹配,就会出现内容丢失或错位的情况。
具体解决方案
1. 调整Spark CSV解析参数(推荐)
如果是用Spark处理的话,可以通过设置解析选项来兼容这种不规范的引号:
import org.apache.spark.sql.SparkSession import your.package.yourCaseClass val spark = SparkSession.builder().appName("CSVParser").getOrCreate() val df = spark.read .option("quote", "\"") // 指定字段包裹符为双引号 .option("escape", "\"") // 用双引号转义字段内部的双引号 .option("quoteMode", "NON_NUMERIC") // 只对非数字字段用引号包裹,避免干扰 .schema(spark.implicits.newProductEncoder[yourCaseClass].schema) // 用case class生成Schema .csv("your-file.csv")
这里的escape参数是关键——它告诉解析器:字段内部的双引号需要用另一个双引号转义,这样就能正确识别"http://svnbook.red-bean.com/"里的引号是字段内容的一部分,而不是字段结束标记。
2. 预处理CSV文件修复格式
如果数据格式太不规范,解析参数也搞不定,可以先手动修复文件里的引号问题:
比如用命令行工具sed把字段内部的单个双引号替换成两个(CSV标准的转义方式):
sed -E 's/([^,])"([^,])/\1""\2/g' input.csv > corrected.csv
这个正则会匹配不在逗号前后的单个双引号,把它变成两个,这样解析器就能正确识别了。
3. 手动解析每行数据(兜底方案)
如果上面两种方法都不行,你可以直接读取文本行,自己实现简单的CSV解析逻辑:
import org.apache.spark.sql.functions._ // 先读取原始文本行 val rawLines = spark.read.text("your-file.csv") // 自定义解析逻辑,处理嵌套引号 def parseCsvLine(line: String): yourCaseClass = { val fields = collection.mutable.ArrayBuffer[String]() val currentField = StringBuilder.newBuilder var inQuotes = false for (c <- line) { c match { case '"' => inQuotes = !inQuotes case ',' if !inQuotes => fields += currentField.toString().trim currentField.clear() case _ => currentField.append(c) } } // 加入最后一个字段 fields += currentField.toString().trim // 把解析后的字段映射到你的case class yourCaseClass( fields(0).toInt, fields(1).toInt, fields(2), fields(3).toInt, fields(4).toInt, fields(5) ) } // 转换为DataFrame val parsedDF = rawLines.map(r => parseCsvLine(r.getString(0))).toDF()
这种方式完全由你控制解析逻辑,能应对各种奇葩的CSV格式。
内容的提问来源于stack exchange,提问作者methefish
相关产品推荐
相关产品推荐

