关于网络IO流InputStream.available()相关注意事项

遇到的问题

笔者在进行开发时,从网络中获取对应文件时,需要知道inputStream的大小,经过搜索引擎查询之后得知available可以解决该问题。结果在项目运行时候经常出现数据为0。

原因

在解释这个问题之前,我们都必须知道available返回值,根据api的提示是avaliable用于返回非阻塞情况下,一次性可读的字节数。而SocketInputStream是阻塞的,available的数字每次取决于网络状况。
我们都知道网络是不可靠的,这就导致了有时候获取的是0(双方tcp建立通信,发送方才发送了数据接收方还没来得及接受就被读取了),有时候获取的又不是0,极有可能是因为网络波动导致的SocketInputStream阻塞。

相关知识

为什么FileInputStream.available()读取大小没有问题?

从源码我们可以看出文件流重写了该方法,且获取文件是通过fd.descriptor即文件描述符来获取文件大小的

    ** 
        * Returns the number of bytes that are available before this stream will 
        * block. This method always returns the size of the file minus the current 
        * position. 
        *  
        * @return the number of bytes available before blocking. 
        * @throws IOException 
        *             if an error occurs in this stream. 
        * @since Android 1.0 
        *  
       @Override  
       public int available() throws IOException {  
           openCheck();  
      
            BEGIN android-added  
      
            Android always uses the ioctl() method of determining bytes  
            available. See the long discussion in  
            org_apache_harmony_luni_platform_OSFileSystem.cpp about its  
            use.  
      
           <span style="color: #ff0000;">return fileSystem.ioctlAvailable(fd.descriptor);<span>  
            END android-added   
      
            BEGIN android-deleted  
            synchronized (repositioningLock) {  
                 stdin requires special handling  
                if (fd == FileDescriptor.in) {  
                    return (int) fileSystem.ttyAvailable();  
                }  
             
                long currentPosition = fileSystem.seek(fd.descriptor, 0L,  
                        IFileSystem.SEEK_CUR);  
                long endOfFilePosition = fileSystem.seek(fd.descriptor, 0L,  
                        IFileSystem.SEEK_END);  
                fileSystem.seek(fd.descriptor, currentPosition,  
                        IFileSystem.SEEK_SET);  
                return (int) (endOfFilePosition - currentPosition);  
            }  
            END android-deleted  
       }  

为什么网络传输的小文件传输时就没有问题呢?

以太网最大mtu为1500,这意味着网络传输中,在保证网络质量的情况下,1500以内的网络文件大小是可以通过available获取的。若大于1500则文件会被切片,导致文件流在available时获取的大小很不稳定。
读者可以根据下方代码下载小于1500字节的数据试试看

public static void getHttpRequestData(String urlPath) {

        // 首先抓取异常并处理
        String returnString = "1";
        try {
            // 代码实现以GET请求方式为主,POST跳过
            /** 1 GET方式请求数据 start*/

            // 1  创建URL对象,接收用户传递访问地址对象链接
            URL url = new URL(urlPath);

            // 2 打开用户传递URL参数地址
            HttpURLConnection connect = (HttpURLConnection) url.openConnection();

            // 3 设置HTTP请求的一些参数信息
            connect.setRequestMethod("GET"); // 参数必须大写
            connect.connect();

            // 4 获取URL请求到的数据,并创建数据流接收
            InputStream isString = connect.getInputStream();
            System.out.println(isString.available());
           

   


        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }

对应解决方案

既然文件流可以根据文件描述,那么为什么网络文件不能根据网络传输协议中的描述符获取文件大小呢?
这时候,我们就想到http协议中一个重要的字段header中的Content-Length。在http的协议中Content-Length头部告诉浏览器报文中实体数据的大小。

			 URL url = new URL(urlPath);

            // 2 打开用户传递URL参数地址
            HttpURLConnection connect = (HttpURLConnection) url.openConnection();

            // 3 设置HTTP请求的一些参数信息
            connect.setRequestMethod("GET"); // 参数必须大写
            connect.connect();

            // 4 获取URL请求到的数据,并创建数据流接收
            InputStream isString = connect.getInputStream();

           

          
            System.out.println(connect.getContentLength());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shark-chili

您的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值