zoukankan      html  css  js  c++  java
  • IO流__【字节流】【字节流缓冲区】【read和write特点】


    字符流
    FileReader、FileWriter
    BufferedReader、BufferedWriter

    字节流

    InputStream  此抽象类是表示字节输入流的所有类的超类。 需要定义 InputStream 子类的应用程序必须总是提供返回下一个输入字节的方法
    OutputStream 此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。 

    常用子类FileInputStream、FileOutputStream

    字节流和字符流最大的区别是,字节流可以操作非文本数据,字符流操作非文本数据时会导致文件损坏

    字节流文本操作示例:


    import java.io.*;
    class  FileStream{
    	public static void main(String[] args)  throws IOException
    	{
    		//writeFile();
    		readFile_3();
    	}
    	public static void readFile_3()  throws IOException//3,使用available方法统计个数
    	{
    		FileInputStream fis = new FileInputStream("fos.txt");
    		//int num = fis.available();	//返回有效的字符个数,windows回车符含两个字符
    		byte[] buf = new byte[fis.available()];//直接传入有效的字符个数,大小刚好,不用再循环
    		fis.read(buf);
    		System.out.println(new String(buf));
    		fis.close();
    	}
    	public static void readFile_2()  throws IOException	//2,使用数组提高读取效率
    	{
    		FileInputStream fis = new FileInputStream("fos.txt");
    		byte[] buf = new byte[1024];
    		int len = 0;
    		while ((len=fis.read(buf)) !=-1){	//1,读取fos.txt中内容,一次读一个数组
    			System.out.println(new String(buf,0,len));
    		}
    		fis.close();
    	}
    	public static void readFile_1()  throws IOException//字节流读取
    	{
    		FileInputStream fis = new FileInputStream("fos.txt");
    		int ch = 0;
    		while ((ch=fis.read()) !=-1){	//读取fos.txt中内容,一次读一个字符(两个字节)
    			System.out.println((char)ch);
    		}
    		fis.close();
    	}
    	public static void writeFile() throws IOException	//字节流写入
    	{
    		FileOutputStream fos = new FileOutputStream("fos.txt");//创建fos.txt
    		fos.write("hahahah".getBytes());//该类的write方法接收byte型数组,所以要转型
    		fos.close();	//不需要刷新,但是要关闭资源 
    	}
    }


    【小结】
    1,字符流在底层调用了字节流的缓冲区,所以需要刷新动作;而字节流在操作时则不需要刷新
    2,available()方法要慎用,虚拟机内存默认为64M,如果只用一个大小刚好的缓冲数组,在copy较大的文件时显然是无法承受的,所以还是以第二种方法为主

    【字节流copy图片】

    思路:
    1,用字节读取流读取图片
    2,用字节写入流对象创建图片文件,用于存储获取到的图片数据
    3,通过循环读写,完成数据存储
    4,关闭资源

    import java.io.*;
    class  CopyPicture
    {
    	public static void main(String[] args) 
    	{
    		FileOutputStream fos = null;
    		FileInputStream fis = null;
    		try
    		{
    			fos = new FileOutputStream("G:\2.png");//写入
    			fis = new FileInputStream("G:\1.png");	//读取
    			byte[] buf = new byte[1024];
    			int len = 0;
    			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】

    BufferedInputStream、BufferedOutputStream 

    import java.io.*;
    class CopyMp3 
    {
    	public static void main(String[] args) throws IOException
    	{
    		long start = System.currentTimeMillis();	//模板设计模式
    		copy_1();
    		long end = System.currentTimeMillis();
    		System.out.println((end-start)+"毫秒");	//打印运行时间
    	}
    	public static void copy_1() throws IOException
    	{								//Buffer从硬盘进缓冲区		File读硬盘
    		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("G:\圣诞结-Eason.flac"));//将源文件导入读取流
    		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("G:\圣诞结-陈奕迅.flac"));//目的地
    		int by = 0;
    		while ((by=bis.read()) !=-1){
    			bos.write(by);
    		}
    		bis.close();
    		bos.close();
    	}
    }



    【自定义字节流缓冲区】

    import java.io.*;
    class MyBufferedIOStream 
    {
    	private InputStream in;//装饰模式,私有化成员变量
    	private byte[] buf = new byte[1024];	//1,定义数组
    	private int pos = 0, count = 0;			//2,定义指针pos、3,定义计数器count表示数组中剩余元素个数
    	MyBufferedInputStream(InputStream in){	//装饰类构造函数
    		this.in = in;
    	}
    	public int myRead() throws IOException	//自定义字节流缓冲区read方法,一次读取一个字节,
    	{	
    		if (count == 0)	//计数器为0,则读取一个数组,开始计数
    		{	//通过in对象读取硬盘上数据,存储到buf数组中
    			count = in.read(buf);//read返回该数组中有效元素个数,到末尾返回-1
    			if (count<0)	//健壮性判断、read到达文件末尾返回为-1
    				return -1;	
    			pos = 0;	//执行到这一步说明有一个新的数组,初始化指针
    			byte b = buf[pos];//通过指针获取字节数组元素
    			count--;	//执行一次,元素有效个数-1
    			pos++;		//指针位置右移
    			return b&255;	//该数组字节为byte,通过&与运算将其提升为int型并补上24个0返回
    		}
    		else if (count>0)	//计数器大于0,对数组继续读取就可以了
    		{
    			byte b = buf[pos];
    			count--;
    			pos++;
    			return b&0xff;	//16进制的255
    		}
    	}
    	public static void main(String[] args) 
    	{
    		System.out.println("Hello World!");
    	} 
    }


    缓冲区中read和write的特点

    在计算机中数据都是以二进制存取的,而字节是以byte型存取的
    如果刚好有连续的8个1,直接转成int型就还是-1,而在缓冲区中的read时,就意外满足了-1的控制条件

    从而导致读写操作无法进行,所以字节流缓冲区的read方法必须避免这种情况的发生生

    byte: -1  --->  int : -1;
    00000000 00000000 00000000 11111111  255
    11111111 11111111 11111111 11111111
    11111111  -->提升了一个int类型 那不还是-1吗?是-1的原因是因为在8个1前面补的是1导致的。
    那么我只要在前面补0,即可以保留原字节数据不变,又可以避免-1的出现。
    怎么补0呢?
    			通过&运算补0
     11111111 11111111 11111111 11111111                        
    &00000000 00000000 00000000 11111111 
    ------------------------------------
     00000000 00000000 00000000 11111111 

    结论:
    字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
    因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1;那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。
    所以,为了避免这种情况将读到的字节进行int类型的提升。并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。

    而在write写入数据时,只写该int类型数据的最低8位。




  • 相关阅读:
    Java中字符串indexof() 的使用方法
    .Net Core WebApi(3)—NLog
    .Net Core WebApi(2)—Swagger
    left join 左边有数据,右边无数据
    Angular—入门环境,项目创建,导入项目
    SQLite介绍和使用
    .Net Core-类库中创建CodeFirst
    .Net Core WebApi(1)— 入门
    .Net Jpush极光推送
    Webform中的前后端分离
  • 原文地址:https://www.cnblogs.com/Joure/p/4337213.html
Copyright © 2011-2022 走看看