zoukankan      html  css  js  c++  java
  • 22天学习java基础笔记之day22

    Day22 IO

    一、IO流的特点及相关问题

    1. IO流用来处理设备之间的数据传输

    设备:硬盘,内存,键盘录入

    1. Java对数据的操作是通过流的方式
    2. Java用于操作流的对象都在IO包中
    3. 流按操作数据分为两种:字节流与字符流。
    4. 流按流向分为:输入流,输出流。

    1、输入流和输出流的流向的理解?

    流就是处理数据的一种方式或者一种手段,或者理解为一种数据流。

            从硬盘已有的数据读取出来放内存里面的这个过程就是输入流。

    外部--------->内存           输入流  

            把内存中的数据存储到硬盘中的这个过程就是输出流。

    内存--------->外部           输出流    

            简单理解就是:以内存为中心。

    2、什么时候使用流对象?

            操作设备上的数据或操作文件的时候可以使用。

    二、字符流

    字符流的抽象基类:Reader &Writer

    1、字符流的理解,由来和作用?

    由于很多国家的文字融入进来,比如说中文在编码表中默认占2个字节。(在UTF-8中是3个字节)而为了按照文字的单位来处理,所以出现了字符流。

            由来:后期编码表的不断出现,识别某一文字的码表不唯一。比如中文,GBK&unicode都可以识别,就出现了编码问题,为了处理文字数据,就需要通过早期的字节流+编码表结合完成。

            作用:为了更便于操作文字数据。

    结论:只要是处理纯文本数据,就要优先考虑使用字符流,除此之外都是用字节流。

    2IO分类

    按照功能进行分类---------->读和写

     

    字节流

    inputStream(字节输入流

    outputStream() 字节输出流

    字符流

    Reader(字符输入流

    Writer()   字符输出流

    IO体系中的子类名称后缀大部分都是父类名称,而前缀都是体现子类功能的名字

    Reader

    InputStreamReader

           FileReader

    专门用于处理文件的

    字符读取流对象

    Writer

    OutputStreamWriter

             FileWriter

    专门用于处理文件的

    字符写入流对象

    3、字符流继承体系图

     

    4Reader中的常见方法

    • int read()读取一个字符。返回的是读到的那个字符(0-65535),如果读到流的末尾,返回-1
    • int read(char[ ]):将读到的字符存入指定的数组中,返回的是读到的字符个数,也就是往数组里装元素的个数,如果读到流的末尾,返回-1。
    • close( )读取字符用的是windows系统的功能,就希望使用完毕后,进行资源的释放。

    5Writer中的常见方法

    • void write(ch)将一个字符写入到流中。
    • void write(char[ ])将一个字符数组写入到流中。
    • void write(String)将一个字符串写入到流中。
    • void flush()刷新流,将流中的数据刷新到目的地中,流还存在
    • void close()关闭资源,在关闭前会先调用flush(),刷新流中的数据去目的地,然后关闭流。

    6FileWriter

    该类没有特有的方法,只有自己的构造方法。

    特点:

    1. 用于处理文本文件;
    1. 该类中有默认的编码表;
    2. 该类中有临时缓冲。

    构造方法:在写入流对象初始化时,必须有一个存储数据的目的地

    1. FileWriter(String filename):该构造函数做了什么事情呢?

    A:调用系统资源;

    B:在指定位置创建一个文件,如果该文件已经存在,将会被覆盖。

    1. FileWriter(String filename,boolean true)该构造函数如果传入的boolean类型值为true时,会在指定文件末尾处进行数据的续写
    2. 换行:private static final String LINE_SEPARATOR = System.getProperties("line.separator");

      fr.writer("xi"+LINE_SEPARATOR+"xi");

    7FileReader

    用于读取文本文件的流对象,用于关联文本文件。

    构造函数:在读取流对象初始化的时候,必须要指定一个被读取的文件,如果该文件不存在会发生FileNotFindException

    FileReader  fr = new  FileReader(String filename)

    基本的读写操作方式

    因为数据通常都以文件的形式存在,所以就要找到IO体系中可以用于操作文件的流对象,通过名称可以更容易获取该对象。

    8、将文本数据存储到一个文件中。

    import java.io.FileWriter;

    import java.io.IOException;

    public class Demo1 {

        public static void main(String[] args) throws IOException {

            FileWriter fw = new FileWriter("E:\1.txt");

            fw.write("abcd");

            fw.flush();//数据刷到目的地了,流还可以继续使用

            fw.write("mn");

            fw.close();//数据也刷到目的地了,但是流不能再被使用

        }

    }

    文件中写入的数据:abcdmn            意外收获:异常包也得导入。

    对于读取或者写入流对象的构造函数,以及读写方法,还有刷新关闭功能都会抛出IOException或其子类。

    所以要进行处理,要么抛出throws,要么try……catch处理。

    9、完整的异常处理方式。

    import java.io.FileWriter;

    import java.io.IOException;

    public class Demo2 {

        public static void main(String[] args) {

            FileWriter fw = null;//定义为全局,关闭的时候也要使用

            try {

                fw = new FileWriter("E:\1.txt");

                fw.write("abcd");

                fw.flush();

                fw.write("mn");

            } catch (IOException e) {

                e.printStackTrace();

            } finally {

                if (fw != null) {//防止空指针异常----->运行时异常要做健壮性判断

                    try {

                        fw.close();

                    } catch (IOException e) {

                        throw new RuntimeException("关闭异常");

                    }

                }

            }

        }

    }

    小细节:当指定绝对路径时,定义目录分隔符有两种方式:

    1,反斜线,但是一定要写两个。new FileWriter("c:\1.txt");

    2,斜线,一个即可。new FileWriter("c:/1.txt");

    10、读取字符流对象的两种方式

    读取一个已有的文本文件,将文本数据打印出来。

    方式一:一次读取一个字符

    import java.io.FileReader;

    import java.io.IOException;

    public class Demo3 {

        public static void main(String[] args) {

            FileReader fr =null;

            try {

    //1,创建一个文件读取流对象,和指定名称的文件相关联要保证该文件已经存在的。如果不存在,会发生异常。FileNotFoundException

                fr = new FileReader("e:\1.txt");

    //2,定义一个变量,用于记录读到的那个字符对应的二进制数值。char在0-65535之间,不存在就-1。

                int ch=0;

    //3,用循环读取文件中的数据

                while((ch=fr.read())!=-1){

                    System.out.print((char)ch);

                }

            } catch (Exception e) {

                e.printStackTrace();

            } finally{

                if(fr!=null){

                    try {

                        fr.close();

                    } catch (IOException e) {

                        e.printStackTrace();

                    }          

                }

            }

        }

    }

    方式二:将读取的字符放入一个字符数组中<较第一种效率要高得多>

    import java.io.FileReader;

    import java.io.IOException;

    public class Demo4 {

        public static void main(String[] args) {

            FileReader fr = null;

            try {

    //1,创建一个文件读取流对象,和指定名称的文件相关联要保证该文件已经存在的。如果不存在,会发生异常。FileNotFoundException

                fr = new FileReader("e:\1.txt");

                //2,定义一个字符数组,用于存储到的字符

    char[] ch = new char[1024];//长度通常是1024的整数倍

    //3,定义一个变量,用于记录读取字符的个数,读到末尾返回-1。

                int len = 0;

    //4,把读到的字符暂时存到buf数组中该read(char[])返回的是读到字符的个数

                while ((len = fr.read(ch)) != -1) {

                    System.out.print(new String(ch, 0, len));

                }//将字符数组转换成字符串输出

            } catch (Exception e) {

                e.printStackTrace();

            } finally {

                if (fr != null) {

                    try {

                        fr.close();

                    } catch (IOException e) {

                        e.printStackTrace();

                    }

                }

            }

        }

    }

    11、复制文本文件的原理

    首先用一个读取流对象和一个文件进行关联,然后用一个写入流对象作为目地的,为了把读取流中的文件传输到目的地流对象中,我们就提供了一个字符数组,为了关联这个数组,所以读取流对象有一个read()方法与这个字符数组进行关联,同理,写入流对象也有一个write()方法与这个字符数组进行关联,这样2个流对象就相连接了,而这个字符数组就相当于一个中转站。

    e盘的文件复制到i盘中

    public class CopyFileTest {

        public static void main(String[] args) {

            File startfile = new File("e:\a.txt");

            File endfile = new File("i:\hello.txt");

            copyFile(startfile, endfile);

        }

        public static void copyFile(File startfile,File endfile){

            FileReader fr = null;

            FileWriter fw = null;

            try {

                //1,创建一个字符读取流读取与源数据相关联。

                fr = new FileReader(startfile);

                //2,创建一个存储数据的目的地。

                fw = new FileWriter(endfile);

                //3,创建一个字符数组将读取流对象和写入流对象相连接。

                char[] buf = new char[1024];

                //4,每次读取的长度不一样,所以定义一个变量.

                int len = 0;

                //5,用循环读取文件中的数据

                while((len = fr.read(buf))!=-1){//判断是否读取完没

                    fw.write(buf,0,len);       //为了只写入有效的数据

                }

            } catch (Exception e) {

                e.printStackTrace();

            } finally {

                if(fr!=null){

                    try {

                        fr.close();

                    } catch (Exception e2) {

                        throw new RuntimeException("读取流关闭失败");

                    }

                }

                if(fw!=null){

                    try {

                        fw.close();

                    } catch (Exception e2) {

                        throw new RuntimeException("写入流关闭失败");

                    }

                }

            }

        }

    }

    声明:为了减少代码的书写,以后出现的异常全使用抛出!

    三、字符流缓冲区

    1、字符缓冲区的原理

    其实就是将数组进行封装。变成对象后,方便于对缓冲区的操作,提高效率。并提供了对文本便捷操作的方法。readLine( )&newLine( )。

     

    缓冲区的基本思想就是对要处理的数据进行临时存储。譬如购物车以及篮子。

    原理:减少频繁的操作,给读取流对象和写入流对象提供中转站,相对于来回跑的麻烦,利用缓冲区的容量,可以一边先存储,满了后再写入的方式,这样就提高了效率。

    BufferedWriter的特有方法:newLine():跨平台的换行符。

    BufferedReader的特有方法:readLine():一次读一行,到行标记时,将行标记之前的字符数据作为字符串返回。当读到末尾时,返回null。(返回的字符是不带回车符的)

    在使用缓冲区对象时,要明确,缓冲的存在是为了增强流的功能而存在的,所以在建立缓冲区对象时,要先有流对象存在。其实缓冲内部就是在使用流对象的方法,只不过加入了数组对数据进行了临时存储,为了提高操作数据的效率

    2、代码上的体现

    A:写入缓冲区对象-------->带缓冲区的写操作,一般都要进行刷新!

    建立缓冲区对象必须把流对象作为参数传递给缓冲区的构造函数。

    BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));

    bw.write("abcd");//将数据写入缓冲区

    bw.flush();//对缓冲区的数据进行刷新,将数据刷到目的地中

    bw.close();//关闭缓冲区,其实关闭的是被包装在内部的流对象。

    B:读取缓冲区对象

    BufferedReader br = new BufferedReader(new FileReader("b.txt"));

    String line = null;

    while((line= br.readLine)!=null){

    System.out.println(line);

    }

    br.chose();

    3readLine( )方法的原理

    其实缓冲区中的该方法,用的还是与缓冲区关联的流对象的read方法,只不过,每一次读到一个字符,先不进行具体操作,而是进行临时存储。当读到回车标记时,将临时容器中的数据一次性返回。----->StringBuilder调用了buff.read()将缓冲区中的数据存储到了该容器中。

    1. 缓冲区的read()和流对象的read()方法的区别?

    流对象:从目的地一次读取一个字符

    缓冲区:通过流对象的read([])将一批数据读取到缓冲数组,然后在数组中一次取一个字符,内存比硬盘操作要高效。

    4、自定义缓冲区MyBufferedReader

    /*

     * 模拟一个缓冲区

     * 基于已有的缓冲区思想,我们可以从源读取用read方法。

     * 我们的缓冲区,应该是一个更高效的read读取方法。

     */

    public class MyBufferedReader extends Reader{

        private Reader r;

        private char[] buf = new char[1024];

    //用于记录缓冲区数据的个数

        private int count = 0,pos = 0;

        public MyBufferedReader(Reader r){

            this.r = r;

        }

        /**

         * 一次从缓冲区中取一个

         * @return 返回一个缓冲区中的字符

         * @throws IOException

         */

        public int myRead() throws IOException {

            //1,首先判断缓冲区中是否有数据,如果没有就从源中去拿。

            if(count == 0){

    //读取一批数据到缓冲数组buf中

                count = r.read(buf);

                pos = 0;

            }

            //2,当缓冲区中没数据了且源中也没有数据时,count自减1小于0时就返回-1结束.

            if(count < 0)

                return -1;

            //3,如果以上都不满足,那么从缓冲区中写入一个字符到新的文件中。

            char ch = buf[pos];

            pos++;

            count--;

            return ch;

        }

        /**

         * 按照文本特点,提供一个特有的操作文本的方法。

         * 一次读取一行文本,只要是到行结束符之前的文本即可。

         * @return 返回读取到的一行文本

         * @throws IOException

         * 原理:就是从缓冲区中取出数据,并存储到一个临时容器中。

         * 如果取到了回车符,就将临时容器中的数据转成字符串返回。

         */

        public String myReadLine() throws IOException{

            //1,定义一个临时容器,进行临时存储

            StringBuilder sb = new StringBuilder();

            //2,定义一个变量,接收读取到的字符对应的二进制数(ASCII),0-65535

            int ch = 0;

            while((ch = myRead()) != -1){

                //3,当读取到 时,直接跳出本次循环,进行下次循环

                if(ch == ' ')

                    continue;

                //4,当读取到 时,直接跳出当前循环

                if(ch == ' ')

                    return sb.toString();

                //5,当都没有读取到时,就将这些数据存储到临时容器中。

                sb.append((char)ch);

            }

            //6,当临时容器中的长度不等于0时,就输出字符。

            if(sb.length() != 0)

                return sb.toString();

            return null;

        }

        @Override

        public void close() throws IOException {

        }

        @Override

        public int read(char[] arg0, int arg1, int arg2) throws IOException {  

            return 0;

        }

    }

    5、通过缓冲区的形式,对文本文件进行拷贝

    public class BufferCopyTest {

        public static void main(String[] args) throws IOException {

            BufferedReader br = new BufferedReader(new FileReader("e:\a.txt"));

            BufferedWriter bw = new BufferedWriter(new FileWriter("i:\copy.txt"));

            String line = null;

            while((line = br.readLine())!=null){//高效读操作

                bw.write(line);//高效写

                bw.newLine();//换行符

                bw.flush();

            }

            bw.close();

            br.close();

        }

    }

  • 相关阅读:
    php的运行模式
    PostgreSQL指定用户可访问的数据库pg_hba.conf
    PostgreSQL创建只读用户
    Python操作PostGreSQL数据库
    Python爬虫基础示例
    Linux下设置tomcat开机自启
    Windows下配置jar环境
    警告1909。无法创建快捷方式VMware Workstation Pro.Ink。解决方法(附 VMware_workstation 12的安装方法)
    删数问题
    An Easy Problem
  • 原文地址:https://www.cnblogs.com/aohongzhu/p/12938747.html
Copyright © 2011-2022 走看看