黑马程序员_java IO流1

----------------------  ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

1、IO流概述
IO流用来处理设备之间的数据传输;Java对数据的操作是通过流的方式; Java用于操作流的对象都在IO包中;
IO流的两种分类:
1)、按操作数据分类:字节流、字符流;
2)、按流向分类:输入流、输出流。

2、IO流中常用的基类
1)、 字节流的抽象基类:InputStream, OutPutStream;
2)、 字符流的抽象基类:Reader, Writer
IO流的一般特性: 后缀名为父类名,前缀名是该流对象的功能。
如: 由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。 如:InputStream的子类FileInputStream。 如:Reader的子类FileReader   。

3、字符流的基本操作演示
字符流一般使用来操作文本文件的。

    示例:

FileWriter fw = new FileWriter(“java.text”);

//创建一个FileWriter对象,该对象一初始化就必须要明确被操作的文件,该文件会被创建到指定目录下;如果该目录中已有同名文件将会被覆盖,该步就是在明确数据要存放的目的地;

       fw.write(“Hello World!!!”);

//调用write方法,将字符串写入到流中;

       fw.flush();

//刷新流对象中的缓冲数据;将数据刷到目的地中;

       fw.close();

//关闭资源,但是在关闭之前会刷新一次内部中的缓冲数据;将数据刷到目的地。

//closeflush的区别:flush刷新后流可以继续使用;close刷新后流将会关闭;

 


4、IO流的异常处理
IO流一般都会抛出异常,因此在写程序时,不能仅仅的将异常直接抛出,而应该根据实际情况做相应的处理。一般在finally语句中关闭流资源。
  1. import java.io.*;  
  2. class IOExceptionDemo  
  3. {  
  4.        public static void main(String[] args)  
  5.        {  
  6.               FileWriter fw = null;//首先将fw赋值为空,是因为创建FileWriter文件时  
  7.               //会抛出异常,需要捕捉;如果放在try中,finally中将访问不到fw;  
  8.               try  
  9.               {  
  10.                      fw = new FileWriter("java.text");  
  11.                      fw.write("Hello World!!!");  
  12.               }  
  13.               catch (IOException e )  
  14.               {  
  15.                      System.out.println(e.toString());  
  16.               }  
  17.               finally  
  18.               {  
  19.                      try  
  20.                      {  
  21.                             if(fw!=null)//如果上面的新创建对象抛出异常,fw将为空,执行到close时将会抛出空指针异常;所以确保不会抛出空指针异常需要做一个判断;  
  22.                             fw.close();  
  23.                      }  
  24.                      catch (IOException e )  
  25.                      {  
  26.                             System.out.println(e.toString());  
  27.                      }  
  28.               }  
  29.        }  
  30. }

5、IO流的一些基本操作方式
5.1、文件的续写
在新建对象的时候,传递一个 true 参数,代表不覆盖已有文件,并在文件的末尾处进行数据续写。例如: FileWriter fw = new FileWriter("Java.txt",true);  该语句将在Java.txt文件后面继续写入数据。
5.2、 文本文件读取方式

方式一: 使用 FileReader 中的 read() 方法; read 方法每次只读取一个字符,会自动往下读。 在创建文件流对象时,要保证该文件是存在的,如果不存在则会发生 FileNotFoundException 异常。
     方式二:通过字符数组进行读取。即 read(char[]) ,返回的是读到的字符个数。
    示例:
  1. import java.io.*;  
  2. class FileReaderDemo  
  3. {  
  4.          public static void main(String[] args) throws IOException  
  5.          {  
  6.                    FileReader fr = new FileReader("FileReaderDemo.java");  
  7.                    char[] ch = new char[1024];//一般将该处的数组大小定义为1024的整数倍;  
  8.                    int num = 0;  
  9.                    while((num=fr.read(ch)) != -1)//当read返回的num等于-1时,表示已经读到文件末尾了;  
  10.                    {  
  11.                             System.out.print(new String(ch,0,num));//此处表示读多少就打印多少;  
  12.                    }  
  13.                    fr.close();  
  14.          }  
  15. }
练习:使用以上两种方式,将相关路径的文本文件复制到D盘;
复制原理:将相关路劲的文件数据存储到D盘的一个文件中;
实现步骤:
1)、在D盘建立一个文件,用于存储原始数据;
2)、定义读取流和相关路径的文件相关联;
3)、通过不断地读写完成数据的存储;
4)、关闭资源。    示例:
  1. import java.io.*;  
  2. class CopyTest  
  3. {  
  4.          public static void main(String[] args) throws IOException  
  5.          {  
  6.                    copy_1();  
  7.          }  
  8.          public static void copy_2()throws IOException  
  9.          {  
  10.                    //创建需要Copy的目的地;  
  11.                    FileWriter fw = new FileWriter("D:\\CopyDemo.txt");  
  12.                    //创建需要copy的文件;  
  13.                    FileReader fr = new FileReader("CopyTest.java");  
  14.                    //使用read方法,每次读一个字符写一个字符;  
  15.                    int len = 0;  
  16.                    while((len=fr.read()) !=-1)  
  17.                   {  
  18.                             fw.write(len);  
  19.                    }  
  20.                    fw.close();  
  21.                    fr.close();  
  22.    
  23.          }  
  24.          //使用数组存储字符,让后让字符一次性输出;  
  25.          public static void copy_1()  
  26.          {  
  27.                    FileWriter fw = null;  
  28.                    FileReader fr = null;  
  29.                    try  
  30.                    {  
  31.                             fw = new FileWriter("D:\\CopyDemo.txt");  
  32.                             fr = new FileReader("CopyTest.java");  
  33.                             int len = 0;  
  34.                             char[] ch = new char[1024];  
  35.                             while((len=fr.read(ch)) != -1)  
  36.                             {  
  37.                                      fw.write(ch,0,len);  
  38.                             }  
  39.                    }  
  40.                    catch (IOException e)  
  41.                    {  
  42.                             throw new RuntimeException("Read and write failure");  
  43.                    }  
  44.                    finally  
  45.                    {  
  46.                             try  
  47.                             {  
  48.                                      if(fw != null)  
  49.                                      fw.close();  
  50.                             }  
  51.                             catch (IOException e)  
  52.                             {  
  53.                                      throw new RuntimeException("Write close failure");  
  54.                             }  
  55.                             try  
  56.                             {  
  57.                                      if(fr != null)  
  58.                                      fr.close();  
  59.                             }  
  60.                             catch (IOException e)  
  61.                             {  
  62.                                      throw new RuntimeException("Read close failure");  
  63.                             }  
  64.                    }  
  65.          }

6、字符流缓冲区
    缓冲区的出现提高了对数据的读写效率;对应类有BufferedWriter  &  BufferedReader;缓冲区要结合流才能使用,并且在流的基础上对流的功能进行了增强。
6.1、BufferedWriter
BufferedWriter将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。操作方法:由于缓冲区的出现是为了提高流的操作效率;所以在创建缓冲区之前需要先有流对象。将流对象作为参数传递到缓冲区的构造函数,用于缓冲区的方法对数据进行操作。   注:该缓冲区还提供了一个跨平台的换行符:newline()
  1. import java.io.*;  
  2. class BufferedWriterDemo  
  3. {  
  4.          public static void main(String[] args) throws IOException  
  5.          {  
  6.                    FileWriter fw = new FileWriter("java.txt");//创建一个写入流对象和文件相关联;  
  7.    
  8.                    BufferedWriter buf = new BufferedWriter(fw);//将流对象作为参数传递到缓冲区的构造函数;  
  9.                    buf.write("Hello java");  
  10.    
  11.                    buf.flush(); //需要刷新,缓冲区中的文件才能进去流对象中;  
  12.                    buf.close();  
  13.                    //fw.close();此时的fw不需要关闭,因为关闭了缓冲区,  
  14.                    //也就是关闭了缓冲区中的流对象;  
  15.          }  
  16. }

6.2、BufferedReader
BufferedReader从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
该缓冲区提供了一个一次读取一行的方法:readLine(),方便与对文本文件的读取。该方法返回包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null。
    演示示例:
  1. import java.io.*;  
  2. class BufferedReaderDemo  
  3. {  
  4.          public static void main(String[] args)throws IOException  
  5.          {  
  6.                    FileReader fr = new FileReader("CopyTest.java");  
  7.                    //创建一个缓冲区,将流对象作为参数传递给缓冲对象的构造函数;  
  8.                    BufferedReader buf = new BufferedReader(fr);  
  9.                    String line = null;  
  10.                    while((line=buf.readLine()) != null)//readLine每次读一行,  
  11.                    {                           //当读到文件末尾时返回null;  
  12.                             System.out.println(line);  
  13.                    }  
  14.                    buf.close();  
  15.          }  
  16. }

6.3、练习:通过缓冲区复制一个.java文件。
  1. import java.io.*;  
  2. class BufferedCopyDemo  
  3. {  
  4.          public static void main(String[] args) throws IOException  
  5.          {  
  6.                    BufferedReader bufr = null;  
  7.                    BufferedWriter bufw = null;  
  8.                    try  
  9.                    {  
  10.                             bufr = new BufferedReader(new FileReader("CopyTest.java"));  
  11.                             bufw = new BufferedWriter(new FileWriter("D:\\BufferedCopy.txt"));  
  12.    
  13.                             String line = null;  
  14.                             while((line=bufr.readLine()) != null)  
  15.                             {  
  16.                                      bufw.write(line);//由于readLine不读换行符;  
  17.                                      bufw.newLine();//所以每读一行就需要换行一次;  
  18.                             }  
  19.                    }  
  20.                    catch (IOException e)  
  21.                    {  
  22.                             throw new RuntimeException("Read and write failure");  
  23.                    }  
  24.                    finally  //关闭流资源;
  25.                    {  
  26.                             try  
  27.                             {  
  28.                                      if(bufr != null)  
  29.                                                bufr.close();  
  30.                             }  
  31.                             catch (IOException e)  
  32.                             {  
  33.                                      throw new RuntimeException("Read close failure");  
  34.                             }  
  35.                             try  
  36.                             {  
  37.                                      if(bufw != null)  
  38.                                                bufw.close();  
  39.                             }  
  40.                             catch (IOException e)  
  41.                             {  
  42.                                      throw new RuntimeException("Write close failure");  
  43.                             }  
  44.                    }  
  45.          }  
  46. }

6.4、readLine方法的原理
readLine方法的原理:readLine方法虽然每次都是读一行,其实最终还是在硬盘上一个一个的读取,所以最终使用的还是read方法一次一个的读取。
通过了解readLine方法的原理,我们可以自己写一个readLine方法。
  1. import java.io.*;  
  2. class MyBufferedReader  
  3. {  
  4.     private FileReader r;  
  5.     MyBufferedReader(FileReader r)  
  6.     {  
  7.         this.r = r;  
  8.     }  
  9.     //自定义一个readLine方法myReadLine;  
  10.     public String myReadLine()throws IOException  
  11.     {  
  12.         StringBuilder sb = new StringBuilder();  
  13.         int ch = 0;  
  14.         while((ch=r.read()) != -1)  
  15.         {  
  16.             if(ch == '\r')//当读到'\r'时,重新回去循环;  
  17.                 continue;  
  18.             if(ch == '\n')//当读到'\n'时,将读到的数据转换成字符串;  
  19.                 return sb.toString();  
  20.             else  
  21.                 sb.append((char)ch);//否则的话,就将数据存储到sb中;  
  22.         }  
  23.         if(sb.length() !=0)//当最后一行没有出现回车符时,也要将数据转换成字符串;  
  24.             return sb.toString();  
  25.         return null;  
  26.     }  
  27.     public void myClose()throws IOException //自定义myClose方法;  
  28.     {  
  29.         r.close();  
  30.     }  
  31. }  
  32. class MyBufferedReaderDemo   
  33. {  
  34.     public static void main(String[] args) throws IOException  
  35.     {  
  36.         FileReader fr = new FileReader("CopyTest.java");  
  37.         MyBufferedReader mbuf = new MyBufferedReader(fr);  
  38.         String line = null;  
  39.         while((line=mbuf.myReadLine()) != null)//调用myReadLine方法;  
  40.         {  
  41.             System.out.println(line);  
  42.         }  
  43.         mbuf.myClose();  
  44.     }  
  45. }

7 、装饰设计模式
当要对已有对象进行功能增强时,就可以定义一个类,将已有对象传入,基于已有功能并提供增强功能,该自定义的类就称为装饰类。装饰类通常会通过构造方法接受别装饰的对象,并基于被装饰的的对象的功能,提供更强的功能。
装饰模式比继承要灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系;装饰类因为是增强已有对象,具备的功能和已有对象时相同的,只不过提供了更强大的功能,所以装饰类和被装饰类一般都是属于一个体系的。
例如:在一个专门用于读取的类中,
继承体系:
MyReader
|---MyTextReader
|---MyBufferedTextReader
|---MyMediaReader
|---MyBufferedMediaReader
|---MyDataReader
|---MuBufferedDataReader
class MyBufferedReader
{
MyBufferedReader(MyTextReader text){}
MyBufferedReader(MyMediaReader Media){}
}
该类的扩展性很差,找其参数的共同类型,可以通过多态的形式提高其扩展性。
class MyBufferedReader extends MyReader
{
MyBufferedReader(MyReader r){}
}
装饰设计模式:(扩展性更强,也更加简洁)
MyReader
|---MyTextReader
|---MyMediaReader
|---MyDataReader
|---MuBufferedReader

通过对装饰类的学习,我们可以将以上myReadLine方法进行改进成装饰类:
  1. import java.io.*;  
  2. class MyBufferedReader extends Reader  //该类继承Reader
  3. {  
  4.          private Reader r;  
  5.          MyBufferedReader(Reader r)  
  6.          {  
  7.                    this.r = r;  
  8.          }  
  9.          public String myReadLine()throws IOException  
  10.          {  
  11.                    StringBuilder sb = new StringBuilder();  
  12.                    int ch = 0;  
  13.                    while((ch=r.read())!=-1)  
  14.                   {  
  15.                             if(ch == '\r'//当读到回车符的’\r’时重新循环;  
  16.                                      continue;  
  17.                             if(ch == '\n'//当读到回车符的’\n’时直接打印当前行;  
  18.                                      return sb.toString();  
  19.                             else  
  20.                                      sb.append((char)ch);//如果没有遇到回车符将一直添加字符到sb中;               
  21.                    }  
  22.                    return null;  
  23.          }  
  24.          /*覆盖父类中的抽象方法*/  
  25.          public void close()throws IOException  
  26.          {  
  27.                    r.close();  
  28.          }  
  29.          public int read(char[] cbuf, int off, int len)throws IOException  
  30.          {  
  31.                    return read(cbuf,off,len);  
  32.          }  
  33.          public void myClose()throws IOException  
  34.          {  
  35.                    r.close();  
  36.          }  
  37. }  
  38.   
  39. class MyBufferedReaderDemo   
  40. {  
  41.          public static void main(String[] args) throws IOException  
  42.          {  
  43.                    MyBufferedReader buf = new MyBufferedReader(new FileReader("java.txt"));  
  44.                    String line = null;  
  45.                    while((line=buf.myReadLine()) != null)  
  46.                    {  
  47.                             System.out.println(line);  
  48.                    }  
  49.          }  
  50. }

8、LineNumberReader
8.1、BufferedReader
|--- LineNumberReader
LineNumberReader是跟踪行号的缓冲字 符输入流。此类定义了方法  de>setLineNumber(int)de> 和  de>getLineNumber()de>,它们可分别用于设置和获取当前行号。
其操作方法见示例:
  1. import java.io.*;  
  2. class  LineNumberReaderDemo  
  3. {  
  4.     public static void main(String[] args) throws IOException  
  5.     {  
  6.         FileReader fr = new FileReader("BufferedWriterDemo.java");  
  7.         LineNumberReader lnr = new LineNumberReader(fr);  
  8.         lnr.setLineNumber(100);//此处设置文件的行号从100(不包含100)开始;  
  9.         String line = null;  
  10.         while((line=lnr.readLine())!=null)  
  11.         {  
  12.             System.out.println(lnr.getLineNumber()+":"+line);  
  13.         }                  //getLineNumber()可以获取文件的行号;  
  14.         lnr.close();  
  15.     }  
  16. }

8.2、通过了解LineNumberReader原理的了解,自定义一个MyLineNumberReader类。
  1. import java.io.*;  
  2. class MyLineNumberReader  
  3. {  
  4.     private Reader r;  
  5.     private int lineNumber;  
  6.     public void setLineNumber(int lineNumber)  
  7.     {  
  8.         this.lineNumber = lineNumber;  
  9.     }  
  10.     public int getLineNumber()  
  11.     {  
  12.         return lineNumber;  
  13.     }  
  14.     MyLineNumberReader(Reader r)  
  15.     {  
  16.         this.r = r;  
  17.     }  
  18.     public String myReadLine() throws IOException  
  19.     {  
  20.         lineNumber++;  //当每次调用MyReadLine方法时lineNumber就加一次;  
  21.         StringBuilder sb = new StringBuilder();  
  22.         int ch = 0;  
  23.         while((ch = r.read()) != -1)  
  24.         {  
  25.             if(ch == '\r')  
  26.                 continue;  
  27.             if(ch == '\n')  
  28.                 return sb.toString();  
  29.             else  
  30.                 sb.append((char)ch);  
  31.         }  
  32.         if(sb.length() != 0)  
  33.             return sb.toString();  
  34.         return null;  
  35.     }  
  36.     public void myClose()throws IOException  
  37.     {  
  38.         r.close();  
  39.     }  
  40. }  
  41. class MyLineNumberReaderDemo   
  42. {  
  43.     public static void main(String[] args) throws IOException  
  44.     {  
  45.         FileReader fr = new FileReader("BufferedReaderDemo.java");  
  46.         MyLineNumberReader mlnr = new MyLineNumberReader(fr);  
  47.         mlnr.setLineNumber(100); //设置起始行号为100;  
  48.         String line = null;  
  49.         while((line = mlnr.myReadLine()) != null)  
  50.         {  
  51.             System.out.println(mlnr.getLineNumber()+":"+line);  
  52.         }  
  53.         mlnr.myClose();  
  54.     }

9、字节流
字节流:InputStream   OutputStream
字符流是用于操作文本文件的,但是当要操作图片文件或者媒体文件等其他文件时,就得需要使用字节流。
InputStreamOutputStreamReaderWriter的用法基本一致。在InputStream类中有一个available()方法,该方法可以获取文件的长度。
    读取文件(InputStream)的三种操作方式:

  1)、每读一个字节就打印一个字节;

  2)、定义一个固定长度的数组,将读到的字节先存入到数组中,读完之后再一次性打印出来。

  3)、定义一个长度为刚好的数组,其可是使用available方法获取,将读到的字节存入到刚好大小的数组中,让后直接全部打印出来

在实际使用时,建议使用第二种方法,因为第一种方法读取速度较慢,第三种方法在读取较大文件时,当内存不够用时,就会发生内存溢出。

FileInputStream和FileOutputStread相关操作演示:
  1. import java.io.*;  
  2. class FileStream  
  3. {  
  4.          public static void main(String[] args) throws IOException  
  5.          {  
  6.                    readFile_3();  
  7.          }  
  8.          public static void readFile_1()throws IOException  
  9.          {  
  10.                    FileInputStream fis = new FileInputStream("D:\\java.txt");  
  11.                    int ch = 0;  
  12.                    while((ch = fis.read()) != -1)  
  13.                    {  
  14.                             System.out.print((char)ch);  
  15.                    }  
  16.                    fis.close();  
  17.          }  
  18.          public static void readFile_2()throws IOException  
  19.          {  
  20.                    FileInputStream fis = new FileInputStream("D:\\java.txt");  
  21.                    byte[] bt = new byte[1024];  
  22.                    int len = 0;  
  23.                    while((len = fis.read(bt)) != -1)  
  24.                    {  
  25.                             System.out.println(new String(bt,0,len));  
  26.                    }  
  27.                    fis.close();  
  28.          }  
  29.          public static void readFile_3()throws IOException  
  30.          {  
  31.                    FileInputStream fis = new FileInputStream("D:\\java.txt");  
  32.                    byte[] bt = new byte[fis.available()];//使用available方法可以获取fis的字节长度;  
  33.                    fis.read(bt);  
  34.                    System.out.println(new String(bt));  
  35.          }  
  36.          public static void writeFile()throws IOException  
  37.          {  
  38.                    FileOutputStream fos = new FileOutputStream("D:\\java.txt");  
  39.                    fos.write("Hellojava".getBytes());  
  40.                    fos.close();  
  41.          }  
  42. }

练习:使用字节流拷贝一副图片。
思路:1)、 用字节读取流对象和图片关联;

               2)、用字节写入流对象创建一副图片文件,用于存储获取到的图片数据;

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

                    4)、关闭资源。

  1. import java.io.*;  
  2. class CopyPicDemo  
  3. {  
  4.          public static void main(String[] args)  
  5.          {  
  6.                    FileInputStream fis = null;  
  7.                    FileOutputStream fos = null;  
  8.                    try  
  9.                    {  
  10.                             fis = new FileInputStream("D:\\1.jpg");  
  11.                             fos = new FileOutputStream("D:\\2.jpg");  
  12.                             int len = 0;  
  13.                             byte[] bt = new byte[1024];  
  14.                             while((len = fis.read(bt)) != -1)  
  15.                             {  
  16.                                      fos.write(bt,0,len);  
  17.                             }  
  18.                    }  
  19.                    catch (IOException e)  
  20.                    {  
  21.                             throw new RuntimeException("read and write file failure");  
  22.                    }  
  23.                    finally  
  24.                    {  
  25.                             try  
  26.                             {  
  27.                                      if(fis!=null)  
  28.                                                fis.close();  
  29.                             }  
  30.                             catch (IOException e)  
  31.                             {  
  32.                                      throw new RuntimeException("read close failure");  
  33.                             }  
  34.                             try  
  35.                             {  
  36.                                      if(fos!=null)  
  37.                                                fos.close();  
  38.                             }  
  39.                             catch (IOException e)  
  40.                             {  
  41.                                      throw new RuntimeException("write close failure");  
  42.                             }  
  43.                    }  
  44.          }

10、字节流缓冲区
BufferedInputStreamBufferedOutputStream。该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。字节流缓冲区与字符流缓冲区用法基本一致。以下通过一个复制mp3文件来演示字符流缓冲区的用法:
  1. import java.io.*;    
  2. class CopyMp3Demo  
  3. {  
  4.          public static void main(String[] args) throws IOException  
  5.          {  
  6.                    long start = System.currentTimeMillis();//复制开始时间;  
  7.                    copy();  
  8.                    long end = System.currentTimeMillis();//复制结束后的时间;  
  9.                    System.out.println((end-start)+"毫秒");//复制mp3总共用时;  
  10.          }  
  11.          public static void copy()throws IOException  
  12.          {  
  13.                    //通过字节流的缓冲区完成复制;将流对象作为参数传递给缓冲对象的构造函数;  
  14.                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\1.mp3"));  
  15.                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\2.mp3"));  
  16.                    //此方法是读一字节的数据就写一字节的数据;将数据写入到缓冲区中;  
  17.                    int bt = 0;  
  18.                    while((bt = bis.read()) != -1)  
  19.                    {  
  20.                             bos.write(bt);  
  21.                    }  
  22.                    bis.close();  
  23.                    bos.close();  
  24.          }  
  25. }

自定义字节流缓冲区:
  1. import java.io.*;  
  2. class MyBufferedInputStream  
  3. {  
  4.          private InputStream in;  
  5.          private byte[] buf = new byte[1024];  
  6.          private int pos = 0, count = 0;  
  7.          MyBufferedInputStream(InputStream in)  
  8.          {  
  9.                    this.in = in;  
  10.          }  
  11.          //一次读一个字节,从缓冲区(字节数组)获取;  
  12.          public int myRead()throws IOException  
  13.          {  
  14.                    //通过in对象读取硬盘上的数据,并存储在buf中;  
  15.                    if(count == 0)  
  16.                    {  
  17.                             count = in.read(buf);  
  18.                             if(count < 0)  
  19.                                      return -1;  
  20.                             pos = 0;  
  21.                             byte b = buf[pos];  
  22.                             count--;  
  23.                             pos++;  
  24.                             return b;  
  25.                    }  
  26.                    else if(count > 0)  
  27.                    {  
  28.                             byte b = buf[pos];  
  29.                             count--;  
  30.                             pos++;  
  31.                             return b;  
  32.                    }  
  33.                    return -1;  
  34.          }  
  35.          public void myClose()throws IOException  
  36.          {  
  37.                    in.close();  
  38.          }  
  39. }  
  40.    
  41. class MyBufferedInputStreamDemo  
  42. {  
  43.          public static void main(String[] args) throws IOException  
  44.          {  
  45.                    MyBufferedInputStream bis = new MyBufferedInputStream(new FileInputStream("D:\\1.mp3"));  
  46.                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\2.mp3"));  
  47.                    int by = 0;  
  48.                    while((by = bis.myRead()) != -1)  
  49.                    {  
  50.                             bos.write(by);  
  51.                    }  
  52.                    bis.close();  
  53.                    bos.close();  
  54.          }  
  55. }

此代码在复制过程中,会出现目标文件中没有数据;这是问什么呢?

mp3文件的存储格式是二进制数据存放的,当取数据的时候碰到1111 1111 1111 1111 0000 0101 0100 1101… ,当连续读到8个二进制数据1111 1111返回时,将会被强转提升成int型,即变成-1,此时用4个八位存储该数据;所以当读到语句while((by = bis.myRead()) != -1)时,将跳出循环,不再写数据;就会出现以上情况。

 那么这个问题该如何解决呢?

 为了避免-1与判断标记-1相同,需要在保留原8个二进制数据1111 1111时,在转换成int类型时,在前24位补0,即00000000 00000000 00000000 11111111,这样既可以避免 原数据不变化,也可以避免出现于标记-1相同的情况出现。此时只需要将返回的b&255。其修改情况如下:

  1. public int myRead()throws IOException  
  2.          {  
  3.                    //通过in对象读取硬盘上的数据,并存储在buf中;  
  4.                    if(count == 0)  
  5.                    {  
  6.                             count = in.read(buf);  
  7.                             if(count < 0)  
  8.                                      return -1;  
  9.                             pos = 0;  
  10.                             byte b = buf[pos];  
  11.                             count--;  
  12.                             pos++;  
  13.                             return b&255;  
  14.                    }  
  15.                    else if(count > 0)  
  16.                    {  
  17.                             byte b = buf[pos];  
  18.                             count--;  
  19.                             pos++;  
  20.                             return b&0xff;  
  21.                    }  
  22.                    return -1;  
  23.          }

11、读取键盘录入
System.out:对应的是标准输出设备,控制台
System.in:对应标准输入设备,键盘。
     需求:利用键盘输入数据,并在控制台上打印出来,当遇到over时,退出打印。
  1. import java.io.*;  
  2. class ReadIn  
  3. {  
  4.          public static void main(String[] args) throws IOException  
  5.          {  
  6.                    InputStream in = System.in; //通过键盘输入数据;  
  7.                    StringBuilder sb = new StringBuilder();//定义一个容器存储数据;  
  8.                    while(true)  
  9.                    {  
  10.                             int ch = in.read();  
  11.                             if(ch == '\r')  
  12.                                      continue;  
  13.                             if(ch == '\n')//当遇到回车符时将数据转换成字符串;  
  14.                             {  
  15.                                      String s = sb.toString();  
  16.                                      if("over".equals(s))//遇到over时退出循环;  
  17.                                                break;  
  18.                                      System.out.println(s.toUpperCase());//打印出输入字符的大写;  
  19.                                      sb.delete(0,s.length());//每次输完一行后就清空一次容器;  
  20.                             }  
  21.                             else  
  22.                                      sb.append((char)ch);//否则就将数据存储在容器中;  
  23.                    }  
  24.          }  
  25. }

12、转换流(InputStreamReader、OutputStreamWriter)
1)、读取转换流
    通过以上示例发现就是每次读一行的原理,也就是readLine方法;这时可以考虑是否可以用readLine方法来实现以上方法呢?但readLine方法是字符流BufferedReader类中的方法,而键盘录入的read方法是字节流InputStream类中的方法,那么能不能将字节流转换成字符流,在使用字符流缓冲区的readLine方法呢?
通过API文档查找,我们知道了InputStreamReader类可以将字节流转换成字符流;而OutputStreamWriter则可以将字符流转换成字节流。读取转换流InputStreamReader是字节流通向字符流的桥梁; 写入转换流OutputStreamWriter 是字符流通向字节流的桥梁。
    所以以上代码可以简化成:
  1. import java.io.*;  
  2. class InputStreamReaderDemo   
  3. {  
  4.     public static void main(String[] args) throws IOException  
  5.     {  
  6.         //获取键盘录入;  
  7.         InputStream in = System.in;  
  8.         //将字节流转换成字符流,使用转换流;  
  9.         InputStreamReader isr = new InputStreamReader(in);  //读取转换流;
  10.         //为了提高效率使用缓冲流技术;  
  11.         BufferedReader bufr = new BufferedReader(isr);  
  12.         OutputStream out = System.out;  
  13.         OutputStreamWriter osw = new OutputStreamWriter(out); //写入转换流;
  14.         BufferedWriter bufw = new BufferedWriter(osw);  
  15.   
  16.         String line = null;  
  17.         while((line = bufr.readLine()) != null)  
  18.         {  
  19.             if(line.equals("over"))  
  20.                 break;  
  21.             bufw.write(line.toUpperCase());  
  22.             bufw.newLine();  //由于readLine不读取回车符,所以没读一行就需要重新换行;
  23.             bufw.flush();  
  24.         }  
  25.         bufr.close();  
  26.         bufw.close();  
  27.     }  
  28. }
记住:BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in))是以后键盘录入经常使用的语句。

13、流操作的 基本规律
    通过三个明确来完成:
1)、明确源和目的。
   源:输入流,InputStream   Reader
      目的:输出流,OutputStream Writer

2)操作的数据是否是纯文本文件

    是: 字符流     不是:字节流

3)当体系明确后,再明确使用哪个具体的对象,通过设备来进行区分:

    源设备:内存、硬盘、键盘;

    目的设备:内存、硬盘、控制台。

示例:
1.需求:将一个文本本件数据存储到另一个文件中(复制文件)
       源:因为是源,所以使用读取流:InputStream  Reader;
   是不是操作文本文件?是,选择Reader;
       接下来明确要使用该体系中的哪个对象
       明确设备:硬盘,文件  Reader体系中可以操作文本的对象是FileReader;
       是否需要提高效率?是,加入Reader体系中的缓冲区BufferedReader;
       FileReader fr= new FileReader(“a.txt”);
            BufferedReader bufr = new BufferedReader(fr);

   目的:OutputStream  Writer;
      是否是纯文本?是,选择Writer;
           Writer体系中可以操作文本的对象时FileWriter
      是否需要提高效率?是,加入Writer体系中的缓冲区BufferedWriter;
   FileWriter fw = new FileWriter(“b.txt”);
     BufferedWriter bufw = new BufferedWriter(fw);

2.需求:将键盘录入的数据保存在一个文件中。
源:InputStream  Reader   是否是纯文本? 是,选择Reader
设备:键盘。对应的对象时System.in
       System.in对应的是字节流,为什么要选择Reader呢? 为了操作键盘输入的文本数据方便,将字节流转换成字符      流,按照字符串操作时最方便的。既然明确了Reader,那么就将System.in转换成Reader;这时就需要使用Reader体      系中的转换流:InputStreamReader

         InputStreamReader isr = new InputStreamReader(System.in);

         需要提高效率吗?需要,则需要使用BufferedReader

          BufferedReader bufr = new BufferedReader(isr);


 目的:OutputStream  Writer

     设备:硬盘,文件,使用FileWriter

     是否是纯文本?是,使用Writer

          FileWriter fr = new FileWriter(“A.txt”);

 需要提高效率吗?需要,使用BufferedWriter

 BufferedWriter new = BufferedWriter(fr);

 

     扩展:需要把录入的数据按照指定的编码表UTF-8存入到文件中

 目的:OutputStream  Writer

 是否是纯文本?是,使用Writer

        设备:硬盘,文件,使用FileWriterFileWriter使用的是默认编码表:GBK.      

         但是存储时要使用指定的编码表UTF-8,而指定的编码表只有转换流可以指定,所以要使用的对象时                      OutputStreamWriter,而该转换流对象要接受一个字节输出流,而且还可以操作文件的字节输出流FileOutputStream 

        OutputStreamWriter osw 

        = new OutputStreamWriter(new FileOutputStream(“B.txt”),”UTF-8”);

         什么时候使用转换流?转换流为字符和字节之间的桥梁。通常涉及到字符编码转换时,需要用到转换流。
      示例:
  1. import java.io.*;  
  2. class InputStreamTest  
  3. {  
  4.          public static void main(String[] args) throws IOException  
  5.          {  
  6.                    BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));  
  7.                    BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\3.txt"),"UTF-8"));  
  8.                    //这里需要将指定的编码表作为参数传递到OutputStreamWriter;  
  9.                    String line = null;  
  10.                    while((line = bufr.readLine()) != null)  
  11.                    {  
  12.                             if(line.equals("over"))  
  13.                                      break;  
  14.                             bufw.write(line);  
  15.                             bufw.flush();  
  16.                             bufw.newLine();  
  17.                    }  
  18.                    bufr.close();  
  19.                    bufw.close();  
  20.          }  
  21. }

14、其他常用小操作
1)、改变标准输入输出设备(改变输入输出方式)
System.setIn(InputStream in)
System.setOut(PrintStream out)

2)、异常日志信息
演示示例:
  1. import java.io.*;  
  2. import java.util.*;  
  3. import java.text.*;  
  4. class ExceptionInfo   
  5. {  
  6.     public static void main(String[] args) throws IOException  
  7.     {  
  8.         try  
  9.         {  
  10.             int[] arr = new int[2];  
  11.             System.out.println(arr[2]);//角标越界异常发生;  
  12.         }  
  13.         catch (Exception e)  
  14.         {  
  15.             try  
  16.             {  
  17.                 Date d = new Date();  
  18.                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//打印异常信息日期;  
  19.                 String s = sdf.format(d);  
  20.                 PrintStream ps = new PrintStream("D:\\ExceptionLog.txt");//指定异常信息存放目的地;  
  21.                 ps.println(s);  
  22.                 System.setOut(ps);  
  23.             }  
  24.             catch (IOException ex)  
  25.             {  
  26.                 throw new RuntimeException("日志创建失败");  
  27.             }  
  28.             e.printStackTrace(System.out);  
  29.         }  
  30.     }  
  31. }
该程序将把异常信息以txt文本的形式存储在D盘,该信息包括异常出现日期、异常信息等。

3)、系统信息
  1. import java.util.*;  
  2. import java.io.*;  
  3. class SystemInfo   
  4. {  
  5.     public static void main(String[] args) throws IOException  
  6.     {  
  7.         Properties prop = System.getProperties();  
  8.         //System.out.println(prop);  
  9.         System.setOut(new PrintStream("D:\\1.txt"));  
  10.         prop.list(System.out);  
  11.     }  
  12. }
该程序也将把系统信息以txt文本形式输出到指定目录D盘,方便与读者参看。

----------------------  ASP.Net+Android+IOS开发 .Net培训 、期待与您交流! ----------------------



java程序设计》课程的题库资料,由贺州学院整理,可供学生期末课程复习使用,也可以供相关任课教师出卷使用。 内容示例为: 40. __________包包含了Collection的接口的类的API。 答案:Java.util 41. Math.round(11.5)等于__________,Math.round(-11.5)等于__________。 答案:12; -11 [考点范围] 常用的系统类 42. ________对象可以使用read方法从标准输入设备(通常键盘)读取数据;__________对象可以使用print方法向标准输出设备(屏幕)输出显示。 答案:System.in ;System.out [考点范围] JAVA输入输出系统 43. 框架(JFrame)和面板(JPanel)的默认布局管理器分别是______和_______。 答案:BorderLayout FlowLayout [考点范围] 图形用户界面 44. Swing的布局管理器主要包括_______。 答案:FlowLayout、BorderLayout、CardLayout、GridLayout、GridBogLayout、BoxLayout [考点范围] 图形用户界面 45. Java事件处理包括建立事件源、________和将事件源注册到监听器 。 答案:声明监听器 [考点范围] 图形用户界面 46. AWT的事件处理机制包括_______、事件和事件监听者。 答案:事件源 [考点范围] 图形用户界面 47. Swing的顶层容器有________、JApplet、JWwindow和JDialog。 答案:JFrame [考点范围] 图形用户界面 48. 线程的启动是通过调用其______________方法而实现的。 答案:start() [考点范围] 线程 49. Java虚拟机(JVM)中的线程调度器负责管理线程,调度器把线程的优先级分为10个级别,分别用Thread类中的类常量表示,每个Java线程的优先级都在常数________和_______之间,即Thread.MIN_PRIORIY和Thread.MAX_PRIORIY之间。 答案:1;10 [考点范围] 线程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值