黑马程序员 java基础<四>--IO流(2)

来源:互联网 发布:淘宝实名认证怎么注销 编辑:程序博客网 时间:2024/06/16 00:11

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


                                              知识点二   字节流

一、概述:

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

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

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

                             OutputStream  --->  输出流(写)

4、不用进行刷新流的动作的原因:

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

5、字节流所特有方法:

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

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

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

举例:

/*字符流:FileReader FileWriterBufferedReaderBufferedWriter字节流:两个基类:InputStream(读) OutputStream(写)需求:想要操作图片数据,这时候就要用到字节流*/import java.io.*;class FileStream{    public static void main(String []args) throws IOException   {       // writeFile();  // readFile_1();  // readFile_2();  readFile_3();   }   public static void readFile_1() throws IOException   {     FileInputStream fis=new FileInputStream("fos.txt");  int ch=0; while((ch=fis.read())!=-1) {    System.out.println((char)ch); } fis.close();   }       public static void readFile_2() throws IOException   {     FileInputStream fis=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();   }       public static void readFile_3() throws IOException   {     FileInputStream fis=new FileInputStream("fos.txt");  // int num=fis.available();//这种方式要慎用,数据不是太大的话,可以这样使用byte[] buf=new byte[fis.available()];//定义一个刚刚好的缓冲区,不用再循环了   fis.read(buf); // System.out.println("num="+num); System.out.println(new String(buf));  fis.close();   }      public static void writeFile() throws IOException   {      FileOutputStream fos=new FileOutputStream("fos.txt");    //将字符串变为字节数组  fos.write("abcde".getBytes());    fos.close();     }}

二、复制媒体文件(一张图片):

1、思路:

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

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

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

4)关闭资源

注意:不要用字符流操作媒体文件,因为图片数据读取一段后去查编码表,如果找到对应的数字编码未变话,如果没找到去找编码表的未知区域,所以编码会发生变化,这样生成新图片的编码和老图片的编码就不一样了,字节码发生变化,因此字符流只用于处理文字数据。

示例:

import java.io.*;class  CopyPic{public static void main(String[] 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("写入关闭失败");}}}}
三、字节流缓冲区:

1、读写特点:

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

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

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

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

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

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

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

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

示例:

/*通过缓冲区,演示Mp3的复制BufferedOutputStreamBufferedInputStream*/import java.io.*;class CopyMp3{    public static void main(String []args) throws IOException   {       long start=System.currentTimeMillis();      //copy_1();  copy_2();  long end=System.currentTimeMillis();    System.out.println((end-start)+"毫秒");   }      //通过字节流的缓冲区,完成复制   public static void copy_1() throws IOException   {       //缓冲区里已经定义了数组       BufferedInputStream  bufis=new BufferedInputStream(new FileInputStream("C:\\0.mp3"));   BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("C:\\1.mp3"));      int by=0;         while((by=bufis.read())!=-1)   {     bufos.write(by);   }   bufos.close();   bufis.close();   }      public static void copy_2() throws IOException   {       MyBufferedInputStream bufis=new  MyBufferedInputStream(new FileInputStream("C:\\0.mp3"));   BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("C:\\2.mp3"));      int by=0;      //读了一次没有写出去  // System.out.println("第一个字节:"+bufis.myRead());      while((by=bufis.myRead())!=-1)   {     bufos.write(by);   }   bufos.close();   bufis.myClose();   }}

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做与运算即可

示例:

/*11111111 -->提升了一个int类型,那不还是-1,吗?是-1的原因是因为在8个1的前面补得的是1导致的那么我只要在前面补0,既可以保留原字节数据不变,又可以避免-1的出现,那么怎,补0呢                            11111111 11111111 11111111 11111111&00000000 00000000 00000000 11111111------------------------------------- 00000000 00000000 00000000 11111111  这样就可以避免-1的发生 byte:-1  ---->int:-1 read方法在提升,write方法将指定的字节写入此缓冲的输出流(强制转换,取最低的8位)*/import java.io.*;class MyBufferedInputStream{   private InputStream in;      private byte[] buf=new byte[1024*4];      private int pos=0;      private int count=0;   MyBufferedInputStream(InputStream in)   {     this.in=in;   }      //一次读一个字节,从缓冲区(字节数组)获取   public int myRead() throws IOException   {      //通过in对象,读取硬盘上的数据,并存储到buf中  if(count==0)  {    count= in.read(buf);  if(count<0)    return -1;  pos = 0;  //取数组第一个元素pos=0;  byte b=buf[pos];    count--;  pos++; //b与255进行与操作,用十六进制表示就是0xff  return b&255;  }else if(count>0)  {  byte b=buf[pos];    count--;  pos++;  //b与255进行与操作,用十六进制表示就是0xff  return b&255;  }    return -1;   }   public void myClose()throws IOException   {      in.close();   } }
5.读取键盘录入

System.out:对应的是标准的输出设备,控制台。
System.in:对应的标准输入设备,键盘

/*需求:通过键盘录入数据,当录入一行数据后就进行打印。如果当录入的数据时over,那么停止录入Dos下键盘录入操作终止可以使用Ctrl+C操作*/import java.io.*;class  ReadIn{  public static void main(String[] args) throws IOException  {    InputStream in=System.in;StringBuilder sb=new StringBuilder();    /*int ch=0;    while((ch=in.read())!=-1)    { System.out.println(ch);}*/while(true){    int ch=in.read();if(ch=='\r') continue;if(ch=='\n')    {   String s=sb.toString();   if("over".equals(s))    break;   System.out.println(s.toUpperCase());   //sb=new StringBuilder();      sb.delete(0,sb.length());}elsesb.append((char)ch);}in.close();//数据类型转换System.out.println('\r'+0);System.out.println('\n'+0);/*int by=in.read();int by1=in.read();int by2=in.read();System.out.println(by);System.out.println(by1);System.out.println(by2);*/  }}

                                             知识点三   转换流


一、概述:

转换流的由来:内部可以指定编码表

1.通过上面的示例,通过键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理

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

那么能不能将字节流转成字符流在使用字符流缓冲区的readLine方法呢?

2.两个转换流:读取转换流InputStreamReader和写入转换流OutputStreamWriter,这两个类分别属于字符流Reade和Writer的子类

二、读取转换流:

InputStreamReader是字节流通向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符。

InputStreamReader:读取转换流

a.获取键盘录入对象: ---> InputStream in = System.in;

b.将字节流对象转换成字符流对象,使用转换流InputStreamReader: ---> InputStreamReader isr = new InputStreamReader(in);

c.为提高效率,将字符串进行缓冲区技术操作,使用BufferedReader: ---> BufferedReader bufw = new BufferedReader(isr);

d.之后就可以使用readLine()方法读取录入的一行数据了。


示例:

class TransStreamDemo{    public static void main(String []args) throws IOException   {            //获取键盘录入对象  // InputStream in=System.in;      //将字节流对象装换成字符流对象,InputStreamReader  //InputStreamReader isr=new  InputStreamReader(in);      //为了提高效率,讲将字符流进行缓冲区技术的高效操作     // BufferedReader bufr=new BufferedReader(isr);     BufferedReader bufr=new BufferedReader(new InputStreamReader(new FileInputStream("CopyMp3.java")));         BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));         String line=null;      while((line=bufr.readLine())!=null)   {     if("over".equals(line)) break;     System.out.println(line.toUpperCase());           }   bufr.close();   }}


二、写入转换流

OutputStreamWriter是字符流通向字节流的桥梁,可使用指定的charset将要写入流中的字符编码成字节。

OutputStreamWriter:写入转换流 ---> 和读取转换流同理,即使用对应的Writer的子类

示例:

class TransStreamDemo{    public static void main(String []args) throws IOException   {         //*************毕老师说这句换一定要记住,键盘录入,非常的重要********************  //键盘录入最常见写法   BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));         BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));         String line=null;      while((line=bufr.readLine())!=null)   {     if("over".equals(line)) break;     bufw.write(line.toUpperCase());             bufw.newLine();      bufw.flush();    }      bufr.close();   }}

                                                                                                   知识点四  流操作规律

一、分析清楚源和目的以及需求:

1.源:键盘录入
目的:控制台
2.需求:想把键盘录入的数据存储到一个文件中
源:键盘 
目的:文件
3.需求:想要将一个文件的数据打印在控制台上。
源:文件
目的:控制台
二:
流操作的基本规律:
最痛苦的就是流对象有很多,不知道该用哪一个

通过三个来明确
1.明确源和目的
  源:输入流  InputStream Reader
  目的:输出流 OutputStream Writer
  

2.明确操作的数据是否是纯文本
  是:字符流
  不是:字节流

3.当体系明确后,在明确要使用哪个具体的对象
  通过设备来进行区分;
  源设备:内存(ArrayStream),硬盘(FileStream),键盘(System.in)
  目的设备:内存(ArrayStream),硬盘(FileStream),控制台(System.out)
4、需求体现:

4.1需求:将一个文本文件中的数据存储到另一个文件中,复制文件。
  源:因为是源,所以使用读取流 InputStream Reader
  是不是操作文本文件?
  是!这时就可以选择Reader
  这样体系就明确了
  
  接下来明确对象该体系中的哪个对象。
  明确设备:硬盘上的一个文件。
  Reader体系中可以操作文件的对象是FileReader
  
  是否需要提高效率:是!加入Reader体系中的缓冲区,BufferedReader
  
  FileReader fr=new FileReader("a.txt");
  
  BufferReader bufr=new BufferedReader(fr);
  
  目的:OutputStream Writer
  是否是纯文本文件?
  是!Writer。
  设备:硬盘。一个文件。
  Writer体系中可以操作文件的对象是FileWriter
  
  是否需要提高效率:是!加入Writer体系中的缓冲区,BufferedWriter
  
  FileWriter fw=new FileWriter("b.txt");
  
  BufferedWriter  bufw=new BufferedWriter(fw);
  
练习:将一个图片文件中数据存储到另一个文件中,复制文件。要按照以上格式完成三个明确。

分析:

1)源:InputStream和Reader

      图片:字节流 ---> InputStream

      设备:硬盘上的文件 --->  FileInputStream

2)目的:OutoutStream和Writer

      图片:字节流  --->  OutputStream

      设备:硬盘上的文件 --->  FileOutputStream

4.2需求:将键盘录入的数据保存到一个文件中
    这个需求中有源和目的都存在。
    那么分别分析
    源:InputStream Reader 
    是不是纯文本?是!Reader

    设备:键盘。对应的对象是System.in
    不是选择Reader吗?System.in对应的不是字节流吗?
    为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
    所以既然明确了Reader,那么就将System.in装换成Reader。
    用了Reader体系中的转换流,InputStreamReader

     InputStreamReader isr=new InputStreamReader(System.in);
     //需要提高效率吗?需要BufferedReader
     BufferedReader bufr=new BufferedReader(isr);

     目的:OutputputStream Writer
     是否是纯文本?是!Writer
     设备:硬盘。一个文件。使用FileWriter
     FileWriter fw=new FileWriter("c.txt");
     需要提高效率吗?需要
     BufferedWriter bufw=new BufferedWriter(fw);

5.扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中

   目的:OutputputStream Writer
是否是纯文本?是!Writer
设备:硬盘。一个文件。使用FileWriter
但是FileWriter是使用默认的编码表,GBK
但是存储时需要加入指定的编码表utf-8,只有转换流才能指定。
所以要使用的对象是OutputStreamReader
而该转换流对象要接受一个字节输出流,而且还可以操作文件的字节输出流。FileOutputStream
  OutputStreamWriter osw=new  OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
需要提高效率吗?需要
BufferedWriter bufw=new BufferedWriter(osw);
所以记住,装换流什么时候使用,字符和字节之间的桥梁,通常,涉及到字符编码装换时需要用到转换流
示例:
class TransStreamDemo2{    public static void main(String []args) throws IOException   {           //获取键盘录入对象  // InputStream in=System.in;  //键盘录入最常见写法   BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));      BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d2.txt"),"UTF-8"));         String line=null;      while((line=bufr.readLine())!=null)   {     if("over".equals(line)) break;       bufw.write(line.toUpperCase()); bufw.newLine(); bufw.flush();           }   bufr.close();   }}
6.改变标准输入输出设备
System.setIn(new FileInputStream("PersonDemo.java"));
System.setOut(new PrintStream("zz.txt"));
                                                                   
                                             知识点五  信息

一、异常的日志信息:

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

示例:
/*说明:Log4j的jar包可以完成日志信息建立*/import java.io.*;import java.util.*;//格式化要用的包import java.text.*;class ExceptionInfo{  public static void main(String[] args) throws IOException  {    try{    int[] arr=new int [2];  System.out.println(arr[3]);  }catch(Exception e){try{   //打印日期   Date d=new Date();   //SimpleDateFormat将时间格式化   SimpleDateFormat sdf=new  SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//h是12小时制,H是24小时制   String s=sdf.format(d);      PrintStream ps=new PrintStream("exception.log");   //ps是字节流,要将字符串变成字节数组写出去   //ps.write(d.toString().getBytes);   //ps.println(d.toString());   ps.println(s);    //改变标准输出   System.setOut(ps);   //e.printStackTrace(new PrintStream("a.txt"));}catch(IOException ex){  throw new RuntimeException("日志文件创建失败");}   e.printStackTrace(System.out);}    }  }

二、系统信息:

获取系统信息:
Properties getProperties()
将信息输出到指定输出流中
void  list(PrintStream out)
将输出流中数据存入指定文件中
new PrintStream("systeminfo.txt")
示例:

import java.io.*;import java.util.*;class SystemInfo{  public static void main(String[] args) throws IOException  {      //打印系统信息     //源就是集合中的数据也就是内存     Properties prop=System.getProperties();  //System.out.println(prop); //将系统信息打印在控制台上  //prop.list(System.out);  prop.list(new PrintStream("sysinfo.txt"));  }}

最新最全的的java学习视频教程:http://pro.net.itcast.cn/View-22-1458.aspx       
                                              -------android培训java培训java学习型技术博客、期待与您交流! ----------

详细请查看:http://edu.csdn.net/heima


原创粉丝点击