---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
流按操作数据分为两种:字节流与字符流
流按流向分为:输入流,输出流。
首先明确一下
字节流的继承结构
字节流的抽象基类:InputStream,OutputStream。
字节流的使用和字符流相差无几
格式如下
FileOutputStream fs = new FileOutputStream("File.txt");
//创建流对象,建立数据存放文件
fs.write("asfsdf".getBytes());
//这里接收的数据类型必须是字节,所以调用字符串的转换字节的方法,把字符串转换成字节
//调用流对象的写入方法,将数据写入流
fs.close();
对比字节流和字符流的使用,发现字节流操作不用刷新动作,这个详细的内部实现后面再详细解释
问题二:返回值到底代表的是什么,为什么有时候能够要定义一个int型的变量去接收返回值,为什么有时候定义String型去接收返回值
对于字符流
BufferedReader有三个Read(),分别是:
int read():返回int型的数据,理解为把字符强转成int返回,即数据的ASCII码,如果到达流末尾返回“-1”
int read(char[] buf):返回读到的字符数量,到达流末尾返回“-1”
String readLine():返回读到的字符串,如果到达流末尾返回“null”//只有用readLine()才会用null,其余一律用“-1”
FileReader也有三个Read(),分别是:
int read():返回int型的数据,理解为把字符强转成int返回,即数据的ASCII码,如果到达流末尾返回“-1”
int read(char[] buf):返回读到的字符数量,到达流末尾返回“-1”
int read(char[],int off,int len ):返回读到的字符数量,到达流末尾返回“-1”
对于字节流
FileInputStream有两个read(),分别是
int read(byte[] bt):返回读到的字节数量,到达流末尾返回“-1”
int read():返回下一字节数,到达流末尾返回“-1”
BufferedInputStream有两个read(),分别是
int read(byte[],int off,int len):返回读到的字节数量,到达流末尾返回“-1”
int read():返回下一字节数,到达流末尾返回“-1”
总结:
(1)只有用BufferedReader的readLine()才会用到null,其余一律用“-1”作为结束条件
(2)对于有参数的read()方法里有数组形参“byte[]”“char ch”“byte[],int off,intlen”这三种的,返回值都是代表读取到的数据的数目
(3)read()无参数的,分两种讨论
1:字符流:返回int型的数据,理解为把字符强转成int返回,即数据的ASCII码
2:字节流:返回下一字节数
(2)到底什么时候定义int ch;
While((ch=fd.read(char))!=-1)
{}
什么时候定义string str=null;
While((str=bufr.readLine())!=null)
{}
观察上面的代码能够得出规律,用字符缓冲区的readLine()读取行数据时,会有一个返回值,返回值是一行字符串,String型接收,判断用“!=null”;
用字符流对象直接读取数据时,也有一个返回值,但是这个返回值是读取的个数,用int型接收,判断用“!=-1”
弄明白记清楚返回值类型和其代表的意义,可以知道什么时候用int什么时候用string
available()方法能够返回准备读取数据的个数,这个个数把\r\n也计算在内
这个方法的作用是,当数据量比较小的时候,能够用作定义一个恰当的数组,避免资源的浪费
但是一般不建议使用,数据量大的时候,会造成很大的内存消耗,还是以定义确定的数组大小最好
byte[] bt = new byte[1024];
int ch = 0;
int num = fis.available();
while((ch=fis.read(bt))!=-1)
{
fos.write(bt);
}
使用了available()方法之后可以修改为下面代码
int num = fis.available();
byte[] bt = new byte[num];
int ch = 0;
while((ch=fis.read(bt))!=-1)
{
fos.write(bt);
}
但是一般不建议使用,数据量大的时候,会造成很大的内存消耗
还是以定义确定的数组大小最好
问题:BufferedInputStream的read()每次只读一个字节,而FileInputStream的read()也是每次读一个字节,那么BufferedInputStream的效率是如何提高的?
答:BufferedInputStream的内部维护着一个8K的数组,BufferedInputStream一次性把8K的字节读进数组(相当于读进内存),然后read()每次都从数组中取一个字节数据
而FileInputStream每次调用read()都是从硬盘中直接读取数据
从内存中读取数据的速度要远远大于从硬盘读数据
字节流缓冲区的使用和字符流的区别
BufferedInputStream
BufferedOutputStream
用法和字符流的是一样的,都要创建缓冲区对象,然后关联文件
但是这里有一个区别,就是字节流的读取不用定义一个用于临时储存的数组,字节是直接操作数据的
注意是指缓冲区的使用不用定义临时数组,而不是说所有字节流都不用定义,仅限于缓冲区
操作字节流控制循环需要注意的地方
以下这个代码是在自定义实现BufferedInputStream的功能时的代码
class MyBufferedInputStream
{
private InputStream in;
private byte[] buf = new byte[1024*4];
private int pos = 0, count = 0;
MyBufferedInputStream(InputStream in)
{
this.in = in;
}
//一次读一个字节,从缓冲区(字节数组)获取。
public int myRead()throws IOException //为什么读取的是byte类型返回值却是int类型
{
//通过in对象读取硬盘上数据,并存储buf中。
if(count==0)
{
count = in.read(buf);
if(count<0)
return -1;
pos = 0;
byte b = buf[pos];
count--;
pos++;
return b&255; //为什么要&255
}
else if(count>0)
{
byte b = buf[pos];
count--;
pos++;
return b&0xff; // b&0xff;十六进制也是表示255
}
return -1;
}
public void myClose()throws IOException
{
in.close();
}
}
public static void copy_2()throws IOException
{
MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("c:\\9.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\3.mp3"));
int by = 0;
//System.out.println("第一个字节:"+bufis.myRead());
while((by=bufis.myRead())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.myClose();
}
视频讲解+我的理解
由于是直接操作字节,那么在判断循环结束条件的时候,在读到流的末尾的时候,人为地设置返回“-1”,标记到读取数据达了末尾,但是实际字节数据在内存中的存储是以二进制码的形式的,有可能会存在恰好读到“1111 1111”
这个特殊的数据,“1111 1111”转换成十进制就是“-1”,也就是循环结束的标志
问题就出来了,如何解决读到“1111 1111”而不退出呢
publicint myRead()在标志返回值类型的时候用了int,强制把读取到的byte数据类型转成了int,由1个8位二进制提升到4个8位。以读到特殊字节11111111为例。
“(byte)11111111&255”这个步骤就能够把(byte)11111111---->(int)11111111 11111111 11111111 11111111
因为255的二进制的值就是(int) 00000000 00000000 00000000 11111111
通过&运算,就得到4个8位的二进制00000000 00000000 00000000 11111111
这样就能够避免在判断循环结束条件的时候为“-1”
可是真正的有效位是最低8位,这个在bufos.write(by);查阅API文档,
OutputStream的write(int num)读取只保留最低8位
结论:
字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.
那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。
所以,为了避免这种情况将读到的字节进行int类型的提升。
并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。
而OutputStream在写入数据时,只写该int类型数据的最低8位。
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
本文详细介绍了Java字节流与字符流的使用方法,包括流的操作数据类型、流向、返回类型解析及具体实例演示。重点解释了返回类型为int与null的原因及应用场景,并探讨了字节流与字符流缓冲区的使用方法及效率提升策略。
1147

被折叠的 条评论
为什么被折叠?



