(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中写的将指定的字节写入此缓冲的输出流。

posted @ 2017-07-22 15:09  测试开发分享站  阅读(197)  评论(0编辑  收藏  举报