JAVA---字节流

目录

写入数据

读数据

示例:

字节流的缓冲区

自定义字节流缓冲区

缓冲区中read和write的特点


写入数据

FileoutputStram

class FileStream
{
    public static void writeFile() throws IOException
    {
        FileOutputStream fos = new FileOutputStream("fos.txt")
        //写入需要转化为字节
        fos.write("abc".getBytes());
        //
        fos.close()
    }
}

 

读数据

//一个字节一个字节的读
class FileStream
{
    public static void ReadFile_1() throws IOException
    {
        FileInputStream fos = new FileInputStream(fos.txt);
        
        int ch=0;
        while((ch=fis.read())!=-1)
        {
            System.out.println((char)ch);
        }
    }
}
//一个数组的读
class FileStream
{
    public static void ReadFile_1() throws IOException
    {
        FileInputStream fos = new FileInputStream(fos.txt);
        
        byte[] buf =new byte[1024];
        int len=0;
        while((len=fis.read(buf))!=-1)
        {
            System.out.println(new String(buf,0,len));
        }

        fis.close();
    }
}

 

拿到文件大小

class FileStream
{
    public static void ReadFile_3() throws IOException
    {
        FileInputStream fos = new FileInputStream(fos.txt);
        
        //available返回了文件中数据的个数(回车符算2个,/r/n)
        byte[] buf =new byte[fis.available()]; //定义一个刚刚好的缓冲区,不用在循环了
        
        fis.read(buf);

        System.out.println(new String(buf));
        
        fis.close();
    }
}

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

建议用byte[] buf =new byte[1024];

1.因为现代操作系统的内存管理都具有分页机制,而内存页的大小都是1024的整数倍,定义1024整数倍大小的缓冲区在分配内存时将不会形成碎片。

2.读和写都是放在while循环中的,每次读取1024个字节,也就是1kb,如果最后一次读取和写入可能不够1024个字节,所以写入的时候加了fos.write(buf,0,len);意思是还剩多少就写多少。

 

示例:

复制一个图片

/*
思路:
1.用字节读取流对象和图片关联
2.用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
3.通过循环读写,完成数据的存储
4.关闭资源
*/
class CopyPic
{
    public static void main(Stirng[] args)
    {
        FileOutputStream fos =null;
        FileInputStream fis=null;

        try
        {
            fos = new FileOutputStream("C:\\2.bmp");
            fis = new FileInputStream("C:\\1.bmp");

            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("写入关闭失败");
            }
        }    
    }
}

 

字节流的缓冲区

class Copy
{
    public static void main(String[] args) throws IOException
    {
        //计算运行copy方法需要多长时间
        long start = System.currentTimeMillis();
        copy();    
        long end = System.currentTimeMillis();

        System.out.println((end-start)+"毫秒")
    }

    //通过字节流的缓冲区完成复制
    public static void copy throws IOException
    {
        BufferedInputStream bufis =new BufferedInputStream(new FileInputStream("C:\\0.mp3"));
        BufferedOutputStream bufis =new BufferedOutputStream(new FileOutputStream("C:\\1.mp3"));

        int by =0;
        while(by =bufis.read()!=-1)
        {
            bufos.writer(by);
        }    

        bufos.close();
        bufis.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位,write有强制转换为byte,保证了数据的原样性

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值