现在的位置: 首页 > 综合 > 正文

java基础_Day19

2017年11月05日 ⁄ 综合 ⁄ 共 19723字 ⁄ 字号 评论关闭

1,BufferedWriter:
/*

字符流的缓冲区:

对应类:
     字符写入流缓冲区:BufferWriter:Writer的子类
     字符读取流缓冲区:BufferedReader:Reader的子类

缓冲区要结合流才可以使用,是在流的基础上对流的功能进行了增强。所以在建立缓冲区之前,必须要先有流对象。
*/
import java.io.*;
class BufferedWriterDemo
{
     public static void main(String[] args)throws IOException
     {
          //创建一个流对象:
          FileWriter fw = new FileWriter("buf.txt");
          //为了提高流的效率,加入了缓冲技术。
          //将需要被提高效率的流对象作为参数传递给缓冲区的构造函数。
          BufferedWriter bufw = new BufferedWriter(fw);
         
          for(int x=1;x<10;x++)
          {
               bufw.write("abcd"+x);
               //缓冲区的特有换行方法,不分系统:newLine()
               bufw.newLine();
               //只要用到缓冲区,就要记得刷新。写一次刷新一次,因为缓冲区的数据先写入内存,如果写完一段再刷新,遇到断电或者机器重启等的情况,数据就会写不进去。
               bufw.flush();
          }
          //其实关闭缓冲区就是关闭缓冲区中的流对象。只需关闭缓冲区,不必再关闭流对象。
          bufw.close();
     }
}

2,BufferedReader:
/*
字符流读取缓冲区:
*/
import java.io.*;
class BufferedReaderDemo
{
     public static void main(String[] args)throws IOException
     {
          //创建一个读取流对象:
          FileReader fr = new FileReader("buf.txt");
          //为了提高效率,加入缓冲技术,将字符流对象作为参数传递给缓冲区对象的构造函数。
          BufferedReader bufr = new BufferedReader(fr);
          //缓冲区的特有读取方法,读一行:readLine(),当返回null时,表示读到文件末尾。
          String line = null;
          while((line=bufr.readLine())!=null)
          {
               System.out.println(line);
          }
          bufr.close();
     }
}
3,通过缓冲区复制文本:
/*
通过缓冲区复制一个.java文件。
readLine方法返回的时候,只返回回车符之前的数据内容。并不返回回车符。
*/
import java.io.*;
class CopyTextBuf
{
     public static void main(String[] args)throws IOException
     {
          BufferedReader bufr = null;
          BufferedWriter bufw = null;
          try
          {
               bufr = new BufferedReader(new FileReader("CopyTextBuf.java"));
               bufw = new BufferedWriter(new FileWriter("复制.txt"));
               //该变量line是两个流之间的中转站:
               String line=null;
               while((line=bufr.readLine())!=null)
               {
                    bufw.write(line);
                    bufw.newLine();
                    bufw.flush();
               }
          }
          catch (IOException e)
          {
               throw new IOException("读写失败");
          }
          finally
          {
               try
               {
                    if(bufr!=null)
                    bufr.close();
               }
               catch (IOException e)
               {
                    throw new IOException("读取关闭失败");
               }
               try
               {
                    if(bufw!=null)
                    bufw.close();
               }
               catch (IOException e)
               {
                    throw new IOException("写入关闭失败");
               }
          }
     }
}
4,readLine原理:
无论是读一行,或者读取多个字符。其实最终还是从硬盘上一个一个读取。所以最终使用的还是read方法一次读一个的方法。
readLine方法返回的时候,只返回回车符之前的数据内容。并不返回回车符。
当其读取数据到\n的时候,会将之前存储的数据以字符串的形式返回。
5,MyBufferedReader:
import java.io.*;
import java.lang.*;
class MyBufferedReader
{
     private FileReader r;
     MyBufferedReader(FileReader r)
     {
          this.r=r;
     }

     //定义一个一次读取一行数据的方法:
     public String myReadLine()throws IOException
     {
          //定义一个临时容器,原BufferedReader封装的是字符数组。
          //为了演示方便,定义一个StringBuilder容器,因为最终还是要将数据变成字符串。
          StringBuilder sb =new StringBuilder();
          int ch=0;
          while((ch=r.read())!=-1)
          {
               if(ch=='\r')
                    //继续读取下一个字符:
                    continue;
               if(ch=='\n')
                    return sb.toString();
               else
                    sb.append((char)ch);
          }         
          //避免没有回车符时,只存,没返回的情况:
          if(sb.length()!=0)
               return sb.toString();
          return null;
     }

     //定义一个关闭缓冲区的方法:
     public void myClose()throws IOException
     {
          r.close();
     }
}

class MyBufferedReaderDemo
{
     public static void main(String[] args)throws IOException
     {
          FileReader fr = new FileReader("buf.txt");

          MyBufferedReader mybuf = new MyBufferedReader(fr);

          String line=null;
          //注意line=mybuf.myReadLine(),丢失line的话返回的都是null
          while((line=mybuf.myReadLine())!=null)
          {
               System.out.println(line);
          }
          mybuf.myClose();
     }
}

6,装饰设计模式:
/*
装饰设计模式:
     当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于已有的功能,提供加强功能,那么自定的该类称为装饰类。

装饰类通常会通过构造方法接收被装饰的对象。
并基于被装饰的对象的功能,提供更强的功能。
*/
class Person
{
     public void chifan()
     {
          System.out.println("吃饭");
     }
}

class SuperPerson
{
     private Person p;
     SuperPerson(Person p)
     {
          this.p=p;
     }
     public void superchifan()
     {
          System.out.println("开胃酒");
          p.chifan();
          System.out.println("甜点");
          System.out.println("来一根");
     }
}

class PersonDemo
{
     public static void main(String[] args)
     {
          Person p = new Person();
//          p.chifan();
          SuperPerson sp = new SuperPerson(p);
          sp.superchifan();
     }
}

7,装饰和继承:
MyReader//专门用于读取数据的类。
     |--MyTextReader
          |--MyBufferTextReader
     |--MyMediaReader
          |--MyBufferMediaReader
     |--MyDataReader
          |--MyBufferDataReader

class MyBufferReader
{
     MyBufferReader(MyTextReader text)
     {}
     MyBufferReader(MyMediaReader media)
     {}
}
上面这个类扩展性很差。
找到其参数的共同类型。通过多态的形式。可以提高扩展性。

class MyBufferReader extends MyReader
{
     private MyReader r;
     MyBufferReader(MyReader r)
     {}
}    

MyReader//专门用于读取数据的类。
     |--MyTextReader
     |--MyMediaReader
     |--MyDataReader
     |--MyBufferReader

以前是通过继承将每一个子类都具备缓冲功能。
那么继承体系会复杂,并不利于扩展。

现在优化思想。单独描述一下缓冲内容。
将需要被缓冲的对象。传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。
这样继承体系就变得很简单。优化了体系结构。

装饰模式比继承要灵活。避免了继承体系臃肿。
而且降低了类于类之间的关系。

装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。
所以装饰类和被装饰类通常是都属于一个体系中的。

8,自定义装饰类:
import java.io.*;
class MyBufferedReader extends Reader
{
    
     private Reader r;
     MyBufferedReader(Reader r)
     {
          this.r = r;
     }

     //可以一次读一行数据的方法。
     public String myReadLine()throws IOException
     {
          //定义一个临时容器。原BufferReader封装的是字符数组。
          //为了演示方便。定义一个StringBuilder容器。因为最终还是要将数据变成字符串。
          StringBuilder sb = new StringBuilder();
          int ch = 0;
          while((ch=r.read())!=-1)
          {
               if(ch=='\r') 
                    continue;
               if(ch=='\n')
                    return sb.toString();
               else
                    sb.append((char)ch);
          }

          if(sb.length()!=0)
               return sb.toString();
          return null;         
     }

     //覆盖Reader类中的抽象方法。
     public int read(char[] cbuf, int off, int len) throws IOException
     {
          return r.read(cbuf,off,len) ;
     }
     public void close()throws IOException
     {
          r.close();
     }
     public void myClose()throws IOException
     {
          r.close();
     }

}

class  MyBufferedReaderDemo1
{
     public static void main(String[] args) throws IOException
     {
          FileReader fr = new FileReader("buf.txt");

          MyBufferedReader myBuf = new MyBufferedReader(fr);

          String line = null;

          while((line=myBuf.myReadLine())!=null)
          {
               System.out.println(line);
          }

          myBuf.myClose();
     }
}

9,LineNumberReader:
/*

是BufferedReader的子类:

带行号的装饰类:
     特有方法:setLineNumber()和getLineNumber():分别用于设置和获取当前行号,默认从0开始
*/
import java.io.*;
class LineNumberReaderDemo
{
     public static void main(String[] args)throws IOException
     {
          FileReader fr = new FileReader("LineNumberReaderDemo.java");

          LineNumberReader lnr = new LineNumberReader(fr);
          String line=null;
          while((line=lnr.readLine())!=null)
          {
               System.out.println(lnr.getLineNumber()+":"+line);
          }
          lnr.close();
     }
}

10,MylineNunberReader:
import java.io.*;

class MyLineNumberReader extends MyBufferedReader
{
     private int lineNumber;
     MyLineNumberReader(Reader r)
     {
          super(r);
     }

     public String myReadLine()throws IOException
     {
          lineNumber++;
          return super.myReadLine();
     }

     public void setLineNumber(int lineNumber)
     {
          this.lineNumber = lineNumber;
     }
     public int getLineNumber()
     {
          return lineNumber;
     }
}

class MyLineNumberReaderDemo
{
     public static void main(String[] args)throws IOException
     {
          FileReader fr = new FileReader("MyLineNumberReaderDemo.java");

          MyLineNumberReader mylnr = new MyLineNumberReader(fr);
          mylnr.setLineNumber(100);
          String line = null;
          while((line=mylnr.myReadLine())!=null)
          {
               System.out.println(mylnr.getLineNumber()+":"+line);
          }
          mylnr.myClose();
     }
}

11,字节流file读写操作:
/*
字节流:
     InputStream:读
     OutputStream:写
*/
import java.io.*;
class FileStream
{
     public static void main(String[] args)throws IOException
     {
//          writeFile();
//          readFile_1();
          readFile_2();
     }
     //字节写入流:FileOutputStream
     public static void writeFile()throws IOException
     {
          FileOutputStream fos = new FileOutputStream("fos.txt");
          fos.write("abcdefg".getBytes());
          fos.close();
     }
     //字节读取流:FileInputStream
     //读一个操作一个:
     public static void readFile_1()throws IOException
     {
          FileInputStream fis = new FileInputStream("FileStream.java");
          int ch=0;
          while((ch=fis.read())!=-1)
          {
               System.out.print((char)ch);
          }
          fis.close();
     }
     //用数组作中转站:
     public static void readFile_2()throws IOException
     {
          FileInputStream fis = new FileInputStream("FileStream.java");
//          int num = fis.available();
//          System.out.println(num);
          //定义一个刚刚好的缓冲区,不用再循环了。这种情况容易内存溢出。
          byte[] buf = new byte[fis.available()];
          fis.read(buf);
          System.out.println(new String(buf));
          /*
          byte[] buf = new byte[1024];
          int len=0;
          while((len=fis.read(buf))!=-1)
          {
               System.out.print(new String(buf,0,len));
          }
          */
          fis.close();
     }
}
12,拷贝图片:
/*
复制一个图片
思路:
1,用字节读取流对象和图片关联。
2,用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。
3,通过循环读写,完成数据的存储。
4,关闭资源。

*/

import java.io.*;
class  CopyPic2
{
     public static void main(String[] args)
     {
          FileOutputStream fos = null;
          FileInputStream fis = null;
          try
          {
               //创建目的地:
               fos = new FileOutputStream("c:\\99.png");
               //用字节读取流与已有的文件相关联:
               fis = new FileInputStream("c:\\JIUJIU.png");
               //定义数组为中转站:
               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("写入关闭失败");
               }
          }
     }
}

13,字节流的缓冲区:
/*
演示mp3的复制。通过缓冲区。
BufferedOutStream
BufferedInputStream
*/

import java.io.*;
class CopyMp3
{
     public static void main(String[] args)throws IOException
     {
          long start = System.currentTimeMillis();
          copy_1();
          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:\\000.mp3"));
          //缓冲区中其实已经定义了数组为中转站。所以这里不需要再定义中转站。
          int by=0;
          while((by=bufis.read())!=-1)
          {
               bufos.write(by);
          }
          bufos.close();
          bufis.close();
     }
}

14,自定义字节流的缓冲区read和write的特点:
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;
               byte b = buf[pos];
               count--;
               pos++;
               return b&255;
          }
          else if(count>0)
          {
               byte b = buf[pos];
               count--;
               pos++;
               return b&0xff;
          }
          return -1;
     }
     public void myClose()throws IOException
     {
          in.close();
     }
}

class MyBufferedInputStreamDemo
{
     public static void main(String[] args)throws IOException
     {
          long start = System.currentTimeMillis();
          copy_1();
          long end = System.currentTimeMillis();
          System.out.println((end-start)+"毫秒");
     }
     public static void copy_1()throws IOException
     {
          //与已有文件相关联,并加入缓冲技术:
          MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("c:\\0.mp3"));
          //创建目的地。加入缓冲技术:
          BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\0099.mp3"));
          //缓冲区中其实已经定义了数组为中转站。所以这里不需要再定义中转站。
          int by=0;
          //这次没有写进去,因此拷贝的文件会比源文件小一个字节。
          System.out.println("第一个字节是:"+bufis.myRead());
          //因此复制的文件大小为0字节的原因是读取到的第一个字节是-1,循环没有进行。
          while((by=bufis.myRead())!=-1)
          {
               bufos.write(by);
          }
          bufos.close();
          bufis.myClose();
     }
}

15,读取键盘录入:
/*
读取键盘写入:
System.out:对应的是标准的输出设备,控制台。
System.in:对应的是标准的输入设备,键盘。

需求:通过键盘录入数据,当录入一行数据偶,就将改行数据打印,如果录入over,那么停止录入。
*/
import java.io.*;
class ReadIn
{
     public static void main(String[] args)throws IOException
     {
          InputStream in = System.in;
          StringBuilder sb = new StringBuilder();

          //int ch = 0;
          //Ctrl+C其实就是在加了一个结束标记:返回-1;
          //读取一个字节,打印一个字节:
          /*
          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());
               }
               else
                    sb.append((char)ch);
          }
     }
}

16,读取转换流:
/*
通过刚才键盘录入一行数据并且打印其大写。发现其实就是读一行数据的原理。
也就是readLine方法。

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

那么能不能将字节流转换成字符流再使用字符流缓冲区中的readLine方法呢?
InputStreamReader:本身是一个字符流,构造函数需要接收一个字节流。
*/
import java.io.*;

class TransStreamDemo
{
     public static void main(String[] args)throws IOException
     {
          //获取键盘录入:
          InputStream in = System.in;
          //将字节流对象转化成字符流对象,使用转换流。InputStreamReader
          InputStreamReader isr = new InputStreamReader(in);
          //加入缓冲技术。提高效率,使用BufferedReader
          BufferedReader bufr = new BufferedReader(isr);
          String line=null;
          while((line=bufr.readLine())!=null)
          {
               //定义结束标记:录入over时结束
               if("over".equals(line))
                    break;
               System.out.println(line.toUpperCase());
          }
          bufr.close();
     }
}

17,写入转换流:
/*
     OutputStreamWriter
*/
import java.io.*;
class OutputStreamWriterDemo
{
     public static void main(String[] args)throws IOException
     {
//          InputStream in = System.in;
//          InputStreamReader isr = new InputStreamReader(in);
//          BufferedReader bufr = new BufferedReader(isr);
//          OutputStream out = System.out;
//          OutputStreamWriter osw = new OutputStreamWriter(out);
//          BufferedWriter bufw = new BufferedWriter(osw);
          //键盘录入:一次读取一行数据。
          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();
          }
     }
}
18,流操作规律1:
/*
1,几种操作:
     1,源:键盘录入。
        目的;控制台。

     2,需求:把键盘录入的数据存储到一个文件中。
          源:键盘。
          目的:文件。

     3,需求:将一个文件中的数据打印在控制台上。‘
          源:文件。
          目的:控制台。

2,流操作的基本规律:通过两个明确来完成。

     1,明确源和目的。
          源:输入流。InputStream  Reader
          目的:输出流。OutputStream  Writer
     2,操作的数据是否是纯文本。
          是:字符流
          不是:字节流
     3,当体系明确后,再明确要使用哪个具体的对象。
          通过设备来进行区分:
          源设备:内存,硬盘,键盘
          目的设备:内存,硬盘,控制台。
3,将一个文本文件中的数据存储到另一个文件中。复制文件。书写思考步骤:
     源:InputStream  Reader

          是不是操作纯文本文件:是,选择Reader,这样体系就明确了。
          接下来明确使用体系中的哪个对象,明确设备,设备是硬盘上的一个文件,Reader中可以操作文件的对象是FileReader
          FileReader fr = new FileReader("a.txt");
          提高效率:
          BufferedReader bufr = new BufferedReader(fr);

     目的:OutputStream  Writer      
          是不是纯文本:是选择Writer。
          设备:硬盘上的一个文件。Writer中可以操作文件的对象是FileWriter
          FileWriter fw = new FileWriter("b.txt");
          提高效率:
          BufferedWriter bufw = new BufferedWriter(fw);

4,将一个图片文件数据存储到另一个文件中。    

*/
import java.io.*;
class TransStreamDemo2
{
     public static void main(String[] args)throws IOException
     {
          //键盘录入:一次读取一行数据。
          BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("TransStreamDemo2.java")));
          //
          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();
          }
     }
}

19,流操作规律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);

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

     **************
     扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
    
     目的:OutputStream  Writer
     是否是存文本?是!Writer。
     设备:硬盘。一个文件。使用 FileWriter。
     但是FileWriter是使用的默认编码表。GBK.
    
     但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。
     所以要使用的对象是OutputStreamWriter。
     而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream

     OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");

     需要高效吗?需要。
     BufferedWriter bufw = new BufferedWriter(osw);

     所以,记住。转换流什么使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时,
     需要用到转换流。

练习:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。

20,改变标准输入输出设备:
          System.setIn(new FileInputStream("PersonDemo.java"));

          System.setOut(new PrintStream("zzz.txt"));



21,异常的日志信息:
 

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 sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String s = sdf.format(d);

                    PrintStream ps = new PrintStream("exeception.log");
                    ps.println(s);
                    System.setOut(ps);

                   
               }
               catch (IOException ex)
               {
                    throw new RuntimeException("日志文件创建失败");
               }
               e.printStackTrace(System.out);
          }
     }
}
建立日志信息工具:log4j : 



22,系统信息:

import java.util.*;
import java.io.*;
class  SystemInfo
{
     public static void main(String[] args) throws IOException
     {
          Properties prop = System.getProperties();

          //System.out.println(prop);
          prop.list(new PrintStream("sysinfo.txt"));
     }
}

抱歉!评论已关闭.