You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:20:36