最初我有以下代码:

尝试1

try (var output = new ByteArrayOutputStream();
     var printer = new CSVPrinter(new OutputStreamWriter(output), CSVFormat.DEFAULT)) {
   printer.printRecord(EMAIL);
   for (MyBean mb : items) {
     printer.printRecord(mb.getEmail());
   }
   externalHttpCall(output.toByteArray());
}

在这里,我发现有时字节数组未完全写入。

我了解这是因为在externalHttpCall调用期间未刷新流。

为了解决这个问题,我编写了以下内容:

尝试2

try (var output = new ByteArrayOutputStream();
     var printer = new CSVPrinter(new OutputStreamWriter(output), CSVFormat.DEFAULT)) {
  printer.printRecord(EMAIL);
  for (MyBean mb : items) {
    printer.printRecord(mb.getEmail());
  }
  printer.flush();
  log.info("Printer was flushed");

  externalHttpCall(output.toByteArray());
}

它解决了问题,但是在这里我迷失了一个想法,那就是仅在externalHttpCall之后关闭流真的是个坏主意。所以我想出了以下解决方案:

尝试3

externalHttpCall(convertToByteArray(items);

public byte[] convertToByteArray(List<MyBean> items){
  try (var output = new ByteArrayOutputStream();
       var printer = new CSVPrinter(new OutputStreamWriter(output), CSVFormat.DEFAULT)) {
    printer.printRecord(EMAIL);
    for (MyBean mb : items) {
      printer.printRecord(mb.getEmail());
    }
    return output.toByteArray();
  }
}

我预计冲洗会在流关闭之前发生。但是根据我的实验,它不起作用。看起来是因为刷新发生在流关闭之前但在toByteArray调用之后才发生。

我该如何解决?

最佳答案

给定问题中的三个代码段,我认为这应该可行:

externalHttpCall(convertToByteArray(items);

public byte[] convertToByteArray(List<MyBean> items){
  try (var output = new ByteArrayOutputStream();
       var printer = new CSVPrinter(new OutputStreamWriter(output), CSVFormat.DEFAULT)) {
    printer.printRecord(EMAIL);
    for (MyBean mb : items) {
      printer.printRecord(mb.getEmail());
    }
    printer.flush()
    log.info("Printer was flushed");

    return output.toByteArray();
  }
}

根据CSVFormat的不同,CSVPrinter会在关闭时自动刷新(CSVFormat.DEFAULT不会自动刷新...)。您可以使用CSVFormat的构建器(如pattern)使格式在关闭时与CSVFormat.DEFAULT.withAutoFlush(true)齐平(此提示感谢@PetrBodnár)。但是,在上面的示例中这可能没有任何区别。

如果将try-with-resource转换为实际的呼叫顺序,则会得到以下信息:
var output = new ByteArrayOutputStream();
var printer = new CSVPrinter(new OutputStreamWriter(output), CSVFormat.DEFAULT)
printer.printRecord(EMAIL);
...
var result = output.toByteArray();
printer.close();  // might call flush
output.close();
return result;

由于close操作将在finally块中调用,因此它们将在创建字节数组后进行。如果需要冲洗,则需要在调用toByteArray之前进行冲洗。

10-02 23:55