Работая над UT проекта Java 11 с Springboot, я нашел следующую трассировку стека:
java.io.IOException: Stream Closed
at java.base/java.io.FileInputStream.readBytes(Native Method)
at java.base/java.io.FileInputStream.read(FileInputStream.java:279)
at com.amazonaws.internal.SdkFilterInputStream.read(SdkFilterInputStream.java:90)
at java.base/java.io.FilterInputStream.read(FilterInputStream.java:107)
at
Я попытался создать минимальный воспроизводимый пример:
@Test
public void minimalExampleTest() throws IOException {
when(s3Service.getObject(Mockito.anyString())).thenReturn(getS3Object("image.jpg"));
try(FileOutputStream fos = new FileOutputStream( "src/test/resources/exported_data_test.zip");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos)){
service.minimalExample(zos, "directory/s3");
}
ZipFile zipFile = new ZipFile( "src/test/resources/exported_data_test.zip");
List<String> entries = zipFile.stream().map(ZipEntry::getName).collect(Collectors.toList());
//assert
assertNotNull(entries);
assertTrue(entries.stream().filter(ent -> ent.contains(".jpg")).collect(Collectors.toList()).size() == 4);
List<String> imagesNameList = List.of("doc1_export.jpg", "doc2_export.jpg", "doc3_export.jpg", "doc4_export.jpg");
entries.stream().forEach(imageName -> assertTrue(imagesNameList.contains(imageName)));
//generated files deletion
entries.stream().forEach(imageName -> {
File file = new File("src/test/resources" + "/" + imageName);
file.delete();
});
File file = new File( "src/test/resources/exported_data_test.zip");
file.delete();
}
private static S3Object getS3Object(String fileName) throws FileNotFoundException {
S3Object s3Object = new S3Object();
s3Object.setKey(fileName);
File initialFile = new File(IMAGES_DOSSIER + "/" + fileName);
InputStream targetStream = new FileInputStream(initialFile);
s3Object.setObjectContent(targetStream);
return s3Object;
}
public ZipOutputStream minimalExample (ZipOutputStream zipOutputStream, String directoryName) {
try {
List<String> listDocumentType = List.of("doc1", "doc2", "doc3", "doc4");
Map<String, S3ObjectInputStream> s3ObjectInputStreamList = new HashMap<>();
listDocumentType.stream().forEach(docType -> {
String fileName = directoryName + '/' + docType + "_export.jpg";
S3Object s3Object = s3Service.getObject(fileName);
if (s3Object != null)
s3ObjectInputStreamList.put(docType + "_export.jpg", s3Object.getObjectContent());
});
s3ObjectInputStreamList.keySet().forEach(key -> {
var zipEntry = new ZipEntry(key);
try {
zipOutputStream.putNextEntry(zipEntry);
var objectContent = s3ObjectInputStreamList.get(key);
var bytes = new byte[1024];
int length;
while ((length = objectContent.read(bytes)) >= 0) {
zipOutputStream.write(bytes, 0, length);
}
objectContent.close();
zipEntry.clone();
} catch (IOException e) {
e.printStackTrace();
}
});
zipOutputStream.closeEntry();
zipOutputStream.close();
} catch (IOException e) {
logger.log(Level.LOW, e.getMessage());
}
return zipOutputStream;
}
Дело в том, что код при использовании в приложении работает хорошо, но в тесте он делает первую итерацию while и на второй итерации выскакивает ошибка, показанная в трассировке стека. (В минимальном примере тест пройден - ошибка не блокируется)
Я не знаю, почему у меня возникает ошибка java.io.IOException: Stream Closed. Если кто-нибудь может дать объяснение/решение этой проблемы?
Возможно, у вас есть два ключа с тем же входным потоком, что и значение. Поэтому, когда вы закрываете поток ввода первого ключа и пытаетесь прочитать поток ввода второго ключа, он уже закрыт.
закрыть блокfinally{}
@Sören Я попытался создать пример (см. изменения в этом посте).
@ k314159 k314159 Я проверил ключи, и они все разные.




Проблема заключалась в том, что мы вызывали метод в S3Service 4 раза и возвращали одно и то же изображение, поэтому, когда мы пытались прочитать содержимое объекта, поток уже был создан.
Проблема была обнаружена с указанием возврата макета в разные файлы, как в приведенном ниже коде:
@Test
public void minimalExampleTest() throws IOException {
when(s3Service.getObject(Mockito.anyString())).thenReturn(getS3Object("image.jpg"))
.thenReturn(getS3Object("image1.jpg"))
.thenReturn(getS3Object("image2.jpg"))
.thenReturn(getS3Object("image3.jpg"));
try(FileOutputStream fos = new FileOutputStream( "src/test/resources/exported_data_test.zip");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos)){
service.minimalExample(zos, "directory/s3");
}
ZipFile zipFile = new ZipFile( "src/test/resources/exported_data_test.zip");
List<String> entries = zipFile.stream().map(ZipEntry::getName).collect(Collectors.toList());
//assert
assertNotNull(entries);
assertTrue(entries.stream().filter(ent -> ent.contains(".jpg")).collect(Collectors.toList()).size() == 4);
List<String> imagesNameList = List.of("doc1_export.jpg", "doc2_export.jpg", "doc3_export.jpg", "doc4_export.jpg");
entries.stream().forEach(imageName -> assertTrue(imagesNameList.contains(imageName)));
//generated files deletion
entries.stream().forEach(imageName -> {
File file = new File("src/test/resources" + "/" + imageName);
file.delete();
});
File file = new File( "src/test/resources/exported_data_test.zip");
file.delete();
}
Вы закрываете поток где-то между вторым и первым фрагментом кода. минимальный воспроизводимый пример, пожалуйста