判断inputstream是否为空

判断inputstream是否为空

Posted by John Doe on 2022-10-17
Words 742 and Reading Time 2 Minutes
Viewed Times

应用背景

  1. 对文件进行格式转换时如word文件转pdf文件,判断流是否为0kb,如果传入0kb的流,Aspose低版本做文件转换时会出现stackoverflow。

  2. 后端对0kb文件的判断,进行一系列处理。

解决方案

1.InputStream.available

InputStream.available

FileInputStream.available

上图为抽象类InputStream及FileInputStream类源码及注释,可以看到注释中使用estimate(估算、估计)即返回的不是真实的流的大小,而且InputStream的available方法永远返回0(The available method for class InputStream always returns 0.)。所以在业务上可以接受这个estimate的值且不是InputStream的available方法可以使用。

2. toByteArray 转字节数组

IOUtils.toByteArray(InputStream) 转成字节数组,既然通过流拿不到大小,我就曲线救国,把流转成字节数组后,不就可以为所欲为了吗。

这么做确实拿到值了,也能准确判断其是否为空。但是你一下子把流都读成字节数组了,不觉得内存可能有些扛不住吗。

InputStream 其实就是自来水管,连着自来水厂,不管后面是一吨水,还是十吨水,这个 InputStream 占的内存都是基本固定的,用专业术语来说,它的空间复杂度是 O(1) 。 你转成字节数组的话,就相当于把十吨水全部存到你家里。数据量小还好,如果碰到大数据量或者高并发,内存一下子就撑爆了。

听我一句劝,除非你能明确评估没有 OOM 风险,否则不要转成字节数组。

3. read第一个字节

既然我们只要判断其是否为空,那我干嘛费这么大劲, InputStream 不是有 read 方法吗,我 read 一次取第一个字节不就可以判断是否为空了吗。

我们前面说过,InputStream 是自来水管,覆水难收啊,你读了一个字节,那流里就少了一个字节。这就好比有个外卖员,你问他汤咸不咸,他喝了一口,说:汤挺好的,不咸。 你拿到少了一半的汤,会是什么心情。 InputStream 虽然提供了 reset 方法,但是默认是抛异常的哦,不是所有流都可以 reset ,就像有多少爱可以重来。

InputStream.reset

4.PushbackInputStream可回退的流

PushbackInputStream ,顾名思义,就是能回退的流,你可以拿它包装一下原始的流,这样就可以实现检查流是否为空了呀。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 检查输入流是否为空,并返回包装后的流
* 请注意,原始流已经被读了一个字节,后续不能直接对原始流进行读取
*
* @param inputStream inputStream
* @return 包装之后的流,后续操作的都是这个流
*/
public InputStream checkStreamIsNotEmpty(InputStream inputStream) throws IOException,
EmptyInputStreamException {
AssertKit.isNull(inputStream, "流不能为null");
PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
int b = pushbackInputStream.read();
if (b == -1) {
throw new EmptyInputStreamException("这个流是空的,啥也没有。 " + inputStream);
}
pushbackInputStream.unread(b);
return pushbackInputStream;
}

原文地址

原文地址


This is copyright.

...

...

00:00
00:00