Scala按Map键拆分写入不同文件问题求助
解决Scala中按Map Key生成对应文件的问题
你好呀!看了你的代码和问题描述,你现在的核心困扰是:明明生成的Map里有20个不同的日期作为Key,但最后只生成了一个文件,所有记录都被覆盖了对吧?这是因为代码里几个小细节没处理到位,咱们来一步步梳理和修正:
问题根源分析
- 计数器
counter的错误使用:你把counter定义在foreach循环外,而且循环里的counter + 1只是做了加法运算,并没有把结果赋值回counter(正确写法是counter += 1)。更关键的是,你用计数器命名文件而非Map的Key,导致所有循环都在写入同一个文件名,后面的内容直接覆盖了前面的,最终只剩一个文件。 - 文件操作逻辑混乱:判断文件存在时重新创建同名
PrintWriter完全没必要,反而会覆盖已有内容;同时finally块里的pw.flush()和pw.close()没有用大括号包裹,可能导致pw.close()无法执行。 - 资源管理不安全:手动管理
PrintWriter的关闭容易出错,存在资源泄漏风险。
修正后的代码
我帮你调整了代码,主要优化点如下:
- 用Map的
Key(日期)作为文件名的一部分,确保每个Key对应独立文件,避免覆盖 - 将MeterID转为
Set,提升contains操作的效率 - 使用Scala 2.13+的
Using工具类自动管理文件资源,无需手动关闭 - 简化文件写入逻辑,添加异常处理便于排查问题
import java.io.{File, PrintWriter} import java.text.SimpleDateFormat import scala.io.Source import scala.util.Using class ScalaClass(val ccFilePath: String) { val sf = new SimpleDateFormat("yyyy/MM/dd HH:mm") // 把日期格式改成无斜杠的,避免文件名非法字符 val formatter = new SimpleDateFormat("yyyy-MM-dd") def hello(): Unit = { // 读取需匹配的MeterID,转为Set提升查找效率 val inputFile = new File("D:\\IntelliHub MDMS\\CC files\\xml file and Cdata\\cc\\File Import for triggering AU2.csv") val meterIds = Source.fromFile(inputFile) .getLines() .flatMap(_.split(",")) .toSet // 处理主文件,生成按日期分组的Map val result = Source.fromFile(ccFilePath) .getLines() .filter { line => val parts = line.split(",") parts.length >= 2 && meterIds.contains(parts(1)) } .map { line => val parts = line.split(",") val dateKey = formatter.format(sf.parse(parts(2))) (dateKey, line) } .toList .groupBy(_._1) .map { case (key, pairs) => key -> pairs.map(_._2) } // 遍历Map,每个Key对应一个文件 result.foreach { case (dateKey, lines) => val fileName = new File(s"D:\\IntelliHub MDMS\\CC files\\xml file and Cdata\\hkincoming\\NORMAL\\AD1\\AU2_dump_$dateKey.dat") // 使用Using自动关闭PrintWriter,同时处理异常 Using(new PrintWriter(fileName)) { pw => pw.write(lines.mkString("\n")) }.fold( error => println(s"写入文件${fileName.getName}失败: ${error.getMessage}"), _ => println(s"文件${fileName.getName}已成功生成") ) } } }
兼容低版本Scala的写法
如果你的Scala版本低于2.13,没有Using工具类,可以用传统的try-finally手动管理资源:
// 替换foreach里的内容 result.foreach { case (dateKey, lines) => val fileName = new File(s"D:\\IntelliHub MDMS\\CC files\\xml file and Cdata\\hkincoming\\NORMAL\\AD1\\AU2_dump_$dateKey.dat") val pw = new PrintWriter(fileName) try { pw.write(lines.mkString("\n")) } finally { pw.flush() pw.close() } }
这样修改后,每个日期Key都会生成一个独立的文件,比如AU2_dump_2018-03-17.dat,再也不会出现覆盖的问题啦!
内容的提问来源于stack exchange,提问作者Arvind Pant
相关产品推荐
相关产品推荐

