(85)字节流读写(InputStream OutputStream)、缓冲区
需求:想要操作图片数据,这就要用到字节流
字节流:InputStream OutputStream(写入)
字符流中用的是字符数组,在字节流中用的是字节数组
将字符串转换为字节数组:public byte[] getBytes()
将字符串转换为字符数组:public char[ ] toCharArray()
import java.io.*;
public class FileDemo {
public static void main(String[] args)throws IOException {
//写
FileOutputStream fos=new FileOutputStream("fos.txt");
fos.write("abcde".getBytes());//不用刷新
fos.close();//虽然不刷新,但是得关资源
//读
FileInputStream fis=new FileInputStream("fos.txt");
System.out.println("-----------读的第一种方法----------");
//一个字节一个字节的读:read()方法
/*int num=0;
while ((num=fis.read())!=-1) {
System.out.println((char)num);
}
fis.close();
*/
System.out.println("-----------读的第二种方法----------");
//字节数组的读read(byte[] b)
/*byte[] buf=new byte[1024];
int len=0;
while((len=fis.read(buf))!=-1) {
System.out.println(new String(buf,0,len));
}
fis.close();
*/
System.out.println("-----------读的第三种方法----------");
// TODO Auto-generated method stub
FileInputStream fis=new FileInputStream("fos.txt");
int len1=fis.available();//返回字节数
System.out.println(len1);
byte[] buf1=new byte[len1];//定义一个刚刚好的缓冲区,因为已经知道长度了,无需循环
fis.read(buf1);
fis.close();
//将所有的数据存入数组
//read(byte[]):从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
//这个方法完成了两件事情:1:将字符字节流中的数据放入字符数组中2:返回存入的字节长度
System.out.println(new String(buf1));
对比三种读的方式,第一种循环次数太多,速度太慢;第三种方式,虽然空间正好,因为现在操作的字节流,包括某些电影文件,若电影文件1G,在内存中设置这么大的数组是不合理的,所以一般还是用第二种方式
练习:复制一个图片
1,用字节读取流对象和图片关联
2,用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
3,通过循环读写,完成数据的存储
4,关闭资源
注意:字符流只能用于处理文字数据,不能处理图片数据。
FileInputStream:可以用于读取诸如图像之类的原始字节流
import java.io.*;
public class PictureCopy {
public static void main(String[] args) {
// TODO Auto-generated method stub
FileOutputStream fos=null;
FileInputStream fis=null;
try {
fos=new FileOutputStream("picture.png");
fis=new FileInputStream("C:\\picture.png");
int len=0;
byte []buf=new byte[1024];
while((len=fis.read(buf))!=-1) {
fos.write(buf,0,len);
}
}catch(IOException e) {
throw new RuntimeException("复制失败");
}
finally {
try {
if(fis!=null)
fis.close();
}catch(IOException e) {
throw new RuntimeException("原文件关闭失败");
}
try {
if(fos!=null)
fos.close();
}catch(IOException e) {
throw new RuntimeException("复制文件关闭失败");
}
}
}
}
用缓冲区复制Mp3文件
import java.io.*;
public class BufferaMp3Copy {
public static void main(String[] args) {
FileInputStream fis=null;
FileOutputStream fos=null;
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try{
fis=new FileInputStream("C:\\SBS.mp3");
fos=new FileOutputStream("SBS.mp3");
bis=new BufferedInputStream(fis);
bos=new BufferedOutputStream(fos);
int num=0;
while((num=bis.read())!=-1) {
bos.write(num);
bos.flush();
}
}catch(IOException e) {
throw new RuntimeException("mp3复制失败");
}
finally {
try {
if(bis!=null)
bis.close();
}catch(IOException e) {
throw new RuntimeException("原关闭失败");
}
try {
if(bos!=null)
bos.close();
}catch(IOException e) {
throw new RuntimeException("新关闭失败");
}
}
}
}
**自定义字节流的缓冲区 **
① 原理图(一次读一个数据(切记)):
定义数组:来充当缓冲区
定义指针:用来确定读取数组的哪号元素
定义计数器:用来确定是否要想数组(缓冲区中存入一批数组)
import java.io.*;
public class MyBuffer {
private InputStream in;
private byte[] buf=new byte[1024];
private int pos=0,count=0;
MyBuffer(InputStream in){
this.in=in;
}
//一次读一个字节(所以没有循环),从缓冲区(字节数组)获取
public int myRead()throws IOException{
//通过in对象读取硬盘上的数据,并存储在buf中
if(count==0) //在count为0,即缓冲区中没数据了,才需要从硬盘上取数据
{
count=in.read(buf);
if(count<0)
return -1;
pos=0;
byte b=buf[pos];//取了每次装入缓冲区的第一个元素
count--;
pos++;
return b&255;
}
else if(count>0)
{
byte b=buf[pos];
count--;
pos++;
return b&255;
}
return -1;
}
public void myClose()throws IOException {
in.close();
}
}
mp3数据都是由二进制数据组成的,读一个字节就是读8个二进制位,
11111111-11111000000000011111100000
11111111是-1
【负数的二进制是正数的二进制全取反然后加1。
1的二进制为00000001,取反11111110,加1,11111111】
当读取到11111111(1byte),就返回int(4byte),相当于类型提升。
byte:-1 ----->int:-1
11111111 —>11111111 11111111 11111111 11111111
这样提升完,还是-1,与判断没有数据的条件还是一样,仍然不能继续复制。
就可以补0,而不是补1,就避免了不能复制的情况同时原数据没发生变换(也是返回int类型的原因)
00000000 00000000 00000000 11111111
那么怎样补0呢?(取一个数的最低8位)
11111111 11111111 11111111 11111111
&00000000 00000000 00000000 11111111
00000000 00000000 00000000 11111111
11111111---->提升了一个int类型,还是-1的原因是在8个1的前面补1造成的。
那么只要在前面补0,既可以保留字节数据不变,也可以避免-1的出现。
** 上面的byte–>int类型转换理解后,还有个疑问,就是读出来的是int类型,复制出来的文件应该容量x4,但是从测试结果看出,并没有扩大容量,原因是?**
read类型提升,在write中是类型下降,即在API中写的将指定的字节写入此缓冲的输出流。