Akka:如何在一个图形阶段中提取值并在下一个阶段使用它

时间:2018-03-26 18:04:11

标签: scala akka akka-stream alpakka

我正在使用Alpakka和Akka来处理CSV文件。由于我有一堆必须添加到同一个流的CSV文件,我想添加一个包含文件名或请求信息的字段。目前我有这样的事情:

val source = FileIO.fromPath(Paths.get("10002070.csv"))
  .via(CsvParsing.lineScanner())

其中包含ByteStrings(字段)的列表序列(行)。目标是:

val filename = "10002070.csv"
val source = FileIO.fromPath(Path.get(filename))
    .via(CsvParsing.lineScanner())
    .via(AddCSVFieldHere(filename))

创建类似于:

的结构
10002070.csv,max,estimated,12,1,0

文件名是原始来源中不存在的字段。

我认为在流中注入值并不是很漂亮,最后我想确定在读取目录的流阶段中传递给解析的文件名。

通过流阶段传递值以供以后重用的正确/规范方法是什么?

1 个答案:

答案 0 :(得分:1)

您可以使用map转换流,将文件名添加到每个List[ByteString]

val fileName = "10002070.csv"
val source =
  FileIO.fromPath(Path.get(fileName))
    .via(CsvParsing.lineScanner())
    .map(List(ByteString(fileName)) ++ _)

例如:

Source.single(ByteString("""header1,header2,header3
                           |1,2,3
                           |4,5,6""".stripMargin))
  .via(CsvParsing.lineScanner())
  .map(List(ByteString("myfile.csv")) ++ _)
  .runForeach(row => println(row.map(_.utf8String)))

// The above code prints the following:
// List(myfile.csv, header1, header2, header3)
// List(myfile.csv, 1, 2, 3)
// List(myfile.csv, 4, 5, 6)

同样的方法适用于您不知道文件名的更一般情况。如果你想读取目录中的所有文件(假设所有这些文件都是csv文件),将文件连接成一个流,并在每个流元素中保留文件名,那么你可以用Alpakka的{{{以下列方式实用:

val source =
  Directory.ls(Paths.get("/my/dir")) // Source[Path, NotUsed]
    .flatMapConcat { path =>
       FileIO.fromPath(path)
         .via(CsvParsing.lineScanner())
         .map(List(ByteString(path.getFileName.toString)) ++ _)
    }