Java程序设计学习笔记(三)—— IO

时间:2016-3-24 11:02

——IO流(Input/Output)


    IO流用来处理设备之间的数据传输。
    Java对数据的操作是通过流的方式。
    Java对于操作流的对象都在IO包中。

    流按操作数据分为两种:字节流与字符流。
        字符流为了处理文本数据,可以在内部融合编码表,编码表可以自己指定,处理文字时不会出现乱码。
        图片等文件使用字节流。
        首个中国编码表——GB2312
        后来进行了一次扩容——GBK
        再后来为了方便使用,将世界上各个国家的编码表融合——Unicode,在Unicode编码表中无论什么字符,都用两个字节来表示。
        后期Unicode进行了优化,产生了UTF-8,在UTF-8中,能用一个字符就用一个字符,减少空间浪费。

    字符流的由来:
            不同编码表之间的字符会产生乱码,为了避免此现象的发生,Java在流技术上,就基于字节流产生了字符流,字符流可以在字
            符流内部指定编码表,从而解决不同编码表之间的乱码问题。

        通用字节流,字符流是基于字节流的。
        

    流按流向分为:输入流和输出流。

——字符流

    FileReader、FIleWriter、BufferedReader、BufferedWriter

    1、IO流常用基类(这四个类都是抽象类)
        字节流的抽象基类: 
            InputStream,OutputStream
        字符流的抽象基类:
            Reader,Writer
        注:由这四各类派生出来的子类名称都是以其父类名作为自类名的后缀。
            如:InputStream的子类FileInputStream
            如:Reader的子类FileReader
        后缀名是父类名,前缀名是该流对象的功能。
 
    2、Writer类
        是抽象类,构造方法是protected,也就是只能在子类中使用。
        Writer类的共性方法:
            Writer append(char c)
                
            abstract void close()
                关闭流,并刷新流。
                当流关闭后,不能再使用write方法。
            abstract void flush()
                刷新流
            void write(int c)
                写入单个字符。
                write()方法仅仅是将数据写入到内存当中,也就是写入到流中,想要将数据写入文件,需要刷新流。flush()方法刷新流。
            void write(char[] cbuf)
                写入字符数组。
            void write(String str)
                写入字符串。
            void write(String str,int off,int len)
                写入字符串的某一部分。
                    str--字符串    off--相对初始写入字符的偏移量(从哪开始)    len--要写入的字符数。

        既然IO流是用于操作数据的,数据的最常见体现形式是:文件,那么就以操作文件为主来演示。
        需求:
            在硬盘上,创建一个文件并写入一些文字数据。
            找到一个专门用于操作文件的Writer子类对象:FileWriter,前缀名是功能,后缀名是父类名。
            (可以发现,Writer实现的子类特点:前缀名是功能,后缀名是父类名)
            public static void main(String[] args) throws IOException
            {
                //创建一个FileWriter对象,该对象一被创建就必须明确被操作的文件
                //因此该类没有无参构造方法。
                FileWriter fw = new FileWriter("aaaass.txt");
                fw.write("akkkk");
                fw.flush();
                fw.close();
            }

    3、FileWriter
        构造方法:
            FileWriter(String fileName)
                根据给定的文件名构造一个FileWriter流对象。
            FileWriter(String fileName, boolean append)
                根据给定的文件名以及指示是否附加写入数据的boolean值来构造一个FileWriter流对象。
                append:一个boolean值,如果为true,则将数据写入文件末尾处,而不是写入文件开始处。
                               也就是实现了文件的续写,不再从文件开头写数据了。
                               如果文件不存在,先创建文件再续写,如果文件存在,直接续写。

        在Windows操作系统中,换行符是:
        在Linux操作系统中,换行符是:

        继承自Writer的方法:
            abstract void close()
                关闭流,并且刷新流。
            abstract void flush()
                刷新该流的缓冲。
            void write(int c)
                写入单个字符。
            void write(String str)
                写入字符串。
            void write(String str,int off,int len)
                写入字符串的某一部分。
            void wrie(cha[] cbuf)
                写入字符数组。
            abstract void write(char[ ] cbuf,int off,int len)
                写入字符数组的某一部分。

    4、IO异常处理
        凡是能和设备产生关系的操作都会发生异常。
        FileWriter fw = null;    //需要将fw定义在try外部,否则finally无法访问。
        try
        {
            fw = new FileWriter("A:\demo3.txt");
            fw.write("123123");
        }
        catch(IOException e)
        {
            System.out.println("hello"+e.toString());
        }
        finally
        {
            try
            {
                if(fw != null)    //关闭流之前需要判断一下fw是否为null,因为如果fw对象创建失败,调用close时会抛出空指针异常。
                fw.close();    //关流动作一定要执行,所以放在finally中,关闭前先判断有没有流。
            }
            catch(IOException e2)
            {
            System.out.println(e2.toString());
            }
        } 

    5、FileReader
        用来读取字符文件的便捷类,此类的构造方法有默认的字符编码和默认字节缓冲区。 
        默认编码可以通过getProperties()方法获取当前系统的编码。,该编码表是可变化的。
        将文本读入流中。
        构造方法:
            该类的对象一被创建就必须明确要操作的文件,所以该类没有无参构造方法。
            FileReader(String fileName)
                在给定从中读取数据的文件名的情况下创建一个新的FileReader流对象。
                并且该文件会被创建到指定目录下,如果该目录下已有同名文件,将覆盖原文件。
            FileWriter(File file)
                指定文件。

        继承自Reader的方法:
            abstract void close()
                关闭流并释放与之关联的所有资源。
                并不刷新流。 
 
            int read()
                读取单个字符,返回的是int型的ASCII码值。
                read方法一次读取一个字符,而且会自动往下读。 
                如果读到文件的末尾,会返回-1。 

            代码示例:
            //一次读取一个字符
            public static void main(String[] args)throws IOException
            {
                //创建一个文件读取流对象,和指定名称的文件相关联
                //要保证该文件是存在的
                //如果不存在,会发生异常:FileNotFoundException,这个异常是IOException的子类。
                FileReader fr = new FileReader("Demo.txt");
 
                int ch = 0;
                //调用读取流对象的read方法
                while((ch = fr.read()) != -1)
                {
                    System.out.print((char)ch);
                }
                fr.close();
            } 

            int read(char [ ] buff)
                将字符读入数组,返回的是int型的字符个数。
                没有直接读字符串的方法。
                通常字符数组的长度定义为1024或者是1024的整数倍。
         
        代码示例:
            //使用字符数组读取字符
            public static void main(String[] args)throws IOException
            {
                FileReader fr = new FileReader("Demo.txt");
 
                //定义一个字符数组,用于存储读到的字符。
                //该read(char[])方法返回的是读到的字符个数。
                char[] buf = new char[3];
                int num = fr.read(buf);
                System.out.println("num=" + num + ".." + new String(buf));
                num = fr.read(buf);
                System.out.println("num=" + num + ".." + new String(buf));
                num = fr.read(buf);
                System.out.println("num=" + num + ".." + new String(buf));    //如果读取到文本末尾,则没必要全部输出,所以可以通过
                                                                                                               //另一个String方法来输出字符数组:String(char[].offset,len)
                                                                                                               //功能是将指定长度的字符数组转换为字符串。
            }

            //使用循环读取字符
            publicstatic void main(String[] args) throws IOException
            {
                FileReaderfr = new FileReader("Demo.txt");
                char[]ch = new char[3];
                int num;
                while((num= fr.read(ch)) != -1)
                {
                    System.out.println("num= " + num + ".." + new String(ch,0,num));
                }
                fr.close();
            } 

            abstract int read(char[ ],int off,int len)
                从数组指定位置开始读入字符,从off处开始读取字符,要读取的最多字符数为len。

    6、使用FileReader和FileWriter复制文件
            public static void main(String[] args) throws IOException
            {
                //定义读取流
                FileReader fr = new FileReader("D:\Java3.txt");
                //定义一个字符数组来存储读取的字符
                char[] buf = new char[1024];
                //定义输出流
                FileWriter fw = new FileWriter("D:\copy.txt");
                //定义一个num来存储读取到的字符个数
                int num = 0;
                //开始读取并写入
                while((num = fr.read(buf)) != -1) 
                {
                    fw.write(buf);
                }
                fr.close();
                fw.close();
            }
 

    7、字符流的缓冲区
        缓冲区的出现提高了对数据的读写效率。
        对应类
            BufferedWriter
            BufferedReader
        缓冲区要结合流才可以使用,因为缓冲区的为了提高流的操作效率。
        在流的基础上对流的功能进行了增强。

    8、BufferedReader
        从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
        读取流缓冲区在对象建立时需要有被缓冲的对象,也就是在缓冲区构造方法中传入FIleReader的对象。
        构造方法:
            BufferedReader(Read in)
                创建一个默认大小输入缓冲区的缓冲字符输入流。
                in是一个流对象。
        继承自Reader的方法:
            void close()
                关闭该流并释放与之关联的所有资源。
            int read()
                读取单个字符。
            int read(char[ ],int off,int len)
                从指定位置开始读入,并且指定长度。
        特有方法:
            String readLine()
                读取一个文本行。遇到' '或者' '就认为某行终止。
                读完一行会自动跳到下一行。
                包含该行内容的字符串,不包含任何行终止符,如果达到流的末尾,则返回null。
                因为不会读取到换行符,所以在读取过程中一般配合newLine使用。
                readLine底层其实就是read方法。

        代码示例:
 
        import java.io.*;
        public class BufferedReaderDemo01 {
        public static void main(String[] args) throws IOException
        {
            //创建一个读取流对象和文件相关联
            FileReader fr = new FileReader("D:\Demo.txt");
 
            //为了提高效率,加入了缓冲技术
            //将字符读取流对象作为参数传递给缓冲区对象的构造方法
            BufferedReader bufr = new BufferedReader(fr);
//          String s1 = bufr.readLine();
//         String s2 = bufr.readLine();
//         System.out.println("s1 : " + s1);
//         System.out.println("s2 : " + s2);
            String s = null;
            while((s = bufr.readLine()) != null)
            {
                System.out.println(s);
            }
            bufr.close();
        }
    }
 

    9、BufferedWriter
        将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。(意思就是全部存完一次写入)
        该类的构造方法必须有参数,因为有流才有缓冲区。
所以在创建缓冲区之前,必须有流对象。一般开发都会加入缓冲区技术,对性能和效率进行增强。
        构造方法:
            BufferedWriter(Writer out)
                创建一个使用默认大小输出缓冲区的缓冲字符输出流。
                out是一个Writer流对象。
        继承自Writer的方法:
            void close()
                关闭此流并刷新。
            void flush()
                刷新该流的缓冲。
            void write(char [ ],int off,int len)
                写入字符数组的某一部分。
            void write(int c)
                写入单个字符。
            void write(String s,int off,int len)
                写入字符串的某一部分。
        特有方法:
            void newLine()
                写入一个行分隔符,换行。
                因为在Windows中换行符是“ ”,而Linux中换行符为“ ”,会出现兼容性问题,所以newLine的出现提高了Java的跨平台性。

        代码示例:
        
         /**
         * 2016年3月23日23:45:29
         * 使用缓冲区对文件进行写入
         * 
         * 缓冲区的出现是为了提高流的操作效率而出现的
         * 所以在创建缓冲区之前,必须要先有对象。
         * 该缓冲区中提供了一个跨平台的换行符。
         * @author WYC
         *
         */
        import java.io.*;
        public class BufferedWriterDemo01 {
        public static void main(String[] args) throws IOException
        {
            //创建一个字符写入流对象
            FileWriter fw = new FileWriter("D:\Demo.txt");
            //为了提高字符写入流效率,加入了缓冲技术。
            //只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
            BufferedWriter bufw = new BufferedWriter(fw);
 
            for(int i = 1; i <= 100; i++)
            {
                bufw.write("aaaaaaaaa + " + i);
                bufw.newLine();
                if(i % 10 == 0)
                {
                    bufw.flush();
                }
            }
            bufw.close();
        }
    }

    10、使用缓冲区复制文本文件
        /**
         * 通过缓冲区复制文本文件
         * 2016年3月24日00:10:28
         * 
         * 该缓冲区提供了一个一次读一行的方法readLine(),方便与对文本数据的获取
         * 当readLine返回null时,表示读到文件末尾
         * 
         * 注意:readLine方法返回的字符串只返回回车符之前的数据内容,并不返回回车符,所以需要手动newLine
         * @author WYC
         *
         */
        import java.io.*;
        public class BufferedTest {
            public static void main(String[] args) throws IOException
            {
                FileReader fr = new FileReader("D:\Demo.txt");
                BufferedReader bufr = new BufferedReader(fr);
 
                FileWriter fw = new FileWriter("D:\copy.txt");
                BufferedWriter bufw = new BufferedWriter(fw);
                String s = null;
                while((s = bufr.readLine()) != null)
                {
                    bufw.write(s);
                    bufw.newLine();
                    bufw.flush();
                }
                bufr.close();
                bufw.close();
            }
        }

    11、LineNumberReader 
        跟踪行号的缓冲字符输入流。 
        该类继承自BufferedReader,所以可以直接调用BufferedReader的方法。
        此类定义了方法setLineNumber(int)和getLineNumber(),用于设置行号和获取行号,默认情况下,行号从0开始。
        
        setLineNumber(int):设置起始行号。
        getLineNumber()   :获取当前行号。 
    12、输入输出举例
        包含了FileReader,FileWriter,BufferedReader,BufferedWriter的用法。
        import java.io.BufferedReader;
        import java.io.BufferedWriter;
        import java.io.FileNotFoundException;
        import java.io.FileReader;
        import java.io.FileWriter;
        import java.io.IOException;
        
        public class FileReaderDemo {
            public static void main(String[] args) throws IOException
            {
                //fr_1();
                //fr_2();
                //fw_1();
                copy();
                bufr();
                bufw();
            }
            //使用循环输出单个字符
            public static void fr_1()
            
            {
                FileReader fr = null;
                int num = 0;
                try
                {
                    fr = new FileReader("dd.txt");
                    while((num = fr.read()) != -1)
                    {
                        System.out.print((char)num);
                    }
                }
                catch(IOException e)
                {
                    System.out.println("读入错误!程序终止!");
                    System.exit(0);
                }
                finally
                {
                    try
                    {
                        if(fr != null)
                        fr.close();
                    }
                    catch(IOException e)
                    {
                        System.out.println("资源未关闭!");
                    }
                }
                System.out.println();
            }
            //使用循环输出字节数组,每次循环读入300个字节。
            public static void fr_2()
            {
                FileReader fr = null;
                try
                {
                    int num = 0;
                    char[]buf = new char[300];
                    fr = new FileReader("G:\Java\eclipse workspace\IO\src\test\FileReaderDemo.java");
                    while((num = fr.read(buf)) != -1)
                    {
                        System.out.print(new String(buf,0,num));
                    }
                }
                catch(IOException e)
                {
                    System.out.println("读入错误!程序终止!");
                    System.exit(0);
                }
                finally
                {
                    try
                    {
                        if(fr != null)
                        fr.close();
                    }
                    catch(IOException e)
                    {
                        System.out.println("资源未关闭!");
                    }
                }
            }
            //使用循环写入单个字符
            public static void fw_1()
            {
                FileWriter fw = null;
                try
                {
                    fw = new FileWriter("dd.txt",true);
                    char[] buf = {'1','2','3','4','5'};
                    for(int i = 0; i < 5;i++)
                    {
                        fw.write(buf[i]);
                    }
                }
                catch(IOException e)
                {
                    System.out.println("写入错误!程序终止!");
                    System.exit(0);
                }
                finally
                {
                    try
                    {
                        if(fw != null)
                        fw.close();
                    }
                catch(IOException e)
                {
                    System.out.println("资源未关闭!");
                }
            }
        }
        //拷贝文本文件
        public static void copy()
        {
            FileReader fr = null;
            FileWriter fw = null;
            try
            {
                fr = new FileReader("G:\Java\eclipse workspace\IO\src\test\FileReaderDemo.java");
                fw = new FileWriter("G:\Java\eclipse workspace\IO\123.txt");
                char [] buf = new char[5];
                int num = 0;
                while((num = fr.read(buf)) != -1)
                {
                    fw.write(buf);
                }
            }
            catch(IOException e)
            {
                System.out.println("读写失败!程序终止!");
                System.exit(0);
            }
            finally
            {
                try
                {
                    if(null != fr)
                        fr.close();
                    if(null != fw)
                        fw.close();
                }
                catch(IOException e)
                {
                    System.out.println("资源未关闭!");
                }
            }
        }
        //创建一个字符读取流缓冲区
        //该缓冲区提供了一个一次读取一行的方法:readLine,当读取到文件末尾的时候返回null
        public static void bufr() throws IOException
        {
            FileReader fr = new FileReader("dd.txt");
            BufferedReader bufr = new BufferedReader(fr);
            String str = null;
            while((str = bufr.readLine()) != null)
            {
                System.out.println(str);
            }
            bufr.close();
        }
        //字符流写入缓冲区
        //缓冲区的出现是为了提高流的操作效率而出现的,所以创建缓冲区之前必须要有流对象
        //该缓冲区提供了一个跨平台的换行操作:newLine()
        public static void bufw() throws IOException
        {
            //创建一个字符写入流对象。
            FileWriter fw = new FileWriter("dd.txt",true);
            //为了提高字符写入效率,加入了缓冲技术。
            //只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
            BufferedWriter bufw = new BufferedWriter(fw);
            int i = 0;
            while(i < 5)
            {
                bufw.write("abc"+i);
                bufw.newLine();
                //只要用到缓冲区就要刷新。flush
                bufw.flush();
                i++;
            }
            bufw.close();//关闭缓冲区,相当于关闭流对象。
        }
    }

 
    13、装饰设计模式
        当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类可以
        成为装饰类。
        例如
            BufferedReader中的读取一行:readLine();
        装饰类通常会通过构造方法接受被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。

        装饰模式比继承要灵活,避免了集成体系的臃肿,而且降低了类与类之间关系。
        装饰类因为增强已有对象,具备的功能和已有的功能是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常都属于同一
        个体系中。

        /**
         * 装饰设计模式
         * @author Administrator
         *
         */
        public class BufferedReaderDemo02 {
            public static void main(String[] arsg)
            {
                SuperCar sc = new SuperCar(new Car());
                sc.superRun();
            }
        }
        class Car
        {
            public void run()
            {
                System.out.println("启动");
            }
        }
        class SuperCar
        {
            private Car c;
            public SuperCar(Car c)
            {
                this.c = c;
            }
            public void superRun()
            {
                System.out.println("无钥匙进入");
                c.run();
            }
        }

——字节流

    1、FileOutputStream
        如果想要操作图片数据,就需要用到字节流。
        字符串转成字节数组的方法:
            byte[] String.getBytes()
        字符串转成字符数组的方法:
            String[] toCharArrays()
        int available()
            返回剩余字符数。
        可以通过available()的返回值来确定数组大小,但是虚拟机启动时默认是64MB,所以需要注意数组大小。

    2、字节流缓冲区
        BufferedInputStream 和 BufferedOutputStream

    10、IOStream
        字符流需要刷新数据,而字节流不需要刷新,因为字符流中有一个字符数组,临时存储字符数据,刷新后才将数组内容写入。
        字节流如果不使用缓冲区,就不需要刷新操作。

        import java.io.FileInputStream;
        import java.io.FileNotFoundException;
        import java.io.FileOutputStream;
        import java.io.IOException;
    
        public class FileStream {
            public static void main(String[] args) throws IOException
            {
                //Output();
                //Input_1();h
                //Input_2();
                Input_3();
            }
            //FileOutputStream简单用法
            public static void Output() throws IOException
            {
                FileOutputStream fos = new FileOutputStream("fos.txt");
                fos.write("abcdefg".getBytes());
                fos.close();
            }
            //FileInputStream简单用法,读取单个字节。
            public static void Input_1() throws IOException
            {
                FileInputStream fis = new FileInputStream("fos.txt");
                int ch = 0;
                while((ch = fis.read()) != -1)
                {
                    System.out.println((char)ch);
                }
                fis.close();
            }
            //FileInputStream简单用法,读取字节数组。
            public static void Input_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();
            }
            //使用FileInputStream中的available()方法返回文件总的字节数。
            //使用available可以定义足够长的数组一次性全部读入文件,但是会导致内存溢出,不建议使用
            public static void Input_3() throws IOException
            {
                FileInputStream fis = new FileInputStream("fos.txt");
                int num = fis.available();
                byte[] buf = new byte[num];
                fis.read(buf);
                System.out.println(new String(buf));
            }
        }
 
    11、用FileInputStream和FileOutputStream复制一个图片
        public class CopyPic {
            public static void main(String[] args) throws IOException
            {
                FileInputStream fis = new FileInputStream("C:\Users\WYC\Desktop\1.jpg");
                FileOutputStream fos = new FileOutputStream("C:\Users\WYC\Desktop\2.jpg");
                byte [] buf = new byte[1024];
                int len = 0;
                while((len = fis.read(buf)) != -1)
                {
                    fos.write(buf);
                }
                fos.close();
                fis.close();
            }
        }
 
    12、用BufferedI/OStream复制一个图片
        public class BufferedStream {
            public static void main(String[] args) throws IOException
            {
                //copy_pic();
                copy_pic2();
            }
            //使用单个字节复制
            public static void copy_pic() throws IOException
            {
                BufferedInputStream bfis = new BufferedInputStream(new FileInputStream("C:\Users\WYC\Desktop\1.jpg"));
                BufferedOutputStream bfos = new BufferedOutputStream(new FileOutputStream("C:\Users\WYC\Desktop\3.jpg"));
 
                int num = 0;
                while((num = bfis.read()) != -1)
                {
                    bfos.write(num);
                }
                bfis.close();
                bfos.close();
            }
            //使用字节数组复制
            public static void copy_pic2() throws IOException
            {
                BufferedInputStream bfis = new BufferedInputStream(new FileInputStream("C:\Users\WYC\Desktop\1.jpg"));
                BufferedOutputStream bfos = new BufferedOutputStream(new FileOutputStream("C:\Users\WYC\Desktop\4.jpg"));
                byte[]buf = new byte[1024];
                int len = 0;
                while((len = bfis.read(buf)) != -1)
                {
                    bfos.write(buf, 0, len);
                }
                bfis.close();
                bfos.close();
            }
        }
    13、读取键盘录入
        import java.io.IOException;
        import java.io.InputStream;
        /*
         * 2015年12月18日22:20:38
         * 通过键盘录入数据
         * 当录入一行数据之后,就将该行数据进行打印
         * 如果录入的数据是over
         * 就停止录入
         */
        public class KeyboardDemo {
            public static void main(String[] args) throws IOException
            {
                InputStream in = System.in;
                int ch = 0;
                StringBuilder sb = new StringBuilder();
                while((ch = in.read()) != -1)
                {
                    if(ch == ' ')
                    continue;
                    if(ch == ' ')
                    {
                        String st = sb.toString();
                        if("over".equals(st))
                            break;
                        System.out.println(sb.toString().toUpperCase());
                        sb.delete(0, sb.length());
                    }
                    else
                        sb.append((char)ch);
                }
            }
        }
 
    14、读取转换流
        InputStreamReader,专门用于操作字节流的字符流对象。
        可以将字节流转换成字符流。
        在构造时需要接收一个字节流对象。
            InputStreamReader(InputStream in)
        方法继承自Reader。
        /*
            通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。
            也就是readLine()方法。
            那么能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
            readLine方法是字符流缓冲区Buff而恶毒Reader类中的方法。
            那么能不能将字节流转成字符流再使用字符流缓冲区的readLine方法呢?
        */
        public class TransStreamDemo {
            public static void main(String[] args) throws IOException
            {
                //字节转字符
                InputStream in = System.in;
                InputStreamReader isr = new InputStreamReader(in);
                BufferedReader bufr = new BufferedReader(isr);
                String line = null;
                while((line = bufr.readLine()) != null)
                {
                    if("over".equals(line))
                        break;
                    System.out.println(line.toString().toUpperCase());
                }
                //字符转字节
                OutputStream out = System.out;
                OutputStreamWriter osw = new OutputStreamWriter(out);
                BufferedWriter bufw = new BufferedWriter(osw);
 
                while((line = bufr.readLine()) != null)
                {
                    if("over".equals(line))
                        break;
                    bufw.write(line.toUpperCase());
                    bufw.newLine();
                    bufw.flush();
                }
                bufw.close();
                bufr.close();
            }
        }
    15、流操作规律
        /*
         * 2015年12月19日09:18:54
         * 需求:从键盘输入数据,存储到文件
         * 把文件输出到控制台只需要把传入的对象调换一下即可
         * 
         */
 
        public class StreamDemo {
            public static void main(String[] args) throws IOException
            {
                BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt")));
                BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
                String line = null;
                while((line = bufr.readLine()) != null)
                {
                    if("over".equals(line))
                    break;
                    bufw.write(line.toUpperCase());
                    bufw.newLine();
                }
                bufw.close();
                bufr.close();
            }
        }

    16、总结规律
        流操作的基本规律:
            最痛苦的就是对象有很多,不知道该用哪一个。
        选择对象可以通过三个步骤来完成:
            1、明确源和目的
                源:输入流
                        InputStream
                        Reader
                目的:输出流
                        OutputStream
                        Writer
            2、操作的数据是否是纯文本
                如果是,就选择字符流。
                如果不是,就选择字节流。
            3、当体系明确后,再明确要使用哪个具体的对象。
                通过设备来进行区分:
                    源设备:内存,硬盘,键盘。
                    目的设备:内存,硬盘,控制台。
        复制文件:将一个文本文件中的数据存储到另一个文件中。
            源:因为是源,所以使用读取流:InputStream和Reader
                是不是操作文本文件?
                    是!就可以选择字符流Reader。
                明确设备:硬盘中的文件。
                    Reader体系中可以操作文件的对象是FileReader。
                是否需要提高效率?
                    是!使用BufferedReader缓冲区。
                FileReader fr = new FileReader("a.txt");
                BufferedReader bufr = new BufferedReader(fr);
            目的:因为是目的,所以使用输出流:OutputStream和Writer
                是否纯文本?
                    是!使用字符流Writer
                设备:硬盘中的一个文件。
                    Writer体系中可以操作文件的对象是FIleWriter。
                是否需要提高效率?
                    是!使用BufferedWriter缓冲区。
                FileWriter fw = new FileWriter("b.txt");
                BufferedWriter bufw = new BufferedWriter(fw);


    17、指定编码表
        想要把录入的数据按照指定的编码表(utf-8),将数据存储到文件中。
        目的:OutputStream和Writer
        是否存储为文本文件?
            是!使用Writer
        设备:硬盘中的一个文件
            使用Writer体系中可以操作文件的FIleWriter
        但是FIleWriter是使用默认的编码表GBK,存储时需要加入指定的编码表utf-8,而指定的编码表只有转换流可以指定。
        所以要使用的对象是OutputStreamWriter,并且该转换流对象要接收一个字节输出流对象(FileOutputStream),还可以接收指定
        的编码表。
            OutputStreamWriter osw = new OutputStreamWritrr(new FileOutputStream("a.txt"),"utf-8");
        是否需要提高效率?需要。
            BufferedWriter bufw = new BufferedWriter(osw);
        所以,转换流什么时候使用?
            通常涉及到字符编码转换时,需要用到转换流。
        /*
         * 2015年12月19日14:33:15
         * 使用转换流指定utf-8编码表
         */
        public class TransStreamDemo {
            public static void main(String[] args) throws IOException
            {
                OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("test1.txt"),"GBK");
                BufferedWriter bufw = new BufferedWriter(osw);
                BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
                String line = null;
                while((line = bufr.readLine()) != null)
                {
                    if("over".equals(line))
                    break;
                    bufw.write(line);
                    bufw.newLine();
                    bufw.flush();
                }
                bufw.close();
                bufr.close();
            }
        }
    18、改变标准输入输出设备
        System中的setIn和setOut方法,可以改变输入输出设备。
        如果setIn方法参数是一个文本文件,setOut方法参数也是一个文本文件,就会复制文件。 
原文地址:https://www.cnblogs.com/wwwwyc/p/6375036.html