码迷,mamicode.com
首页 > 编程语言 > 详细

黑马程序员——Java基础---IO(二)---IO字节流、流操作规律

时间:2015-08-08 22:37:46      阅读:228      评论:0      收藏:0      [点我收藏+]

标签:

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

  字节流

一、概述

1、字节流和字符流的基本操作是相同的,但字节流还可以操作其他媒体文件。

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

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

                             OutputStream  输出流(写)

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

        因为字节流操作的是字节,即数据的最小单位,不需要像字符流一样要进行转换为字节。所以可直接将字节数据写入到指定文件中。

5、InputStream特有方法:

        int available();//返回文件中的字节个数

注:可以利用此方法来指定读取方式中传入数组的长度,从而省去循环判断。但是如果文件较大,而虚拟机启动分配的默认内存一般为64M。当文件过大时,此数组长度所占内存空间就会溢出。所以,此方法慎用,当文件不大时,可以使用。

示例

 1 /*
 2 复制一个图片
 3 思路:
 4 1,用字节读取流对象和图片关联。
 5 2,用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。
 6 3,通过循环读写,完成数据的存储。
 7 4,关闭资源。
 8 
 9 */
10 
11 import java.io.*;
12 class  CopyPic
13 {
14     public static void main(String[] args) 
15     {
16         FileOutputStream fos = null;//建立字节文件写入流
17         FileInputStream fis = null;//建立字节文件读取流
18         try
19         {
20             fos = new FileOutputStream("c:\\1.jpg");//关联文件
21             fis = new FileInputStream("1.jpg");//关联文件
22 
23             byte[] buf = new byte[1024];
24 
25             int len = 0;
26 
27             while((len=fis.read(buf))!=-1)//缓冲区提供的 一次读一行的方法,只要不读到末尾
28             {
29                 //fos.write(buf[0]);
30                 fos.write(buf,0,len);
31             }
32         }
33         catch (IOException e)
34         {
35             throw new RuntimeException("复制文件失败");
36         }
37         finally
38         {
39             try
40             {
41                 if(fis!=null)
42                     fis.close();//读取流不为空,则关闭 读取流
43             }
44             catch (IOException e)
45             {
46                 throw new RuntimeException("读取关闭失败");
47             }
48             try
49             {
50                 if(fos!=null)
51                     fos.close();//写入流不为空,则关闭写入流
52             }
53             catch (IOException e)
54             {
55                 throw new RuntimeException("写入关闭失败");
56             }
57         }
58     }
59 }

二、字节流缓冲区

        同样是提高了字节流的读写效率。

1、读写特点:

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

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

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

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

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

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

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

        5)当文件中的全部数据都被读取出时,read()方法就返回-1。

3、自定义读取字节流缓冲区

        需求:根据字节流缓冲区的原理,自定义一个字节流缓冲区。

注意:

        1、字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。

       因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。

       所以,为了避免这种情况将读到的字节进行int类型的提升。并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。而在写入数据时,只写该int类型数据的最低8位。

        2、byte类型的-1提升为int类型时还是-1。原因:因为在bit8个1前面补的全是1导致的。如果在bit8个1前面补0,即可以保留原字节数据不变,又可以避免-1的出现。这时将byte型数据&0xff即255即可。

代码:

 1 /*
 2 演示MP3的复制,通过缓冲区
 3 BufferedOutputStream
 4 BufferedInputStream
 5 */
 6 import java.io.*;
 7 class MyBufferedInputStream
 8 {
 9     private InputStream in;
10 
11     private byte[] buf = new byte[1024*4];//自定义缓冲区  为字节数组
12         
13     private int pos = 0,count = 0;  //pos  确认数组的位置,方便存储,count确认输入的个数,
14     
15     MyBufferedInputStream(InputStream in)
16     {
17         this.in = in;
18     }
19 
20     //一次读一个字节,从缓冲区(字节数组)获取。
21     public int myRead()throws IOException//字节流返回值类型为int,一次读一个的方法读取硬盘上数据,并存储buf中。
22     {
23     
24         if(count==0)
25         {
26             count = in.read(buf);//计数 键盘录入的个数
27             if(count<0)            //当count为零时, 说明已存储完成
28                 return -1;
29             pos = 0;
30             byte b = buf[pos];   //
31 
32             count--;
33             pos++;
34             return b&255;//返回的byte类型提升为int类型,字节数增加,且高24位被补1,原字节数据改变。  
35                          //通过与上255,主动将byte类型提升为int类型,将高24位补0,原字节数据不变。  
36                          //而在输出字节流写入数据时,只写该int类型数据的最低8位。  
37         }
38         else if(count>0)
39         {
40             byte b = buf[pos];
41 
42             count--;
43             pos++;
44             return b&0xff;//
45         }
46         return -1;
47 
48     }
49     public void myClose()throws IOException
50     {
51         in.close();
52     }
53 }
54 class CopyMp3
55 {
56     public static void main(String[] args)throws IOException
57     {
58         long start =System.currentTimeMillis();//获取时间的毫秒数
59         copy_2();
60         long end=System.currentTimeMillis();
61         System.out.println((end-start)+"毫秒");//通过相减可以得出 用时
62     }
63 
64 
65     public static void copy_2()throws IOException  //自定义缓冲区完成复制
66     {
67         MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("1.mp3"));
68         BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
69         
70         int by = 0;
71 
72         //System.out.println("第一个字节:"+bufis.myRead());
73 
74         while((by=bufis.myRead())!=-1)
75         {
76             bufos.write(by);
77         }
78 
79         bufos.close();
80         bufis.myClose();
81     }
82     
83     public static void copy_1()throws IOException//通过字节流的缓冲区完成复制
84     {
85         BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("1.mp3"));
86         BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("2.mp3"));
87 
88         int by=0;
89 
90         while((by=bufis.read())!=-1)
91         {
92             bufos.write(by);
93         }
94         bufos.close();
95         bufis.close();
96 
97     }
98 }

                                                                流操作规律

一、键盘录入以及

1、标准输入输出流

        System.in:对应的标准输入设备,键盘。

        Ssytem.out:对应的是标准的输出设备,控制台。

        System.in的类型是InputStream.

        System.out的类型是PrintStream是OutputStream的子类FilterOutputStream的子类。

2、整行录入

       当使用输入流进行键盘录入时,只能一个字节一个字节进行录入。为了提高效率,可以自定义一个数组将一行字节进行存储。当一行录入完毕,再将一行数据进行显示。这种正行录入的方式,和字符流读一行数据的原理是一样的。也就是readLine方法。

      那么能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?readLine方法是字符流BufferedReader类中方法。而键盘录入的read方法是字节流InputStream的方法。

      那么能不能将字节流转成字符流再使用字符流缓冲区的readLine方法呢?这就需要用到转换流了。

3、转换流

3.1 转换流的由来:

       a、字符流与字节流之间的桥梁

       b、方便了字符流与字节流之间的操作

转换流的应用:

      字节流中的数据都是字符时,转成字符流操作更高效。

3.2   InputStreamReader将字节流通向字符流

       a、获取键盘录入对象。

              InputStream in=System.in;

       b、将字节流对象转成字符流对象,使用转换流。

              InputStreamReaderisr=new InputStreamReader(in);

       c、为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader

              BufferedReaderbr=new BufferedReader(isr);

       //键盘录入最常见写法

              BufferedReaderin=new BufferedReader(new InputStreamReader(System.in));

3.3   OutputStreamWriter字符流通向字节流

       字符通向字节:录入的是字符,存到硬盘上的是字节。步骤和InputStreamReader转换流一样。

示例:

  1 import java.io.*;
  2 
  3 /*
  4 1
  5 源:键盘录入
  6 目的:控制台
  7 
  8 2    需求:想把键盘录入的数据存储到一个文件中
  9 
 10 源:    键盘
 11 目的:  文件
 12 
 13 3    需求:  想要将一个文件的数据打印在控制台上
 14 源:    文件
 15 目的:    控制台
 16 
 17 流操作的基本规律:
 18 最痛苦的就是流对象有很多,不知道该用哪一个。
 19 
 20 通过三个明确来完成。
 21 1    明确源和目的、
 22         源:    输入流。    InputStream        Reader
 23         目的:    输出流。    OutputStream    Writer
 24 2    操作的数据是否是纯文本。
 25         是:字符流
 26         不是: 字节流。
 27 3    当体系明确后,在明确要使用哪个具体的对象。
 28         通过设备来进行区分:
 29         源设备:  内存,硬盘,键盘
 30         目的设备: 内存,硬盘,控制台
 31 
 32 1    将一个文本文件中数据存储到另一个文件中,复制文件。
 33         源:因为是源,所以使用读取流。 InputStream Reader
 34         是不是操作文本文件、
 35         是! 这时  可以选择Reader
 36         接下来明确使用该体系中的哪个对象
 37         明确设备:硬盘。上的一个文件。
 38         Reader 体系中可以操作文件的对象是  FileReader
 39         是否需要高效:  是!  加入Reader体系中  缓冲区  BufferedReader 。
 40 
 41 
 42         FileReader fr=new FileReader("a.txt");
 43         BufferedReader bufr=new BufferedReader(fr);
 44 
 45 
 46         目的: OutputStream Writer
 47         是不是纯文本。
 48         是:  Writer
 49         设备:  硬盘,一个文件夹、
 50         Writer体系中可以操作文件的对象 FileWriter 。
 51         是否需要提高效率:  是!  加入Writer体系中缓冲区   BufferedWriter 。
 52 
 53         FileWriter fw=  new FileWriter("b.txt");
 54         BufferedWriter bufw=new BufferedWriter(fw);
 55 
 56 练习:  将一个图片文件中数据存储到另一个文件中。复制文件。要按照以上格式自己完成三个明确
 57 
 58 --------------------------------------------------------------------
 59 2    需求:将键盘录入的数据保存到一个文件中。
 60             这个需求中有源和目的都存在
 61             那么分别分析:
 62             源:  InputStream  Reader
 63             是不是纯文本? 是  Reader
 64 
 65             设备:  键盘。对应的对象是 System.in
 66             不是选择Reader么? System.in对应的不是字节流么?
 67 
 68             为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
 69             所以既然明确了Reader,那么久将System.in转换成Reader。
 70             用了Reader体系中转换流 InputStreamReader
 71             InputStreamReader isr=new InputStreamReader(System.in);
 72 
 73             需要提高效率么?  是  :   BufferedReader
 74             BufferedReader bufr=new BufferedReader(isr);
 75 
 76             目的: OutputStream  Writer
 77             是否是纯文本?  是 ;   Writer
 78             设备:硬盘。  中的一个文件。  使用 FileWriter
 79 
 80             FileWriter fw=new FileWriter("c.txt");
 81             需要提高效率么?   需要
 82             BufferedWriter bufw=new BufferedWriter(fw);
 83 
 84 
 85 
 86             *********************************
 87             扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
 88 
 89             目的: OutputStream  Writer
 90             是不是纯文本:  是   :  Writer
 91             设备:硬盘  中的一个文件  FileWriter
 92             但是FileWriter是使用的默认编码表。   GBK
 93 
 94             但是存储时,需要加入指定编码表utf-8.而指定的编码表只有转换流可以指定
 95             
 96             所以要使用的对象是OutputStreamWriter。、      
 97             而该转换流要接收一个字节输出流。而且还可以操作文本的字节输出流。 FileOutputStream
 98 
 99             OutputStreamWriter osw =new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
100 
101             需要高效么?  需要
102             BufferedWriter bufw =new BufferedWriter(osw);
103             所以,记住,转换流什么时候使用。字符和字节 之间的桥梁,通常,设计到字符编码转换时。
104 
105             需要用到转换流。
106 
107 
108 练习:   将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
109 
110 */
111 
112 class TranStreamDemo2
113 {
114     public static void main(String[] args)throws IOException
115     {
116         System.setIn(new FileInputStream("PersonDemo.java"));
117         System.setOut(new PrintStream("zzz.txt"));
118 
119         //获取键盘录入对象。  
120         //InputStream in=System.in;  
121         //将字节流对象转成字符流对象,使用转换流。  
122         //InputStreamReader isr=new InputStreamReader(in);  
123         //为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader  
124         //BufferedReader br=new BufferedReader(isr);  
125   
126         //键盘录入最常见写法  
127         BufferedReader in=new BufferedReader(new InputStreamReader(System.in));  
128   
129         //字符流通向字节流  
130         BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(System.out));  
131   
132         String s=null;  
133         while((s=in.readLine())!=null)  
134         {  
135             if("over".equals(s))  
136                 break;  
137             bw.write(s.toUpperCase());//写入数据  
138             bw.newLine();//换行  
139             bw.flush();//刷新  
140               
141         }  
142         bw.close();//关闭流资源  
143         in.close();
144         }
145     }
146 }

小知识:

1、异常的日志信息:

        当程序在执行的时候,出现的问题是不希望直接打印给用户看的,是需要作为文件存储起来,方便程序员查看,并及时调整的。

示例:

 1 import java.io.*;  
 2 import java.text.*;  
 3 import java.util.*;  
 4 class  ExceptionInfo  
 5 {  
 6     public static void main(String[] args)   
 7     {  
 8         try  
 9         {  
10             int[] arr =new int[2];  
11             System.out.println(arr[3]);  
12   
13         }  
14         catch (Exception e)  
15         {  
16             try  
17             {  
18                 Date d=new Date();//创建时间对象  
19             //时间模块格式对象  
20             SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");  
21                 String s=sdf.format(d);  
22   
23                 PrintStream ps=new PrintStream("info.log");//打印流对象  
24                 System.setOut(ps);//修改输出流设备  
25                 ps.println(s);//输出时间  
26                   
27             }  
28             catch (IOException ex)  
29             {  
30                 throw new RuntimeException("文件创建失败");  
31             }  
32             e.printStackTrace(System.out);//将异常信息输出指定输出流  
33         }  
34     }  
35 }  

2、系统属性信息存入文本

        获取系统信息:

                 Properties getProperties()

        将信息输出到指定输出流中

                 void list(PrintStream out)

        将输出流中数据存入指定文件中

                  new PrintStream("systeminfo.txt")

示例:

import java.util.*;    
import java.io.*;    
  
class SystemInfo     
{    
   public static void main(String[] args)     
   {     
       PrintStream ps = null;    
       try    
       {    
          //获取系统信息:    
          Properties pop = System.getProperties();    
          //创建输出流对象,将输出流中数据存入指定文件中    
          ps = new PrintStream("systeminfo.txt");    
          //将属性列表输出到指定的输出流    
          pop.list(ps);    
       }    
       catch (Exception e)    
       {    
            throw new RuntimeException("获取系统信息失败。");    
       }    
    }    
}  

3、通过System类的setIn,setOut方法可以对默认设备进行改变

        System.setIn(newFileInputStream(“1.txt”));//将源改成文件1.txt。

        System.setOut(newFileOutputStream(“2.txt”));//将目的改成文件2.txt

流的基本应用小结:

  1  流是用来处理数据的。

  2  处理数据时,一定要先明确数据源,与数据目的地(数据汇)。

  3  数据源可以是文件,可以是键盘。

  4  数据目的地可以是文件、显示器或者其他设备。

  5  流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理.转换处理等。、

自我总结:

  流是用来操作数据的,并不能操作文件文件夹(例如修改只读模式等),而操作数据必定需要关联数据源,或者关联数据目的。数据源可以是内存,硬盘,键盘,目的源可以是控制台,内存,硬盘。而流的操作需要中转站,可以是自定义的缓冲区,也可以是数据流里的缓冲区,其中IO流的缓冲区定义了一些方便我们操作的方法。字节流的操作范围较字符流会更广一些,它可以操作音乐图片等字节流数据。而字符流操作的是我们看的懂的字符。通过IO流我们可以实现,复制,也可以把流切成n段,还可以将n段整合成完整的文件。因此总的来说IO流的作用很大,实现了信息的传递。

黑马程序员——Java基础---IO(二)---IO字节流、流操作规律

标签:

原文地址:http://www.cnblogs.com/ktlshy/p/4713934.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!