java.lang.IllegalStateException: InputStream已经被读取 - 如果需要多次读取流,请勿使用InputStreamResource。

9

我试图从AWS S3存储桶中读取文件并将其设置为我的Spring Batch Reader类内的资源。当我在AWS Lambda函数上测试应用程序时,出现以下错误。有什么建议吗?

    Caused by: java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times
    at org.springframework.core.io.InputStreamResource.getInputStream(InputStreamResource.java:97) ~[task/:na]
    at org.springframework.batch.item.file.DefaultBufferedReaderFactory.create(DefaultBufferedReaderFactory.java:34) ~[task/:na]
    at org.springframework.batch.item.file.FlatFileItemReader.doOpen(FlatFileItemReader.java:266) ~[task/:na]
    at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:146) ~[task/:na]

Class to read from s3 bucket
@Service
public class S3BucketProcessing {
private static final AmazonS3 s3 = AmazonS3ClientBuilder.standard().build();

public InputStreamResource readFile() throws IOException{

   String bucketName = "mybuckey";
   String key = "File.txt";

   S3Object object = s3.getObject(new GetObjectRequest(bucketName, key));    

   return new InputStreamResource(object.getObjectContent());

}

Spring Batch 读取器类

    @Component
public class MyReader extends FlatFileItemReader<MyEntity> {

    MyLineMapper mapper;
    MyTokenizer tokenizer;
    S3BucketProcessing s3BucketProcessing;

    @Autowired
    public MyReader(MyTokenizer tokenizer, MyLineMapper mapper, S3BucketProcessing s3BucketProcessing) throws Exception{
        LOG.info("CardCustomerNotificationReader constructor");
        this.mapper = mapper;
        this.tokenizer = tokenizer;
        this.s3BucketProcessing= s3BucketProcessing;
        this.setResource(s3BucketProcessing.readFile());
        mapper.setLineTokenizer(tokenizer);
        this.setLineMapper(mapper);
    }
}
3个回答

19

1
谢谢,您能否分享一个在我的情境下如何实现的例子。 - Maana
这会导致更大的文件出现内存不足的问题吗? - VinuIsNotUnix
是的。如果您在内存中保存一个大文件,如100MB+,或者多个较小的文件,那么它将占用堆空间的相应大小。您需要确定是否值得在内存中拥有这么多数据。此外,它会停留一段时间吗?或者,在不再需要它时,它还会挂起(例如,尽管不再需要它,但仍存在某些静态引用)吗? - Teddy

1

不要返回InputStreamResource,而应该返回流的内容,例如byte[]。
byte[] content = IOUtils.toByteArray(object.getObjectContent()); 返回内容;


那么我该如何设置 -> this.setResource(s3BucketProcessing.readFile()); - Maana

0

所以我必须将JSON/XML对象作为输出流发送。我使用了InputStreamResource,但是遇到了与OP相同的错误。

这是对我有效的解决方案。

    @Override
    public Resource dataExportForFieldExtractorModel() {

        ObjectMapper xmlMapper = new XmlMapper().enable(SerializationFeature.INDENT_OUTPUT);
        byte[] data;
        Resource resource = null;
        try {
            data = xmlMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(new DataExportResponse());
            resource = new ByteArrayResource(data);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return resource;
    }

由于资源需要是byte[],我将resource = new InputStreamResource(new ByteArrayInputStream(data));更改为resource = new ByteArrayResource(data);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接