zoukankan      html  css  js  c++  java
  • Java IO(上)

     捕获

    IO中基本概念和开发过程中如何确定该使用到哪些类.

     

     

     

    1,基本概念

    输入和输出的定义是对于计算机中的内存而言的,从内存到外围设备(比如硬盘)是输出,从外围设备到内存,是输入.

    字节:计算机可以认识的数据.

    字符:通过是控制台输出的内容,人可以认识的.

    字符流的由来:计算机读取到的其实是字节数据,然后在根据提供的各种编码表(每个国家都有自己特有文字的编码表),去获取对应的文字,通俗的来将字符流就是字节流+编码表.

         JavaIO操作只要是指Java进行输入和输出的操作,所涉及到的类和接口都存放在java.io包中,使用时需要导包,从上图可以看出,JavaIO中最重要的有5个类和一个接口,

    InputStream,Reader,OutputStream,Writer,File,和接口Serializable.一下我将用文字简单的总结各个类的特点和类中特有的方法.

        在IO中,主要有字节流和字符流两大类,这两大类都具有输入和输出的功能,在字节流中,输入(InputStream),输出(OutputStream),在字符流中,输入(Reader),输出(Writer)

    2,在开发的过程中,需要明确到时是使用以上到哪些类?我们可以通过4个步骤(熟练后只需要确定最后源和目的的设备即可),就能快速的判断出来

    2.1,明确源和目的(汇)   源:InputStream  Reader    目的:OutputStream  Writer
         2.2明确数据是否是纯文本数据   源:如果是纯文本,Reader 否:InputStream
                                          目的:是纯文本  Writer       否 :OutputStream
          到这里,就可以明确需求中具体要使用到哪个体系
         2.3明确具体的设备     源设备: 硬盘:File 键盘:System.in  内存:数组  网络:Socket流
                                 目的设备:  硬盘:File  控制台:System.out 内存:数组  网络:Socket

    2.4是否需要其他额外功能  1,是否需要高效(缓冲区)   是,就加上buffered

     

     

    2.5需求与代码(通过四部曲来判断使用到的类),一下4个需求,我都会加入额外功能,缓冲区(BufferedReader和BufferedWriter)

    需求1:复制一个文本文件 

    分析:源和目的在硬盘设备上的纯文本文件, FileReader和FileWriter

    需求2:读取键盘存入信息,并存入一个文件中

    分析:源是键盘,目的是硬盘上的纯文本信息, (源需要进行转化,字节->字符)InputStreamReader is = System.in     FileWriter

    需求3:将文本文件的数据显示到控制台上

    分析:源是硬盘,目的是控制台(System.out)的纯文本信息   FileReader   (计算机到控制台显示,字符->字节)OutputStreamWriter ops = System.out

    需求4:读取键盘录入信息,显示在控制台上

    分析:源是键盘(System.in),目的是控制台(System.out)     InputStreamReader ips = System.in  OutputStreamWriter = System.out

    需求5:将一个中文字符串数据按照指定的码表写入到一个文本本件中去

    分析:按照指定的码表,这个一定得想到转化流

    源(硬盘File):转化流的话,查阅API,那么使用的是OutputStreamWriter中的构造方法传入2个参数OutputStream和Charset

    目的(硬盘File):按照源的思路,InputStreamReader中的构造方法传入两个参数InputStream和Charset

    上述5个是IO中最基本的操作,其中设计到一个比较关键的问题,我们社么时候需要考虑使用转换流?

    1,源和目的对应的设备都是字节流,但操作却是文本数据

    2,一旦操作涉及到指定编码的时候,一定得使用转换流

    /*
     * 需求:复制一个文本文件
     */
    public class demo01 {
        public static void main(String[] args) throws IOException {
            BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
            BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
            String line = null;
            while((line=bufr.readLine())!=null){
                bufw.write(line);
                bufw.flush();
            }
        }
    }
    
    //需求:读取键盘录入信息,并存入文件
    public class demo02 {
        public static void main(String[] args) throws IOException {
            BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
            BufferedWriter bufw = new BufferedWriter(new FileWriter("c.txt"));
            String line = null;
            while((line=bufr.readLine())!=null){
                bufw.write(line);
                bufw.flush();
            }
        }
    }
    
    //需求:将文本文件数据显示到控制台
    public class demo03 {
        public static void main(String[] args) throws IOException {
            BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
            BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
            String line = null;
            while((line=bufr.readLine())!=null){
                bufw.write(line);
                bufw.flush();
            }
        }
    }
    
    //需求  读取键盘录入数据,显示到控制台
    public class demo04 {
        public static void main(String[] args) throws IOException {
            BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
            BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
            String line = null;
            while((line=bufr.readLine())!=null){
                bufw.write(line);
                bufw.flush();
            }
        }
    }

    关于BufferedReader和BufferWriter,缓冲区的理解

    缓冲区的原理:从源中先拿到一部分数据,方法缓冲区中先使用,当缓冲区的数据使用完毕后,再从源中取出数据到缓冲区,直到源中没有数据,为-1或者的null作为结尾,这样能提高效率.

    这两个类都是为了提高访问效率,构造方法中需要要传入各自对应的Reader和Writer的对象,没有无参的构造方法.

    源BufferedReader中,有两个读取方法,捕获,一般最后一个比较常用,这里要注意下返回值的不同,int的为-1,String的为null.

    对于读取文件中的数据,都是用读取文本行的方法来完成的,这样能大大的提高提取的效率,tips:使用while循环读取的时候,它的返回值是null.

    目的BufferWriter中,有个方法是特有的,捕获

    Java中的递归

    递归的含义:函数自身直接或者间接的调用自身.

    什么时候使用递归:一个功能被重复使用,参与运算的结果与上次函数调用有关,这类问题都可以利用递归来解决

    递归的注意事项:一个功能被设计成递归,那么这个功能的运算必须要有入口,也比较要有出口,一定要明确条件,否则会发生栈溢出

                       注意递归的次数,假如没明确结束条件,会出现异常

    public class DiGuiDemo {
        public static void main(String[] args) {
            int sum = getSum(5);
            System.out.println("sum:" + sum);
        }
    
        public static int getSum(int i) {
            if (i == 1)
                return 1;
            return i + getSum(i - 1);
        }
    }

    以上例子就是一个递归的运用,去实现连续的自然数的相加,这里的if语句中的代码,就把递归的次数明确好了,从5开始,连续的到2,这里是连续的在调用getSum的函数,然后到1的时候,直接返回的是1,这个时候递归结束,注意,从5到4,这个时候只是在调用函数,这个时候并没有进行加法的循环,知道1结束后,就需要弹栈,这个时候从1开始,从后向前进行加法的运算,这个是重点,该开始我想不同的原因,就是没想想明白,递归的时候,函数是什么时候弹栈的.

    File类

    1 基本概念

    它是在IO中,唯一与文件操作有关的类,通过构造方法,传入字符串的参数,将已经存在或者不存在的文件或者目录封装成对象,以后只要操作到具体的文件,我们就应该把它进行封装,然后再进行操作.

    在File类中提供了两个非常重要的常量:2

    捕获

    在操作文件的时候,一定要使用File.separator来表示分隔符,因为在不同的操作系统上,它会显示对于该操作系统的分割符.

     

    2 下面将介绍几个比较常用的File类中的方法

    列出指定目录的全部文件(比如列出D盘下的文件,它只会到D的一层目录,不会到D目录下的子目录或者子子(子子....)目录)

    12

    以上2个方法,一个返回的是String字符串形式,一个返回的是File[]数组对象,数组对象的输出需要遍历,你懂的,一般我喜欢第二种方式的输出.

    3 那么我们如何可以将D盘目录下的所有的文件的路径都显示出来?这个时候就需要使用到递归了.

    深度遍历的思路:1,创建一个显示所有目录的方法,该方法需要传入一个File对象的参数(需要深度遍历的文件)

                        2,使用方法二对File对象进行遍历

                        3,在遍历的过程中需要进行判断,使用捕获 判断传入的File对象有子目录,那么就递归在调用自身的方法

                        4,弹栈的动作,递归到最后了,然后在输出目录.具体代码如下

    public class FileTest1 {
        public static void main(String[] args) {
            File f = new File("d:");
            listAll(f);
        }
    
        public static void listAll(File f) {
            System.out.println("dir:" + f.getAbsolutePath());
            File[] file = f.listFiles();
            for (int i = 0; i < file.length; i++) {
                if (file[i].isDirectory())
                    listAll(file[i]);
                else
                    System.out.println("file:" + file[i].getAbsolutePath());
            }
        }
    
    }
    
    public class FileTest2 {
    
        /*
         * 需求:删除里面带有内容的目录 原理:从最里面往外面删除 需要进行深度遍历
         * 
         */
        public static void main(String[] args) {
            File f = new File("d:\\a");
            removeDir(f);
        }
    
        public static void removeDir(File f) {
            File[] file = f.listFiles();
            for (File file2 : file) {
                if (file2.isDirectory()) {
                    removeDir(file2);
                } else {
                    System.out.println(file2 + ":" + file2.delete());
                }
            }
            System.out.println(f + ":" + f.delete());
        }
    
    }

    上述两个应用涉及到的File方法123

    上面的删除动作,加入文件夹中是有数据或者内容的话,该文件夹是不能被该方法所删除的,所以一般进行删除操作,都需要从里面到外面来进行操作.

    4,关键文件名过滤的问题

    123

    通过上面3张图中的内容可以完成过滤,用法和Java类集中的比较器原理类似.

    SequenceInputStream类

    该类是将几个输入流连在一起,提供两个构造方法,捕获从API上可以看出,如果需要传入2个以上的输入流的话,我们需要拿到输入流的枚举对象,关于枚举,必须要想到集合框架中的Collections这个工具类,它其中有个方法可以获取集合对象的枚举类型捕获

    需求:将a.txt  b.txt  c.txt三个文本文件中的内容合并到一个文本文件abc.txt中

    分析:该需求是将3个输入流合并到一起,应该使用下面那个构造方法,通过Collections中的方法来获取3个小输入流的枚举

          1,将a,b,c3个在硬盘(File)上的文本文件进行输入流的封装  FileInputStream

          2,创建ArrayList集合,将3个流装入(add)该集合

          3,通过Collections中的方法,从该集合中获取枚举

          4,SequenceInputStream中的构造方法进行封装

          5,创建输出流,确认源目的(abc.txt)    FileOutputStream   定义长度,byte数组,进行读写操作

          6,关闭各个流.

    package cn.wjd.sequence;
    
    import java.io.BufferedWriter;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.SequenceInputStream;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Enumeration;
    import java.util.Iterator;
    import java.util.Vector;
    
    public class SequenceDemo {
    
        /*需求:将a.txt,b.txt,c.txt中的数据合并到一个文件中去
         * 
         */
        public static void main(String[] args) throws IOException {
            ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
            al.add(new FileInputStream("a.txt"));
            al.add(new FileInputStream("b.txt"));
            al.add(new FileInputStream("c.txt"));
            Enumeration<FileInputStream> en = Collections.enumeration(al);
            SequenceInputStream sis = new SequenceInputStream(en);
            FileOutputStream fos = new FileOutputStream("abc.txt");
            byte[] buf = new byte[1024];
            int len = 0;
            while((len=sis.read(buf))!=-1){
                fos.write(buf, 0, len);
            }
            sis.close();
            fos.close();
        }
    
    }

    该类还有一个具体的应用,是文件的切割和文件的合拼,这个会在我下一个博客的由思路出代码的时候,再详细分析.

    java.util中的Properties类

    它是用来保存配置文件信息相关的类,表示了一个持久的属性集,该类中数据都是以字符串的形式出现的,并有key->value的关系,集合中的数据可以保存在流中,也可以从流中获取.下面先看API中几个常用的方法.

    123

    捕获捕获

    需求:修改某个配置文件的信息

    分析:1,将这个配置文件用File进行封装,创建Properties对象

          2,创建输入流  FileInputStream

          3,将流中的信息存储到配置文件 load

          4,修改配置文件信息   setProperty

          5,在修改好的配置文件写出输出流   FileOutputStream  store

    需求:将一些配置信息写入一个新的配置文件

         1,创建Properties对象,  设置配置信息 setProperty

         2,创建输出流,确定新配置文件的名称和位置   FileOutputStream

         3,将信息集合储存到配置文件,关流   store

    需要:输出某个配置文件的信息

    1,创建Properties对象,  设置配置信息 setProperty

    2,stringPropertyNames()得到一个set集合  得到的是配置文件中的key

    3,对set集合进行遍历,然后通过key---->value

    package cn.wjd.properties;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.Properties;
    import java.util.Set;
    
    public class PropertiesDemo {
        /*
         * Map -Hashtable -Properties Properties集合的特点: 1,该集合中的key和value都是字符串类型
         * 2,集合中的数据可以保存在流中,或者从流中获取 
         * 3,通常该集合操作以键值对存在的配置文件
         */
        public static void main(String[] args) throws IOException {
            // propertiesDemo();
            // propertiesMethod_2();
            // propertiesMethod_2();
            //propertiesMethod_3();
            //propertiesMethod_4();
            test();
        }
        // 对已有的配置文件中的信息进行修改
        /*
         * 读取这个文件,并将这个文件中的键值存储到集合中 在集合中对数据进行修改 再通过流将修改后的输出
         */
      private static void test() throws IOException {
          File file = new File("info.txt");
          Properties pro = new Properties();
          if(!file.exists()){
              file.createNewFile();
          }
          //创建一个输入流
          FileInputStream fis = new FileInputStream(file);
          //将流中的信息存储在配置文件
          pro.load(fis);
          //修改配置文件的数据
          pro.setProperty("zhangsan", "1");
          FileOutputStream fos = new FileOutputStream(file);
          pro.store(fos, "name+age");
          pro.list(System.out);
          fis.close();
          fos.close();
        }
    
    
        public static void propertiesMethod_4() throws IOException {
            Properties pro = new Properties();
            //集合中的数据来源与文件,注意:必须保证文件中的数据是键值对
            //需要使用到读取流
            FileInputStream fis = new FileInputStream("info.txt");
            pro.load(fis);
            pro.list(System.out);
            fis.close();
        }
    
    
        public static void propertiesMethod_3() throws IOException {
            // 建立properties集合
            Properties pro = new Properties();
            // 往集合中添加元素
            pro.setProperty("zhangsan", "21");
            pro.setProperty("zhangsan2", "22");
            pro.setProperty("zhangsan3", "23");
            // 将集合中的信息持久化的存储在文件中,需要关联输出流
            FileOutputStream fos = new FileOutputStream("info.txt");
            //将集合信息存储到配置文件中
            pro.store(fos, "name+age");
            fos.close();
        }
    
        /*
         * 演示Properties与流相结合的方法
         */
        public static void propertiesMethod_2() {
            // 建立properties集合
            Properties pro = new Properties();
            // 往集合中添加元素
            pro.setProperty("zhangsan", "21");
            pro.setProperty("zhangsan2", "22");
            pro.setProperty("zhangsan3", "23");
            pro.list(System.out);// 这个方法在程序调试的时候,使用的频率会比较高
        }
    
        public static void propertiesDemo() {
            // 建立properties集合
            Properties pro = new Properties();
            // 往集合中添加元素
            pro.setProperty("zhangsan", "21");
            pro.setProperty("zhangsan2", "22");
            pro.setProperty("zhangsan3", "23");
            // 修改集合中的元素
            pro.setProperty("zhangsan", "26");
            // 取出集合中的元素
            Set<String> set = pro.stringPropertyNames();
            for (String string : set) {
                String value = pro.getProperty(string);
                System.out.println("key:" + string + "  value:" + value);
            }
        }
    
    }
  • 相关阅读:
    CSPS_108
    TortoiseGit配置密钥的方法
    SLF4J和Logback和Log4j和Logging的区别与联系
    slf4j log4j logback关系详解和相关用法
    dubbo服务telnet命令的使用
    基于IDEA的JavaWeb开发环境搭建
    jdk8--十大新特性
    jdk8--collect总结
    字符串的排列
    调整数组顺序使奇数位于偶数前面
  • 原文地址:https://www.cnblogs.com/driverwjd/p/3828549.html
Copyright © 2011-2022 走看看