10年 Java程序员,硬核人生!勇往直前,永不退缩!

欢迎围观我的git:https://github.com/R1310328554/spring_security_learn 寻找志同道合的有志于研究技术的朋友,关注本人微信公众号: 觉醒的码农,或Q群 165874185

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

InputStream.available()  可以获取InputStream的总的长度吗

答案是不确定。总结如下:

处理文件输入流: 可以

处理网络流(socket):不可以

官方的说明是:

 

 

总之,尽量还是别使用它来获取流的长度, 如果是文件, 我们完全可以使用 file对象的.length()  方法啊! 其他流 也应该有对应的方式获取流的长度,实在没有,那怎么办? 只能读流完之后再获取。

 

 

有人说:

InputStream的available()方法返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。下一个调用可能是同一个线程,也可能是另一个线程。一次读取或跳过此估计数个字节不会受阻塞,但读取或跳过的字节数可能小于该数。
注意,有些 InputStream 的实现将返回流中的字节总数,但也有很多实现不会这样做。试图使用此方法的返回值分配缓冲区,以保存此流所有数据的做法是不正确的。
JDK的解释意味着,我们不能通过该方法来获取InputStream的字节大小进而据此大小来初始化缓冲区的大小。
那么我们只能while循环read:

OutputStream out = new BufferedOutputStream(response.getOutputStream());
        byte[] bytes = new byte[1024];
        int len;
        while ((len = in.read(bytes)) != -1) {
            out.write(bytes, 0, len);
        }
        in.close();
        out.flush();
        out.close();

有人说:

所以调用网络流(socket)的available()方法前,一定记得要先调用read()方法,这样才能避免获取为0的不正确情况。

int firstByte = inputStream.read();
int length = inputStream.available();

没试过,感觉是行不通的,因为 网络缓存的原因, 并不是说你调用一次inputStream.read(); 就能够把 inputStream所有的数据加载到tcp缓存区。

 

---- 下面是转载 https://www.cnblogs.com/zjfjava/p/10829241.html

在处理文件输入流时,可以通过调用available()方法来获取还有多少字节可以读取,根据该数值创建固定大小的byte数组,从而读取输入流的信息。

 

但是在处理网络流(socket)时,通过available()方法对输入流进行长度判断,数值为0,这意味着对方发送的流中无数据,但实际上并非如此。

原因在于:

网络通讯往往是间断性的,一串字节往往分几批进行发送。例如对方发来字节长度100的数据,本地程序调用available()方法有时得到0,有时得到50,有时能得到100,大多数情况下是0。这可能是对方还没有响应,也可能是对方已经响应了,但是数据还没有送达本地。也许分3批到达,也许分两批,也许一次性到达。

详细解释参考OSI网络7层结构:

我们进行的数据接收只是基于应用层,网络传输的最上层,数据从一端到另一端传输的时候,会在传输层分解成适合的数据包。传输层(Transport Layer)是OSI 模型中最重要的一层。传输协议同时进行流量控制或是基于接收方可接收数据的快慢程度规定适当的发送速率。除此之外,传输层按照网络能处理的最大尺寸将较长的数据包进行强制分割。例如,以太网无法接收大于1500 字节的数据包。发送方节点的传输层将数据分割成较小的数据片,同时对每一数据片安排一序列号,以便数据到达接收方节点的传输层时,能以正确的顺序重组。该过程即被称为排序。工作在传输层的一种服务是 TCP/IP 协议套中的TCP(传输控制协议),另一项传输层服务是 IPX/SPX 协议集的 SPX(序列包交换)。

InputStream的available()方法的作用是返回此输入流在不受阻塞情况下能读取的字节数。网络流与文件流不同的关键就在于是否“受阻”二字,网络socket流在读取时如果没有内容read()方法是会受阻的,所以从socket初始化的输入流的available也是为零的,所以要read一字节后再使用,这样可用的字节数就等于 available + 1。但文件读取时read()一般是不会受阻的,因为文件流的可用字节数 available = file.length(),而文件的内容长度在创建File对象时就已知了。 

所以调用网络流(socket)的available()方法前,一定记得要先调用read()方法,这样才能避免获取为0的不正确情况。

复制代码
   //将接收到的数据存到字节数组bytes
    int firstByte = inputStream.read();
    int length = inputStream.available();
    byte[] bytes = new byte[length+1];
    bytes[0] = (byte)firstByte;
    inputStream.read(bytes,1,length);
复制代码

另外,在文件上载和表单提交的过程中,可以使用 request.getContentLength()方法代替InputStream.available()方法,通过调用 request.getContentLength() 得到 Content-Length ,并定义一个与 Content-Length 大小相等的字节数组 buffer,从HttpServletRequest 的实例 request 中得到一个 InputStream, 并把它读入 buffer 中。然后使用 FileOutputStream 将 buffer 写入指定文件。

复制代码
// ReceiveServlet.java
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
//示例程序:记录下Form提交上来的数据,并存储到Log文件中
public class  ReceiveServlet extends HttpServlet
{
    public void doPost(HttpServletRequest request,HttpServletResponse response)
    throws IOException, ServletException
    {
//1
        int len = request.getContentLength();
        byte buffer[] = new byte[len];
//2
        InputStream in = request.getInputStream();
        int total = 0;
        int once = 0;
        while ((total < len) && (once >=0)) {
            once = in.read(buffer,total,len);
            total += once;
        }
//3
        OutputStream out=new BufferedOutputStream(
            new FileOutputStream("Receive.log",true));
        byte[] breaker="\r\nNewLog: -------------------->\r\n".getBytes();
        System.out.println(request.getContentType());
        out.write(breaker,0,breaker.length);
        out.write(buffer);
        out.close();
    }
}
posted on 2021-11-12 20:41  CanntBelieve  阅读(7203)  评论(0编辑  收藏  举报