黑马程序员_第18、19天

第18天

(一)   System

System:类中的方法和属性都是静态的。

out:标准输出,默认是控制台。

in:标准输入,默认是键盘。

描述系统的一些信息。

获取系统属性信息:Properties getProperties();

 

因为Properties是Hashtable的子类,也就是Map集合的一个子类对象。

那么可以通过map的方法取出该集合中的元素。

该集合中存储的都是字符串。没有泛型定义。

 

(二)   Runtime

 Runtime类并没有提供构造函数。

说明不可以new对象。那么会直接想到该类中的方法都是静态的。

发现该类中还有非静态方法。

说明该类肯定会提供了方法获取本来对象。而且该方法是静态的,并返回值类型是本类对象。

由这个特点可以看出该类使用了单例设计模式完成。

 

(三)   IO流

字符流和字节流:

字节流两个基类:

InputStream   OutputStream

字符流两个基类:

Reader Writer

先学习一下字符流的特点。

既然IO流是用于操作数据的,

那么数据的最常见体现形式是:文件。

那么先以操作文件为主来演示。

需求:在硬盘上,创建一个文件并写入一些文字数据。

找到一个专门用于操作文件的Writer子类对象。FileWriter。后缀名是父类名。前缀名是该流对象的功能。

流操作练习:复制文本文件

    public static void copy_2()
    {
        FileWriter fw = null;
        FileReader fr = null;
        try
        {
            fw = new FileWriter("SystemDemo_copy.txt");
            fr = new FileReader("SystemDemo.java");

            char[] buf = new char[1024];

            int len = 0;
            while((len=fr.read(buf))!=-1)
            {
                fw.write(buf,0,len);
            }
        }
        catch (IOException e)
        {
            throw new RuntimeException("读写失败");

        }
        finally
        {
            //关闭流要分开try,打开几个流就写几个try。
            if(fr!=null)
                try
                {
                    fr.close();
                }
                catch (IOException e)
                {
                }
            if(fw!=null)
                try
                {
                    fw.close();
                }
                catch (IOException e)
                {
                }
        }
    }

 

第19天

(一)BufferedWriter

BufferedWriter

缓冲区的出现时为了提高流的操作效率而出现的。

所以在创建缓冲区之前,必须要先有流对象。

BufferedWriter缓冲区中提供了一个跨平台的换行符:newline();

BufferedReader缓冲区提供了一个一次读一行的方法readLine();当返回null是表示读到文件末尾。

readLine()方法返回的时候只返回回车符之前的数据内容,不返回回车。

 

自己实现readLine()方法:

 

    //可以一次读一行数据的方法。
    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;        
    }

装饰设计模式:

当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。这个自定义类就称为装饰类。

装饰类通常会通过构造方法接收被装饰的对象。

并基于被装饰的对象的功能,提供更强的功能。

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();
    }
}

 装饰模式比继承要灵活。避免了继承体系臃肿。

而且降低了类与类之间的关系。

装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能。

所以装饰类和被装饰类通常都属于同一个体系。

 

练习:模拟一个带行号的缓冲区对象。

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 MyLineNumberReader 
{
    private Reader r;
    private int lineNumber;
    MyLineNumberReader(Reader r)
    {
        this.r = r;
    }

    public String myReadLine()throws IOException
    {

        lineNumber++;
        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 setLineNumber(int lineNumber)
    {
        this.lineNumber = lineNumber;
    }
    public int getLineNumber()
    {
        return lineNumber;
    }

    public void myClose()throws IOException
    {
        r.close();
    }
}
*/

 

(二)字节流

字符流:

FileReader

FileWriter。

BufferedReader

BufferedWriter

 

字节流:

InputStream  OutputStream

需求,想要操作图片数据。这时就要用到字节流。

读文件,使用字节流逐个读:

    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(new String(buf));

        fis.close();
    }

复制一个图片:

思路:

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("写入关闭失败");
            }
        }
    }
}

 Mp3的复制。通过缓冲区。

BufferedOutputStream

 

import java.io.*;
class  CopyMp3
{
    public static void main(String[] args) throws IOException
    {
        long start = System.currentTimeMillis();
        copy_2();
        long end = System.currentTimeMillis();

        System.out.println((end-start)+"毫秒");
    }

    public static void copy_2()throws IOException
    {
        MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("c:\\9.mp3"));
        BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\3.mp3"));
        
        int by = 0;

        //System.out.println("第一个字节:"+bufis.myRead());

        while((by=bufis.myRead())!=-1)
        {
            bufos.write(by);
        }

        bufos.close();
        bufis.myClose();
    }

    //通过字节流的缓冲区完成复制。
    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();

        
    }
}

 自定义缓冲区:

import java.io.*;

class MyBufferedInputStream
{
    private InputStream in;

    private byte[] buf = new byte[1024*4];
        
    private int pos = 0,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();
    }
}

读取键盘录入。

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();

        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.delete(0,sb.length());
            }
            else
                sb.append((char)ch);
        }
    }
}

读取转换流:

通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。

也就是readLine方法。

能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?

readLine方法是字符流BufferedReader类中的方法。

而键盘录入的read方法是字节流InputStream的方法。

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

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);

        //键盘的最常见写法。
        BufferedReader bufr = 
                new BufferedReader(new InputStreamReader(System.in));
    
//        OutputStream out = System.out;
//        OutputStreamWriter osw = new OutputStreamWriter(out);
//        BufferedWriter bufw = new BufferedWriter(osw);
        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,明确源和目的。

         源:输入流。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.

         不是选择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);

 

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

         需要用到转换流。

 

改变标准输入输出设备:

         System.setIn(new FileInputStream("PersonDemo.java"));

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

 

 

异常的日志信息:

       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);

 系统信息:

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"));
    }
}

 

posted on 2013-05-12 22:20  SinceDayOne  阅读(129)  评论(0编辑  收藏  举报

导航