黑马程序员 Java基础之IO流<二>IO流概述及InputStream字节流

-----------android培训java培训、java学习型技术博客、期待与您交流! ------------

<>IO

 

一、IO流:即Input Output的缩写。数据流是一串连续不断的数据的集合,就像水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流.

数据写入程序可以使一段一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流.

二、特点:

1IO流用来处理设备间的数据传输。

2Java对数据的操作是通过流的方式。

3Java用于操作流的对象都在IO包中。

4)流按操作数据分为两种:字节流和字符流。

5)流按流向分为:输入流和输出流。

注意:流只能操作数据,而不能操作文件。

三、IO流的常用基类:

1)字节流的抽象基流:InputStreamOutputStream

2)字符流的抽象基流:ReaderWriter

注:此四个类派生出来的子类名称都是以父类名作为子类名的后缀,以前缀为其功能;如InputStream子类FileInputStreamReader子类FileReader

所有流都继承于以下四种抽象流类型的某一种:(抽象流)

 

 

.字节流与字符流区别

二者仅仅是操作单位不一样。

InputStreamReader所有输入流的基类,他们都是抽象类,本身不能创建实例,但是他们是所有输入流的模板。

一般来说处理字符或字符串时使用字符流,处理字节或二进制对象时应使用字节流

备注:字符流必须关闭资源,因为它中间有缓冲区!而字节流不需要!但是一般都会(最后)关闭资源!

 

字节流

字节流主要是操作byte(字节)的类型数据:

字节输出流:OutputStream

字节输入流:InputStream

 

字符流

Java中的字符是Unicode编码,是双字节的,1个字符等于 2个字节;

使用字节来处理字符文本就不太方便了,此时可以考虑使用字符流;

字符流主要是操作char的类型数据:

字符输出流:Writer

字符输入流:Reader

 

字节流和字符流在使用上的代码结构都是非常类似的,但是其内部本身也是有区别的,因为在进行字符流操作的时候会使用到缓冲区(内存中),而字节流操作的时候是不会使用到缓冲区的。

在输出的时候,OutputStream类即使最后没有关闭内容也可以输出。但是如果是Writer的话,则如果不关闭,最后一条内容是无法输出的,因为所有的内容都是保存在了缓冲区之中,每当调用了close()方法就意味着清空缓冲区了。那么可以证明字符流确实使用了缓冲区:

字节流:程序文件

字符流:程序缓冲区(内存中)文件

 

如果现在字符流即使不关闭也可以完成输出的话,则必须强制性清空缓冲区:

方法:public void flush() throws IOException

我的总结:

两者相比,肯定使用字节流更加的方便,而且在程序中像图片、MP3等都是采用字节的方式的保存,那么肯定字节流会比字符流使用的更广泛。

但是需要说明的是,但是如果要是想操作中文的话,字符流肯定是最好使的。(字节流的话可能会出现乱码(一个汉字分成了两份)!)

 

<>字节流

一、概述:

1、字节流和字符流的原理是相似的,只不过字节流可以对媒体进行操作。

2、由于媒体数据中都是以字节存储的,所以,字节流对象可直接对媒体进行操作,而不用再进行刷流动作。

3、读写字节流:InputStream     --->  输入流(读)

                              OutputStream  --->  输出流(写)

4、为何不用进行刷流动作:

     因为字节流操作的是字节,即数据的最小单位,不需要像字符流一样要进行转换为字节。可直接将字节写入到指定文件中,但是需要在写代码的时候,如果有字符串,要将字符串转为字节数组再进行操作。

5、特有方法:

      int available() --->  放回数据字节的长度,包含终止符

在定义字节数组长度的时候,可以用到这个方法:byte[] = new byte[fos.available()]  fos为字节流对象)

但是,对于这个方法要慎用,如果字节过大(几个G),那么如此大的数组就会损坏内存,超过jvm所承受的大小(指定内存为64M)。

二、拷贝文件例子:

1、思路:

1)用字节流读取流对象和媒体文件相关联

2)用字节写入流对象,创建一个媒体文件,用于存储获取到的媒体文件数据

3)通过循环读写,完成数据的存储

4)关闭资源

Ex.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamDemo2 {

	public static void main(String[] args) throws IOException {
		File file=new File("templist//fis.txt");
		if(!file.exists()){
			file.createNewFile();
		}
		FileInputStream fis=new FileInputStream(file);
		byte[] buf=new byte[1024];
		int len=0;
		while((len=fis.read(buf))!=-1){
			System.out.println(new String(buf,0,len));
		}
		fis.close();
	}

}


01.import java.io.*;  
class CopyPic  
{  
    public static void main(String[] args)   
   {  
        //创建流对象引用   
        FileOutputStream fos = null;  
        FileInputStream fis = null;  
        try{  
            //创建读写流对象   
            fos = new FileOutputStream("2.gif");  
            fis = new FileInputStream("1.gif");  
            int len = 0;  
            //定义字节数组,存储读取的字节流   
            byte[] arr = new byte[1024];  
            //循环读写流,完成数据存储   
            while((len=fis.read(arr))!=-1){  
                fos.write(arr,0,len);  
           }  
        }catch (IOException e){  
            throw new RuntimeException("复制图片失败");  
        }  
        //最终关闭资源   
        finally{  
            if(fos!=null){  
               try{  
                    fos.close();  
                }catch (IOException e){  
                    throw new RuntimeException("写入流关闭失败");  
               }  
            }  
            if(fos!=null){  
                try{  
                    fis.close();  
                }catch (IOException e){  
                    throw new RuntimeException("读取流关闭失败");  
                }         
            }  
        }  
    }  
}

三、字节流缓冲区:

1、读写特点:

read():会将字节byte型值提升为int型值

write():会将int型强转为byte型,即保留二进制数的最后八位。

2、原理:将数据拷贝一部分,读取一部分,循环,直到数据全部读取完毕。

1)先从数据中抓取固定数组长度的字节,存入定义的数组中,再通过然后再通过read()方法读取数组中的元素,存入缓冲区

2)循环这个动作,知道最后取出一组数据存入数组,可能数组并未填满,同样也取出包含的元素

3)每次取出的时候,都有一个指针在移动,取到数组结尾就自动回到数组头部,这样指针在自增

4)取出的时候,数组中的元素再减少,取出一个,就减少一个,直到减到0即数组取完

5)到了文件的结尾处,存入最后一组数据,当取完数组中的元素,就会减少到0,这是全部数据就取完了

3、示意图:

4、自定义字节流缓冲区:

思路:
1
、定义一个固定长度的数组
2
、定义一个指针和计数器用于读取数组长度,和计数数组元素是否取完为0
3
、每次将字节数据存入元素要先将数组中的元素取完


注:取出的是byte型,返回的是int型,这里存在提升的动作,
byte中的八位全为1的时候是byte-1,提升为int类型,就变为int型的-1,,read循环条件就结束了
变为-1的原因是由于在提升时,将byte的八位前都补的是1,即32位的数都是1,即为int型的-1了。
如何保证提升后的最后八位仍为1呢?就需要将前24位补0,就可以保留原字节数据不变,又可以避免转为int型出现-1的情况;
那么要如何做呢?
这就需要将提升为int的数据和前24位为0,后八位仍为原字节数据的这个值做与运算。即和255做与运算即可

import java.io.*;  
class MyBufferedInputStream  
{  
    private InputStream in;  
    byte[] by = new byte[1024*4];  
   private int pos=0,count=0;  
   //传入加强的类   
    MyBufferedInputStream(InputStream in)  
   {  
        this.in = in;  
    }  
    //自定义读取方法   
   public int myRead()throws IOException  
    {  
        //先判断计数器   
        if(count==0)  
        {  
            //计数器为0则存入数据   
           count = in.read(by);  
            //计数器为负则返回-1,说明结束数据读取   
           if(count<0)  
               return -1;  
            //每次从数组中读取数据完,指针要归零,重新移动指针   
            pos = 0;  
            //获取存入数组的元素,并需要让指针和计数器相应变化   
           byte b = by[pos];  
            count--;  
            pos++;  
           //返回读取的值,需要与运算   
            return b&255;  
        }  
       //计数器大于零时,不需要存数据,只需读取   
       else if(count>0)  
        {  
            byte b = by[pos];  
           count--;  
            pos++;  
            return b&0xff;  
       }  
       //为-1时即到数据结尾   
       return -1;  
   }  
   public void myClose()throws IOException  
    {  
        in.close();  
    }  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值