[19/03/30-星期六] IO技术_四大抽象类_ 字节流( 字节输入流 InputStream 、字符输出流 OutputStream )_(含字节文件缓冲流)...

一、概念及分类

       InputStream(输入流)/OutputStream(输出流)是所有字节输入输出流的父类

【注】输入流和输出流的是按程序运行所在的内存的角度划分的

          字节流操作的数据单元是8的字节,字符流操作的数据单元是16位的字符

【流的概念】

——————————

ooooooooooooooooo

—————————— (输入流模型,文件从头(左边)到尾(右边),)

↑,(记录指针)

 

每个‘’o“”看出一个"水滴",不管是字节流还是字符流,每个水滴是最小的输入/输出单位,对于字节流而言,每个水滴是1个字节(8位)

对于字符流而言,每个水滴是1个字符(16位)。输入流使用隐含的记录指针来表示当前正准备从哪个水滴开始读取,每当程序从InputStream或

Reader里取出一个或多个水滴后,指针自动向后(指针从左往右)移动。此外,还可以控制记录指针的移动,比如说设置偏移量off。

对于输出流相对于把水滴放入输入流水管中,也有记录指针自动控制移动,每当程序向OutputStream或Writer输出一个或多个水滴后,记录指针自

动向后移动。

 

1、InputStream(重要的是 文件操作字节流FileInputStream子类和带8KB缓冲数组的ButteredInputStream)

      此抽象类是表示字节输入流的所有类的父类。InputSteam是一个抽象类,它不可以实例化。 数据的读取需要由它的子类来实现。根据节点的不同,

它派生了不同的节点流子类 。 继承自InputSteam的流都是用于向程序中输入数据,且数据的单位为字节(8 bit)。

      int read():从(所写程序的源文件中)一个一个字节读取数据,并将字节的值作为int类型返回(0-255之间的一个值)。

                         如果未读出字节则返回-1(返回值为-1表示读取结束)。

      int (byte b[]) :一段一段的读取数据

      void close(): (通知操作系统)关闭输入流对象,释放相关系统资源。

【代码示例】字节文件操作流_不带缓冲数组 (FileInputStream)

  1 /*输入流(从数据源输入到程序中) :数据源-->>程序,是从数据源(源文件、类比书本上知识)读取(read)数据到程序(目标程序、大脑)
  2  * 输入流对应read()方法 ,从书本上流入(输入、Input)到大脑中,而大脑需要读取(read)书本上的知识  
  3 * 步骤:选择源数据-->>选择流(选哪个搬家公司)-->>操作(一个一个读/写or一段一段读/写,即怎么搬家)-->>释放系统资源(让搬家公司走)
  4  *  
  5   一、 read():从输入流中读取一个8位的字节的数据,(程序自动)把它转成0-255之间的整数,并返回这个整数。 采用逐个读取字节
  6 1.从读取流读取的是一个一个字节 
  7 2.返回的是字节的(0-255)内的字节值 ASCII码
  8 3.读一个下次就自动到下一个,如果碰到-1说明没有值了.
  9 
 10  二、 read(byte[] bytes): 从输入流中最多读取bytes.length(定量)个字节的数据(最后一次可能不满,前面肯定是满的),并将
 11  它们存在byte数组中,返回实际读取的字节数
 12 1.从读取流读取一定数量的字节,如果比如文件总共是102个字节
 13 2.我们定义的数组长度是10,那么默认前面10次都是读取10个长度
 14 3.最后一次不够十个,那么读取的是2个
 15 4.这十一次,每次都是放入10个长度的数组.
 16 
 17  三、read(byte[] bytes,int off ,int len):从输入流中最多读取len个字节(字节可以设定,但不超过数组最大容量)将其存在bytes
 18 数组中,但放入数组的时候并不是从起点开始的是从可以自己设定的off位置开始的(当然可以设为0,表示从起点开始)返回实际读取的字节数
 19 1.从读取流读取一定数量的字节,如果比如文件总共是102个字节
 20 2.我们定义的数组长度是10,但是这里我们写read(bytes,0,9)那么每次往里面添加的(将只会是9个长度),就要读12次,最后一次放入3个.
 21 3.所以一般读取流都不用这个而是用上一个方法:read(byte[]);
 22 
 23   void close()关闭输入流并释放与该流相关的所有系统资源
 24  */
 25 package cn.sxt.test;
 26 
 27 import java.io.File;
 28 import java.io.FileInputStream;
 29 import java.io.IOException;
 30 import java.io.InputStream;
 31 
 32 
 33 public class Test_0329_InputStream {
 34     public static void main(String[] args) throws IOException { //与外界(操作系统读写)有联系,可能有异常,所以抛出异常
 35         //1、选择源文件 内容为:hello China I love you
 36         File file=new File("编码_GBK_纯英文.txt");    //GBK编码 英文占一个字节
 37         //2、选择流 FileInputStream 顺序的读取文件,只要不关闭每次调用read()方法就顺序的读取源数据中【剩余】的内容
 38         InputStream iStream=new FileInputStream(file);
 39         
 40         //这种写法也对,综合了第一步和第二步,更加简单
 41         FileInputStream iStream2=new FileInputStream("编码_GBK_纯英文.txt");
 42         
 43         //3-1-1、有点绕的写法   测试read()方法选择操作 (读/写) 循环读取 一个一个字节去读
 44         /*int temp;
 45         while ((temp=iStream.read())!=-1) {
 46             System.out.print((char)temp);
 47             
 48         }*/
 49          //3-1-2、最可以让人理解的一种写法
 50         /*int b=0;//b的作用记住每次读取的一个字节的整形返回值(英文、数字及常见符号其实就是ASCII码的值)
 51         while (true) {
 52             b=iStream.read();
 53             if (b==-1) {//如果读出字节为-1 跳出整个循环表示已经到文件末尾
 54                 break;
 55             }
 56             System.out.print((char)b);
 57         }*/
 58         
 59         
 60         /*//3-2 测试read(byte[] b)方法 将数据读取到准备好的字节数组(byte[],这里名字叫datas)中,同时返回读取字节数组的实际长度
 61         // 如果到结尾,返回-1
 62         byte datas[]=new byte[4]; //新建一个大小为4的字节(byte)数组,名字叫datas.
 63         int length=iStream.read(datas);//length=4 就是每次读取时字符的实际长度,因为读到最后是可能剩余的字符不足4 可能为3
 64                                  //当最后读取完后,再去读取时发现没有了,则返回-1 表示读取结束
 65          //String msg2=new String(datas, 0, datas.length, "GBK"); 标准解码语句
 66         String msg2=new String(datas, 0, length); //字节数组解码成字符 
 67         System.out.println(msg2); //输出 "hell" 因为没用循环只表示一次读取的情况,一次只读取了4个字节的字符
 68         //可以加循环或者加大datas数组的大小,让其一次读完 
 69         */
 70          
 71         
 72         
 73         //3-3 测试read(byte[] b,int off,int len)方法 。读取任意一段字节。off(偏移量):表示把源文件中从头(即下标)开始读取到的字节数存在
 74         //datas数组下标为off开始的位置,读取源文件的长度为len,也就是在datas数组中下标为off开始位置存储长度为len字节的源数据 
 75         byte datas[]=new byte[7];
 76         
 77         //虽然定义的数组datas大小为7个字节,但每次只添加4个字节的字符,表示使用datas数组的实际使用空间为4个字节。
 78         //2的含义:表示把读取到数据存在datas数组下标为2的位置 即datas[2]='h'意味着datas[0]=datas[1]=0,即null空字符
 79         //4的含义:在datas数组中从下标为2的位置开始存储一段长度为4的源数据字节(从源文件开头读的) 即
 80         //datas[2]=104,'h';datas[3]=101,'e';datas[4]=108,'l';datas[5]=108,'l' datas[6]=0 ,null
 81         int length=iStream.read(datas, 2, 4);//read()方法返回length=4 4:代表实际存储一段长度为4的字节,其它下标位置存储为空
 82         System.out.println(length);
 83         for (int i=0;i) {
 84             System.out.printf("datas[%d]=%d;",i,datas[i]);
 85             
 86         }
 87         
 88         
 89         //ASCII码 (范围 0-127)null 0;a 97;b 98;c 99;d 100;e 101;f 102; g 103 ;h 104;i 105; g 106;k 107;l 108  
 90         //字节数组解码成字符  从数组datas下标为1的地方开始解码(只测试纯英文的情况,含中文数字可能报异常)。
 91         //解码长度length=4,代表解码一段长度为4的字节码文件 输出" hel";也可以length-1 解码一段长度为3的datas数组文件
 92         //输出结果为" he"  
 93         String msg2=new String(datas, 1, length); //String 构造方法,字节-->>字符 
 94         System.out.println("\n"+msg2); 
 95         
 96         
 97         /*
 98         int data1=iStream.read();//读取第一个字符 "h" 输出的是"h"的ASCLL码104 
 99         int data2=iStream.read();//读取第二个字符 "e"
100         int data3=iStream.read();//读取第三个字符 "l"
101         System.out.println(data1);//返回的数据的ASCII码需要强制转型 。文件的末尾如果没有数据返回-1
102         System.out.println((char)data2);
103         System.out.println((char)data3);*/
104         
105         //4、释放资源
106         iStream.close();
107         
108     }
109 
110 }

 

2、 OutputStream  (重要的是 文件操作字节流FileOutputStream子类和带8KB缓冲数组的ButteredOutputStream子类))

      此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节并将这些字节发送到某个目的地。

      void write(int n):向目的地(即所写程序)中写入一个字节。

      void write(byte b[]):一段一段去写数据

      void  (byte b[],int off,int len) :从指定的字节数组写入len字节,从偏移量off开始输出到此输出流

      void flush() :刷新此输出流,并强制任何缓冲的输出字节流被写出。

      void close(): (通知操作系统)关闭输出流对象,释放相关系统资源。

【代码示例】

 1 /*
 2 *输出(Output)流(Stream)。
 3 *通过写字( write()方法 ),把大脑中的知识(类比程序)输出(写出)到(Output)外界的作业本上(类比源文件,如a.txt文件),去更改作业本上原有的内容
 4 步骤:创建源-->>选择流-->>操作(写出内容)-->>释放资源
 5 void write(int n):     向目的地(即所写程序)中写入一个字节。逐个写入字节
 6   n应是读取到的源数据编码值。如把"love"写入目标文件, 一个一个字节读,读到'l' 此时这里的n应该是'l'的ASCII码值108,依次往下读
 7    while(( len=in.read() )!=-1){
 8          out.write(len);
 9    } 这段程序完成文件的复制,表示读到的十进制编码值(0-255之间,英文就是ASCII码),然后把这个值送到write()方法中,让其执行写入操作
10     但是效率很低,它是读一个字节取到编码值后,然后再根据编码值去写入,循环往复。一个字节一个字节读和写.好比很多货物但每次只送一个,
11     循环往复,尽管车厢很大,只装一个,浪费油。电脑中就是浪费内存,不停进行磁盘读写,速度很慢。       
12     
13 void write(byte b[]):一段一段去写数据。把参数b指定的字节数组的【所有字节】写入到目标文件中去。批量写入
14    为了提高送货速度则可以每次把车厢装满,减少送货次数 车厢就是byte[]数组 批量送货,减少磁盘读写
15 void  (byte b[],int off,int len) :将指定的byte数组【从偏移量off开始的len个字节】写入到目标文件。 批量写入
16 
17 void flush() :刷新此输出流,并强制写出所有缓冲中的字节
18 void close() : 关闭输出流并释放系统资源
19 
20  * 
21  */
22 package cn.sxt.test;
23 
24 import java.io.File;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.OutputStream;
28 
29 public class Test_0329_OutputStream {
30     public static void main(String[] args) throws IOException {
31         //1、给出输出流目的地(给出作业本)(与read()不同那个源文件必须存在,才可以被正确读出,这里可不存在,帮你创建源文件)
32         File file=new File("编码_GBK_输出流.txt");
33         //2、创建指向目的地的输出流。参数:true:(前提是文件已存在)表示同意在文件末尾追加新字节数组, false:表示不同意,即覆盖目的地文件的内容
34         OutputStream oStream=new FileOutputStream(file,true);
35         //3、让输出流把字节数组写入目的地
36         String msg="I love you";
37         byte datas[]=msg.getBytes();
38         //ASCII码 :范围是十进制的 0-127
39         //byte:整形变量(8位,范围十进制的-128-127) 字符串-->>字节存在名叫datas的数组 :编码
40         //再次理解getBytes()方法: 此方法所做的工作就是英文字符(按GBK的方式,本电脑eclipse默认是GBK)进行编码,然后把它们的
41         //十进制编码存在datas数组中,GBK中文占3个字节,英文占1个字节.GBK兼容ACSII码,所以英文字符的编码就是它们的ACSII码
42         //而且一个datas数组下标对应一个字节,对于英文1个下标存储1个字符如:datas[0]=73对应英文字符'I' datas[1]=32 对应' '(空格)
43         //假设有中文字符则是datas[n-1][n][n+1]这3个连续的空间共同存储一个中文字符(占3个字节)。这3个空间返回的分别是这个        
44         //中文字符的编码的(23-16位,15-8位,7-0位)的十进制数。
45         
46         for (int i=0;i) {
47             System.out.printf("datas[%d]=%d;",i,datas[i]);
48             //3-1:利用循环向txt文件中一个一个字节写入
49             //oStream.write(datas[i]);
50             
51         }
52         //3-2 一段一段字节去写入
53         //oStream.write(datas);//把datas数组中的全部字符写入目的文件
54         
55         //3-3 写入部分字节  往目的地的txt文件中写了datas数组的部分字节(从下标2(字符'l')开始,长度为8的一段字节)
56         oStream.write(datas, 2, datas.length-2);
57         
58         //4、关闭输出流
59         oStream.close();;
60     }
61 
62 }

 

【示例】利用输入流和输出流进行文件复制_不带缓冲数组 (FileInputStream)

 1 /*
 2  *利用输入流和输出流完成文件的复制
 3  * 输入流(InputStream)  书本的知识输入到大脑中,大脑要读取(read)知识
 4  * 输出流(OutputStream) 大脑中的知识要写出(write)到作业本上
 5  * 1、为了减少对硬盘的读写次数,提高效率,通常设置缓存数组。相应地,读取时使用的方法为:read(byte[] b)
 6  *                                    写入时的方法为:write(byte[ ] b, int off, int length)。
 7  */
 8 package cn.sxt.test;
 9 
10 import java.io.File;
11 import java.io.FileInputStream;
12 import java.io.FileOutputStream;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.OutputStream;
16 
17 public class Test_0330_CopyFile {
18     public static void main(String[] args) throws Exception {
19 
20         //copy("SongYi.jpg", "Song2.jpg"); 图片也可复制,但是要注意设置缓冲数组的大小
21         copy("src.txt", "src_copy3.txt");
22     }
23 
24 
25     static void copy(String src,String dest) throws IOException{
26         //1、获取源数据
27         File file =new File(src);//源文件 从这里读取字节
28         File file2=new File(dest);//目标文件 往这里写入字节
29 
30         //2、选择流
31         InputStream iStream=new FileInputStream(file);//输入流 。从源文件(书本)输入到程序中(大脑中)
32         OutputStream oStream=new FileOutputStream(file2);//输出流。 从程序中(大脑中)输出到目标文件(作业本)上.采用的是覆盖,而不是追加
33 
34         //3、选择操作
35         /*把读到数据存在butter数组从下标0开始的位置,每次存储长度为数组的长度(也即一次就读完)。若butter.length 改为4表示
36          *每次只读取源文件的(从头开始的)前4个字节,存在butter[0]--butter[3]中,至于源文件剩下的需要再次运行程序读取或加个循环
37          *对于较大的文件(如图片)可以加大缓冲数组的容量
38          */        
39         byte butter[]=new byte[1024];//缓冲数组,数组的大小为1024 。中转站 大脑
40         
41         /*  //3-1:整体读取写入,每次都固定读取1024个字节
42         iStream.read(butter);
43         oStream.write(butter);*/
44         
45         // 3-2 :可以选择整体读取或者部分读入(即把butter.length的数值改低).这里起到效果是整体读取与3-1是一个道理 
46         iStream.read(butter,0,butter.length);
47         oStream.write(butter, 0, butter.length); 
48         
49         
50         /*//可以具体看看读取到的内容 详细步骤
51         iStream.read(butter,0,butter.length);
52         String msg=new String(butter,0,butter.length);//字节-->>字符串:解码
53         System.out.println(msg);
54         byte datas[]=msg.getBytes();//对读取到的msg字符串进行编码:字符串-->>字节
55         oStream.write(datas, 0, datas.length);  */
56          
57 
58         //4、关闭流
59         oStream.close();
60         iStream.close();
61 
62     }
63 }

 【代码示例】字节文件操作流_带缓冲数组 (ButteredInputStream)大小为8192B(大小就是8KB,2^13次方,1KB=1024B,)

·

 1 /** 
 2  * 学习 BufferedInputStream/BufferedOutputStream 缓冲字节流类
 3  *复制文件  测试Java自带的在缓冲数组的输入输出流
 4  */ 
 5 
 6 package cn.sxt.test;
 7 
 8 import java.io.BufferedInputStream;
 9 import java.io.BufferedOutputStream;
10 import java.io.FileInputStream;
11 import java.io.FileOutputStream;
12 import java.io.IOException;
13 
14 
15 public class Test_0330_Buffered {
16     public static void main(String[] args) throws IOException {
17         /*File file=new File("poem.txt");
18         InputStream iStream=new FileInputStream(file);*/
19         //带缓冲的输入流 缓冲区为8KB 8192B (8192个字节)
20         FileInputStream file=new FileInputStream("poem.txt");
21         BufferedInputStream iStream=new BufferedInputStream(file);
22 
23         FileOutputStream file2=new FileOutputStream("poem2.txt");
24         BufferedOutputStream oStream=new BufferedOutputStream(file2);
25         long  b=System.currentTimeMillis();//获取系统当前时间
26         int len;
27         while ( (len=iStream.read()) !=-1) {
28             oStream.write(len);    //当调用read()或write()方法时 首先将读写的数据存入类内部定义好8KB的数组中,然后一次性
29             //读写到文件中,类似于前边自己自定义的大小为1KB的数组,极大提高读写效率
30         }
31         long  c=System.currentTimeMillis();
32         System.out.println("共花费:"+(c-b)+"毫秒");
33         iStream.close();
34         oStream.close();
35         
36         
37         //不带缓存缓冲的
38         FileInputStream file3=new FileInputStream("poem.txt");
39         FileOutputStream file4=new FileOutputStream("poem3.txt");
40         
41         long  d=System.currentTimeMillis();//获取系统当前时间
42         int length;//不带缓冲区的,老办法,读取一个字节,往文件中写一个字节。循环往复直到结束。速度很慢
43         while ( (length=file3.read()) !=-1) {
44             file4.write(length);    
45         }
46         long  e=System.currentTimeMillis();
47         System.out.println("共花费:"+(e-b)+"毫秒"); //很明显比带缓冲区的花费时间多
48         file3.close();
49         file4.close();
50         
51 
52     }
53 
54 }

 

转载于:https://www.cnblogs.com/ID-qingxin/p/10623587.html

你可能感兴趣的:([19/03/30-星期六] IO技术_四大抽象类_ 字节流( 字节输入流 InputStream 、字符输出流 OutputStream )_(含字节文件缓冲流)...)