确定InputStream的大小


77

我目前的情况是:我必须读取文件并将内容放入InputStream。之后,我需要将的内容InputStream放入一个字节数组,该数组需要(据我所知)的大小InputStream。有任何想法吗?

根据要求,我将显示从上传文件创建的输入流

InputStream uploadedStream = null;
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
java.util.List items = upload.parseRequest(request);      
java.util.Iterator iter = items.iterator();

while (iter.hasNext()) {
    FileItem item = (FileItem) iter.next();
    if (!item.isFormField()) {
        uploadedStream = item.getInputStream();
        //CHANGE uploadedStreambyte = item.get()
    }
}

该请求是一个HttpServletRequest对象,类似于FileItemFactoryServletFileUpload,来自Apache Commons FileUpload包。

Answers:


14

我只想添加,Apache Commons IO具有流支持实用程序来执行复制。(顺便说一句,将文件放入输入流是什么意思?您可以向我们展示您的代码吗?)

编辑:

好的,您要如何处理项目的内容?有一个item.get() 整个内容以字节数组形式返回

编辑2

item.getSize()将返回上传的文件大小


我目前将文件保存到数据库中的blob字段中,并以二进制流(输入作为输入流)的形式发送,现在我需要字节流中的输入流,因为我需要对数据进行签名,并且该函数仅占用字节数组。
ChronoXIII,2009年

1
如前所述,item.get()会为您提供字节数组。除非您正在处理多个MB图像,否则不要担心性能大小。
akarnokd

因为图像是由用户上传的,所以可能是这种情况,而且我似乎找不到在服务器端自动修剪图像的方法。:(
ChronoXIII,2009年

自动修剪图像是什么意思?get()将为您提供整个上传的文件(图像)为byte []。然后你继续前进,再次使用它在任何OutputStream.write(),它换到ByteArrayInputStream的,等等
akarnokd

我改变了解决这个职位,因为它的答案更微调为我的当前设置
ChronoXIII

59

这是一个非常老的线程,但是当我搜索该问题时,它仍然是弹出的第一件事。所以我只想添加以下内容:

InputStream inputStream = conn.getInputStream();
int length = inputStream.available();

为我工作。而且比这里的其他答案更简单。

警告:此解决方案无法提供有关流总大小的可靠结果。除了JavaDoc:

请注意,尽管{@code InputStream}的某些实现将返回*流中的字节总数,但许多实现则不会。


81
我认为那是不正确的。来自Javadocs:“请注意,虽然InputStream的某些实现将返回流中的字节总数,但许多实现将不返回。使用此方法的返回值来分配旨在保留此数据中所有数据的缓冲区永远是不正确的。流。” 因此它可能已在您的VM上运行,但可能无法在其他人的VM上运行。 docs.oracle.com/javase/7/docs/api/java/io/…–
Marvo

3
哦,心理。好赶上!我想这个技巧对需要移植的代码不利。我当时在做一个学校项目,所以对我有用。不过,谢谢,很高兴知道未来!
WB Reed

4
当您将所有数据都存储在ByteArrayInputStream中时,这是完美的。
堆高机2014年

9
这是错误的!正如文档中 有关该available()方法的说法所述:“请注意,虽然InputStream的某些实现将返回流中的字节总数,但许多实现不会返回。使用此方法的返回值分配旨在容纳所有字节的缓冲区永远是不正确的。该流中的数据。”
GVillani82

4
答案是误导性的,关于Android文档,有明确说明:“请注意,此方法提供的保证很弱因此在实践中不是很有用”。
克森尼亚

37

我将读入ByteArrayOutputStream,然后调用toByteArray()以获取结果字节数组。您不需要预先定义大小(尽管如果知道的话,这可能是一种优化。在许多情况下,您不需要这样做)


我似乎发现inputstream有一个toString()方法,然后我可以调用getBytes()从字符串创建一个字节数组。我想知道这样做是否有任何性能问题?
ChronoXIII,2009年

您需要注意字节/字符转换。这原本是字节流吗?如果它包含字符,如何编码等。如果您通过网络连接获取这些字符,我会怀疑这是您的主要性能瓶颈,并且我不会担心转换开销
Brian Agnew

我目前将输入流和图像以二进制流的形式读入数据库,这似乎很好用,因为我可以读回后记文件,并且仍然是图像
ChronoXIII,2009年

2
是。您将获得完整的原始字节数组,无需任何转换,没有问题。
akarnokd

1
如果您想要的只是大小,这不是真的内存不足吗?
cdmckay 2013年

19

您必须先读取流,才能确定流中的数据量。但是,您可以要求文件大小:

http://java.sun.com/javase/6/docs/api/java/io/File.html#length()

如果无法做到这一点,则可以将从输入流中读取的字节写到ByteArrayOutputStream中,该字节数将根据需要增加。


在我的场景中,inputstream包含从HTML表单上传的文件,我无法获取文件大小,因为我没有从硬盘上加载文件。
ChronoXIII

1
如果您的输入流具有mark()支持,则可以在开始处进行标记,并完整地阅读它-然后重设()并开始处理它。
akarnokd

1
该文件是图像(可能很大),因此两次读取流会导致性能问题,不是吗?
ChronoXIII

尝试一下。如果速度很慢,则可能会出现性能问题。否则,您不会。就这么简单。
孟买

@ChronoXIII:是的。这就是为什么我要求提供一个小的代码示例,以便我们可以看到您的情况的原因。如果图像已经在内存中(由于文件上传或其他原因),则它将打开更多选项。
akarnokd

8

对于InputStream

org.apache.commons.io.IoUtils.toByteArray(inputStream).length()

对于可选的<MultipartFile>

Stream.of(multipartFile.get()).mapToLong(file->file.getSize()).findFirst().getAsLong()

1
我在任何地方都找不到IoUtils。我猜你的意思是org.apache.commons.io.IOUtils,
ostmond,

IOUtils.toByteArray(inputStream).length对我不起作用。
dev4life

是。它不适用于IOUtils。不知道为什么使用这种方法,以及如何使用它。
UM1979

这是一个返回的字节数组,具有length()方法。我只是忘了加上paranthesis
amstegraf

4

您可以使用Utils.java的getBytes(inputStream)获取InputStream的大小,请检查以下链接

从Inputstream获取字节


这不是一个正确的答案吗?这个解决方案有问题吗?
2015年

2
如果您打算使用输入流,那么它将已经被读取。
琥珀


0

如果您知道自己InputStream是aFileInputStream或a ByteArrayInputStream,则可以使用少量反射来获取流大小,而无需读取全部内容。这是一个示例方法:

static long getInputLength(InputStream inputStream) {
    try {
        if (inputStream instanceof FilterInputStream) {
            FilterInputStream filtered = (FilterInputStream)inputStream;
            Field field = FilterInputStream.class.getDeclaredField("in");
            field.setAccessible(true);
            InputStream internal = (InputStream) field.get(filtered);
            return getInputLength(internal);
        } else if (inputStream instanceof ByteArrayInputStream) {
            ByteArrayInputStream wrapper = (ByteArrayInputStream)inputStream;
            Field field = ByteArrayInputStream.class.getDeclaredField("buf");
            field.setAccessible(true);
            byte[] buffer = (byte[])field.get(wrapper);
            return buffer.length;
        } else if (inputStream instanceof FileInputStream) {
            FileInputStream fileStream = (FileInputStream)inputStream;
            return fileStream.getChannel().size();
        }
    } catch (NoSuchFieldException | IllegalAccessException | IOException exception) {
        // Ignore all errors and just return -1.
    }
    return -1;
}

我敢肯定,这可以扩展为支持其他输入流。


如果您负担得起重新创建inputStream并等待它,则可以阅读全部内容以获取其大小,以作为所有这些内容的后备
android开发人员

-1

使用此方法,您只需要传递InputStream

public String readIt(InputStream is) {
    if (is != null) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"), 8);

        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line).append("\n");
        }
        is.close();
        return sb.toString();
    }
    return "error: ";
}

1
-1,假设InputStream始终为String(因为它可能是二进制数据),所以始终是String,并且在任何情况下都不会返回问题所要求的流大小。此外,它还会\n在数据中添加额外的字节(),因此sb.length()也会不准确。
Vicky Chijwani

好的,我了解,因此当您知道要接收String流时,此功能很有用。\n确实很有必要,因为您必须为接收到的输入提供某种格式,我不希望加长香肠String,所以即使是这些也很\n重要。
卡洛斯·V

-1
    try {
        InputStream connInputStream = connection.getInputStream();
    } catch (IOException e) {
        e.printStackTrace();
    }

    int size = connInputStream.available();

int available()返回一个估计值,该估计值可以从此输入流读取(或跳过)而不会被下一次对此输入流的方法的调用所阻塞。下一个调用可能是同一线程或另一个线程。仅读取或跳过此多个字节不会阻塞,但可能会读取或跳过较少的字节。

InputStream-Android SDK | Android开发人员


这是一个错误,例如我发现available()函数仅返回活动数据大小,而不返回孔流长度。
Ashnet
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.