Java 输入流中的read(byte[] b)方法详解
作者:Rrrrrandom 发布时间:2022-08-13 18:58:12
我就废话不多说了,大家还是直接看代码吧~
public int read(byte[] b)
throws IOException
从一个输入流中读取一定数量的字节,并将这些字节存储到其缓冲作用的数组b中。这个函数会返回一次性读取的字节数。
这个函数是一个阻塞式的函数,当它读到有效数据、确认的文件尾(EOF)或者抛出一个异常时它才会执行其他语句,否则一直停在read()函数处等待。
比如下面的列子:
ServerSocket server = new ServerSocket(port)
Socket client = server.accept();
BufferedInputStream bis = new BufferedInputStream(client.getInputStream);
byte[] box = new byte[1024];
int len = 0;
while(-1!=(len = bis.read(box))) {
System.out.println(len);
String msg = new String(box, 0, len);
}语句1;语句二;
在这种情况下,当从客户端接收了一条信息并转成msg字符串后,while循环会又回到read()函数,不会跳出循环执行语句一和二。
因为这时read()函数并没有遇到文件尾或者抛出异常,所以下一次while条件判断read()函数会一直等待有效数据的输入,而不是返回-1。此时整个程序将会阻塞在这里。
如果我们是从文件用这个函数以这种while循环方式读取数据的话并不会遇到这个问题,因为读到最后会遇到EOF的。
如果用这种方式读取控制台的输入的话,我们可以选择不要while循环。或者设置条件跳出循环,即如果len小于box的长度话就跳出循环。
我们还可以选择用DataInputStream的readUTF()函数也可以。还有就是我们可以采用监听机制,当监听到输入流中有数据之后再读取。
补充:教你完全理解IO流里的 read(),read(byte[]),read(byte[],int off,int len)以及write
好的我们先来讲它们的作用,然后再用代码来实现给大家看
read():
1.从读取流读取的是一个一个字节
2.返回的是字节的(0-255)内的字节值
3.读一个下次就自动到下一个,如果碰到-1说明没有值了.
read(byte[] bytes)
1.从读取流读取一定数量的字节,如果比如文件总共是102个字节
2.我们定义的数组长度是10,那么默认前面10次都是读取10个长度
3.最后一次不够十个,那么读取的是2个
4.这十一次,每次都是放入10个长度的数组.
read(byte[] bytes,int off ,int len)
1.从读取流读取一定数量的字节,如果比如文件总共是102个字节
2.我们定义的数组长度是10,但是这里我们写read(bytes,0,9)那么每次往里面添加的(将只会是9个长度),就要读12次,最后一次放入3个.
3.所以一般读取流都不用这个而是用上一个方法:read(byte[]);
下面讲解write
write(int i);
直接往流写入字节形式的(0-255)int值.
write(byte[] bytes);
往流里边写入缓冲字节数组中的所有内容,不满整个数组长度的”空余内容”也会加入,这个下面重点讲,
write(byte[] bytes,int off,int len);
1.这个是更严谨的写法,在外部定义len,然后每次len(为的是最后一次的细节长度)都等于流往数组中存放的长度
2.如上述read(bytes),前面每次都放入十个,第十一次放入的是2个,如果用第二种write(bytes),将会写入输出流十一次,每次写入十个长度,造成后面有8个空的,比原来的内容多了
3.所以用write(byte[] bytes,int off,int len);就不会出现多出来的空的情况,因为最后一次len不同
下面是详细的代码
public class Test{
public static void main(String[] args) throws Exception {
UseTimeTool.getInstance().start();
FileInputStream fis = new FileInputStream("D:\\1.mp3");
FileOutputStream fos = new FileOutputStream("D:\\1copy.mp3");
//(PS:一下3个大家分开来写和测试,为了方便我都列出来了)
/*--------------不使用缓冲--------------*/
//如果不缓冲,花了差不多14"秒"
int len = -1;
while ((len = fis.read()) != -1) {
//这里就不是长度的问题了,而是读取的字节"内容",读到一个写一个,相当慢.
System.out.println("len : "+ len);
fos.write(len);
}
/*--------------使用缓冲--------------*/
//缓冲方法复制歌曲用了不到20"毫秒"
//创建一个长度为1024的字节数组,每次都读取5kb,目的是缓存,如果不用缓冲区,用fis.read(),就会效率低,一个一个读字节,缓冲区是一次读5000个
byte[] bytes = new byte[1024*5];
//每次都是从读取流中读取(5k)长度的数据,然后再写到文件去(5k的)数据,注意,每次读取read都会不同,是获取到下一个,直到后面最后一个.
while (fis.read(bytes)!=-1) {
//write是最追加到文件后面,所以直接每次添5K.
fos.write(bytes);
}
/*--------------解释len--------------*/
//告诉你为什么用len
byte[] bytes = new byte[1024*5];
int len = -1;
//解释这个fis.read(bytes)的意思:从读取流"读取数组长度"的数据(打印len可知),并放入数组
while ((len = fis.read(bytes,0,1024)) != -1) {
//虽然数组长度的*5,但是这里我们设置了1024所以每次输出1024
System.out.println("len : "+ len);
//因为每次得到的是新的数组,所以每次都是新数组的"0-len"
fos.write(bytes,0,len);
}
fis.close();
fos.close();
UseTimeTool.getInstance().stop();
}
}
为了方便大家,也给大家一个统计时间的工具类
class UseTimeTool {
private static UseTimeTool utt = new UseTimeTool();
private UseTimeTool() {
}
public static UseTimeTool getInstance() {
return utt;
}
private long start;
public void start() {
start = System.currentTimeMillis();
}
public void stop() {
long end = System.currentTimeMillis();
System.out.println("所用時間 : " + (end - start) + "毫秒");
}
}
好了最后一个:len问题 最后多出数组不满的部分我特再写一个出来给大家分析
首先,文本的内容是
public class Test{
public static void main(String[] args) throws Exception {
UseTimeTool.getInstance().start();
FileInputStream fis = new FileInputStream("D:\\a.txt");
FileOutputStream fos = new FileOutputStream("D:\\acopy.txt");
不使用len:
byte[] bytes = new byte[1024*5];
while (fis.read(bytes)!=-1) {
fos.write(bytes);
}
得到的效果:
发现后续后很多的空部分,所以说不严谨
使用len:
byte[] bytes = new byte[1024*5];
int len = -1;
while ((len = fis.read(bytes,0,1024)) != -1) {
fos.write(bytes,0,len);
}
得到的效果
和原来一模一样,讲了那么多就是希望能帮助大家真正的理解。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。
来源:https://blog.csdn.net/qq_36435294/article/details/79774534


猜你喜欢
- 算法概述/思路归并排序是基于一种被称为“分治”(divide and conquer)的策略。其基本思路是这样的:1.对于两个有序的数组,要
- 在练习Java的Scanner时,EditPlus如何读取从键盘输入的数呢?例如如下程序,编译通过,运行时却输入不了数据:package m
- 在之前项目中有用到关于获取手机联系人的部分,闲置就想和大家分享一下,话不多说,上代码:java部分:package com.example.
- 简介Log4J 是 Apache 的一个开源项目(官网 http://jakarta.apache.org/log4j)
- 1、使用FileStream读写文件 文件头:using System;using System.Collections.Gene
- 本文实例讲述了C#实现XML与实体类之间相互转换的方法。分享给大家供大家参考,具体如下:using System;using System.
- 这篇文章主要介绍了Java线程并发访问代码分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参
- 流是字节序列的抽象概念。文件是数据的静态存储形式,而流是指数据传输时的形态。流类分为两个大类:节点流类和过滤流类(也叫处理流类)。程序用于直
- package 移位运算;public class 移位运算 { public static void main(String[] args
- JWT简介Json Web Token(JWT):JSON网络令牌,是为了在网络应用环境间传递声明而制定的一种基于JSON的开放标准((RF
- 日志过滤对于一个网站日志,首先要对它进行过滤,删除一些不必要的信息,我们通过scala语言来实现,清洗代码如下,代码要通过别的软件打包为ja
- 本文实例讲述了Android编程处理窗口控件大小,形状,像素等UI元素工具类。分享给大家供大家参考,具体如下:/*** 处理窗口控件大小,形
- 本篇主要介绍C#的Excel导入、导出,供大家参考,具体内容如下一. 介绍1.1 第三方类库:NPOI说明:NPOI是POI项目的.NET
- 本文实例为大家分享了Android实现类似微信视频接听的具体代码,供大家参考,具体内容如下1、背景需求:业务需要接入视频审核功能,在PC 端
- java 基础之JavaBean属性命名规范问题JavaBean属性名要求:前两个字母要么都大写,要么都小写下面我们来找找如果不遵循这个规范
- MyBatis使⽤PageHelper1.limit分⻚(1)概念:①页码:pageNum(用户会发送请求,携带页码pageNum给服务器)
- 这篇文章主要介绍了Spring 事件Application Event原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定
- 本文实例为大家分享了JAVA实现人脸识别的具体代码,供大家参考,具体内容如下官方下载 安装文件 ,以win7为例,下载opencv-2.4.
- 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;Thread类是在java.lang包中定义的
- 本文实例讲述了WCF实现的计算器功能。分享给大家供大家参考,具体如下:对于WCF,我们有了前面的理论基础,今天通过一个计算器的实例主要给大家