IO流

IO流

1. 介绍

  1. IO流,什么是IO:

    • I:Input O:Output 通过IO可以完成硬盘文件的读和写。
  2. IO流的分类:

    • 一种是按照流的方向进行分类:
      • 往内存中去:叫输入(Input),或者叫做读(Read)
      • 往内存中出来:叫输出(Output),或者叫做写(Write)
    • 另一种是按照读取数据方式不同进行分类:
      • 有的流是按照字节的方式读取数据,一次读取1个字节byte ,等同于一次读取8个二进制位。这种流是万能的,什么类型都可以读取。包括:文本文件,图片,声音文件,视频文件等。
      • 有的流是按照字符的方式读取数据,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片,声音,视频等文件。只能读取纯文本文件,(能用记事本打开)连word文件都无法读取。
  3. Java中的IO流都已经写好了,我们程序员不需要关心,我们最主要的还是掌握,java中所有的流都在:java.io.*;下。

  4. java IO流这块有四大家族(abstract class):

    java.io.InputStream:字节输入流

    java.io.OutputStream:字节输出流

    java.io.Reader:字符输入流

    java.io.Writer:字符输出流

    注意:

    • 在Java中只要 “类名” 以stream结尾的都是字节流。以“Reader/Writer”结尾的都是字符流。

    • 所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。流毕竟是一个管道,这是是内存和硬盘之间的通道,用完之后一定要关闭。不然会占用很多资源。

    • 所有的输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flush()方法。输出流在最终输出之后,一定记得flush()刷新一下。这个刷新表示将管道剩余未输出的数据强行输出完(清空管道)。如果没有flush()可能会导致丢失数据。

  5. java.io包下的需要掌握的流有16个:

文件专属:缓冲流专属:转化流:
java.io.FileInputStreamjava.io.BufferedInputStreamjava.io.InputStreamReader
java.io.FileOutputStreamjava.io.BufferedOutputStreamjava.io.OutputStreamWriter
java.io.FileReaderjava.io.BufferedReader
java.io.FileWriterjava.io.BufferedWriter
数据流专属:对象专属流:标准输出流
java.io.DataInputStreamjava.io.ObjectInputStreamjava.io.PrintWriter
java.io.DataOutputStreamjava.io.ObjectOutputStreamjava.io.PrintStream

2. FileInputStream:

1. 介绍:

  1. 文件字节输入流:万能的,任何类型的都文件可以采用这个流读。
  2. 字节的方式,完成输入的操作,完成读的操作(硬盘–>内存)

2. 代码演示:

  1. 初始代码:

    public class FileInputStreamTest02 {
        public static void main(String[] args) {
            //创建文件字节输入流对象
            FileInputStream fis=null;
            try {
                fis=new FileInputStream("D:\\IO流\\temp");
    /*            while (true){
                    int readData=fis.read(); //读到的是字节本身
                    if(readData==-1){
                        break;
                    }
                    System.out.println(readData);
                }*/
    
                //改造while循环
                int readData=0;  
                while ((readData=fis.read())!=-1){
                    System.out.println(readData);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //在finally语句块中确保流一定关闭
                //关闭流的前提是:流不是空
                if(fis!=null)//避免空指针异常
                {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    
  2. 上面代码出现的问题: 一次读取一个字节byte,这样内存和硬盘交互太频繁,基本上时间/资源都耗费在交互上面了。
    能不能一次读取多个字节呢?

  3. IDEA中的当前路径:

    • 相对路径:相对路径一定是从当前所在位置作为起点开始找!
    • IDEA默认的当前路径是哪里:工程project的根就是IDEA的默认当前路径。
    • 如:在这里插入图片描述
      在这里插入图片描述

    若在IO流项目中创建文件tempfile2,那路径的代码:

    fis=new FileInputStream("IO流/tempfile2");
    

3. 改进上面代码:

  1. int read(byte[]b):一次最多读取b.length个字节,减少硬盘和内存的交互,提高程序的执行效率。

  2. 通过String的构造器,将读取的字节,转化为字符串:String(byte[] bytes, int offset, int length)。

    代码展示:

     //开始读,采用byte[]数组,一次读取多个字节,最多读取 “数组.length” 个字节。
                byte[]bytes=new byte[4];//准备一个长度为4的数组,一次最多读取4个字节
                //readCount读到的字节数量(不是字节本身)
               int readCount= fis.read(bytes);
                System.out.println(readCount);  //第一次读到4个字节
                //将字节数组全部转化成字符串
                //System.out.println(new String(bytes)); //abcd
                //不应该全部转化,应该读取到多少个字节,转换多少个
                System.out.println(new String(bytes,0,readCount)); //abcd
    
                readCount=fis.read(bytes);
               System.out.println(readCount);//第二次只能读取到1个字节
               // System.out.println(new String(bytes)); //ebcd
                //不应该全部转化,应该读取到多少个字节,转换多少个
                System.out.println(new String(bytes,0,readCount)); //e
    
    
                 readCount=fis.read(bytes);//一个字节都没有读到返回-1
                System.out.println(readCount);//-1
    
    

4. 最终版代码(重要):

  1. 代码:

    /*
    * FileInputStream 最终版
    * */
    public class FileInputStreamTest04 {
        public static void main(String[] args) {
            FileInputStream fis=null;
            try {
                fis=new FileInputStream("IO流/src/com/ma/io/tempfile2");
                //准备一个byte[]数组
                byte[]bytes=new byte[4];
    /*            while (true){
                    int readCount=fis.read(bytes);
                  if (readCount==-1){
                      break;
                  }
                    //把byte数组转化成字符串,读到多少个转化多少个
                    System.out.print(new String(bytes,0,readCount));
                }*/
    
              //改进while循环
                int readCount=0;
                while ((readCount=fis.read(bytes))!=-1){
                    System.out.print(new String(bytes,0,readCount));
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fis!=null){
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

5. FilInputStream其他常用方法:

 int available()  :返回流当中剩余的没有读到的字节数量
 long skip(long n) :跳过几个字节不读 
1.available()方法:

注意:这种方式不太适合太大的文件,因为byte[]数组不能太大。

public class FileInputStreamTest05 {
    public static void main(String[] args) {
        FileInputStream fis=null;
        try {
            fis=new FileInputStream("tempfile");
            System.out.println("总字节数量:"+fis.available()); //6
            //读一个字节:
           // int readByte=fis.read();
            //还剩下可以读的字节文件:5
            //System.out.println("还剩下"+fis.available()+"个字节");//还剩下5个字节
            //available()方法的用处
            //这种方式不太适合太大的文件,因为byte[]数组不能太大。
            byte[]bytes=new byte[fis.available()];
            //不用循环了,直接读一次就可以了
            int readCount=fis.read(bytes); //6
            System.out.println(new String(bytes)); //abcdef
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fis!=null)
            {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2. skip()方法:
 //skip跳过几个字节不读取
fis.skip(3);
System.out.println(fis.read()); //100

3.FileOutputStream:

1. 介绍:

  1. 文件字节输出流,负责写,从内存到硬盘。
  2. 注意:写完之后,一定要刷新flush()和关闭流close()。

2.构造函数:

FileOutputStream(String name) :这种方式谨慎使用,这种方式会先将原文件清空,再重新写入。
FileOutputStream(String name, boolean append) :append为true时表示,再执行程序时,以追加的方式在文件末尾写入,不会清空原文件内容。
  1. 代码演示:

    /*
    * 文件字节输出流,负责写。
    * 从内存到硬盘
    * */
    public class FileOutputStreamTest01 {
        public static void main(String[] args) {
            FileOutputStream fos=null;
            try {
                //myfile文件不存在时候会自动新建
                //这种方式谨慎使用,这种方式会先将原文件清空,再重新写入
                //fos=new FileOutputStream("myfile");
                //以追加的方式在文件末尾写入,不会清空原文件内容
                fos=new FileOutputStream("myfile",true);
                //开始写
    
                byte[]bytes={97,98,99,100,101};
                //将byte数组全部写出
                fos.write(bytes);
    
                //将byte数组一部分写出
                fos.write(bytes,0,2);//再执行程序,在文件末尾加上ab
    
                //字符串
                String s="我是小马呀";
                //将字符串转化为byte数组
                byte[]bytes1=s.getBytes();
                fos.write(bytes1);
    
                //写完之后,最后一定到刷新
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(fos!=null){
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
    
            }
        }
    }
    
    

3. 文件复制:

  1. 原理图:

    在这里插入图片描述

  2. 代码:

    /*
    * 使用FileInputStream+FileOutputStream完成文件的拷贝。
    * 拷贝的过程应该是一边读,一边写
    * 使用以上的字节流拷贝文件的时候,文件的类型随意。
    * */
    public class Copy01 {
        public static void main(String[] args) {
            FileInputStream fis=null;
            FileOutputStream fos=null;
            try {
                //创建一个输入流对象
                fis=new FileInputStream("D:\\javascript-基础\\javascript\\js-date封装时间.txt");
                //创建一个输出流对象
                fos=new FileOutputStream("E:\\js-date封装时间.txt");
    
                //最核心的,一边读一边写
                byte[]bytes=new byte[1024 * 1024];//1MB (一次最多拷贝1MB)
    
                int readCount=0;
                while ((readCount=fis.read(bytes))!=-1){
                    fos.write(bytes,0,readCount);
                }
                //刷新,输出流最后要刷新
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //分开try 不要一起try
                //一起try的时候,其中一个出现异常,可能会影响到另一个流的关闭
                if(fos!=null){
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(fis!=null){
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
    }
    

4. FileReader:

  1. FileReader:文件字符输入流,只能读取普通文本。读取文本内容时比较方便。

  2. 代码:

    public class FileReaderTest {
        public static void main(String[] args) {
            FileReader fr=null;
            try {
                //创建文件字符流
                fr=new FileReader("tempfile");
    /*            //准备一个char数组
                char[]chars=new char[4];
                //往char数组中读
                fr.read(chars);
                for (char a:
                     chars) {
                    System.out.println(a);  //按字符的方式读取4个字符  我  是  小 马
                }*/
                //开始读
               char[]chars=new char[4];//一次读取4个字符
                int readCount=0;
                while((readCount=fr.read(chars))!=-1){
                    System.out.print(new String(chars,0,readCount));//全部读出
                }
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(fr!=null){
                    try {
                        fr.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    

5. FileWriter

  1. FileWriter:文件字符输出流,写。只能输出普通文本。

  2. 代码演示:

    public class FileWriterTest {
        public static void main(String[] args) {
            FileWriter fw=null;
            try {
                //创建文件字符输出流对象
                fw=new FileWriter("tempfile");
                char[]chars={'哈','a','b','c','哈'};
                fw.write(chars);
    
                //写出一个换行符
                fw.write("\n");
                fw.write(chars,1,3);
                fw.write("\n");
                fw.write("小马同学");
                //刷新`
                fw.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(fw!=null){
                    try {
                        fw.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    

1. 复制普通文本文件:

  1. 注意:如果使用FileReader和FileWriter拷贝文件,只能拷贝普通文本文件。

    /*
    * 普通文本文件复制
    * */
    public class Copy02 {
        public static void main(String[] args) {
            FileReader fr=null;
            FileWriter fw=null;
            try {
                fr=new FileReader("D:\\javascript-基础\\javascript\\js-date封装时间.txt");
                fw=new FileWriter("E:\\js-date封装时间1.txt");
                char[]chars=new char[1024*512];//1MB
                int readCount=0;
                while ((readCount=fr.read(chars))!=-1){
                    fw.write(chars,0,readCount);
                }
                fw.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    

6. 带缓冲区的字符流:

1.BufferedReader:

  1. 介绍:BufferedReader 带有缓冲区的字符输入流。使用这种流的时候不需要自定义char数组,或者说不需要自定义byte数组。自带缓冲。

  2. 构造方法:

    BufferedReader(Reader in); // 创建一个使用默认大小输入缓冲区的缓冲字符输入流。
    
  3. 当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流外部负责包装的流叫做:包装流或处理流。如:

FileReader fr= new FileReader("tempfile");
BufferedReader br=new BufferedReader(fr);

上面代码中,FileReader就是一个节点流。BufferedReader就是包装流/处理流。

对于包装流来说,只需要关闭最外层的包装流就行。里面的节点流会自动关闭。

  1. 常用方法:

     String readLine() //读取一行 但不带换行符
    
  2. 具体代码演示:

    /*
    BufferedReader 带有缓冲区的字符输入流。
    使用这种流的时候不需要自定义char数组,或者说不需要自定义byte数组。自带缓冲。
    * */
    public class BufferedReaderTest01 {
        public static void main(String[] args) {
            FileReader fr= null;
            BufferedReader br=null;
            try {
    
                fr = new FileReader("tempfile");
                //当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流。
                //外部负责包装的流,叫做:包装流,还有一个名字:处理流。
                //像当前这个程序来说:FileReader就是一个节点流。BufferedReader就是包装流/处理流。
               br=new BufferedReader(fr);
    /*           //读一行 第一行
                String firLine=br.readLine();
                System.out.println(firLine);
    
    
                //第二行
                String secondLine=br.readLine();
                System.out.println(secondLine);
    
                //第三行
                String thirdLine=br.readLine();
                System.out.println(thirdLine);*/
    
                //br.readLine()方法读取一个文本行,但不带换行符
                String s=null;
                while ((s=br.readLine())!=null){
                    System.out.println(s);
                }
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (br!=null){
                    try {
                        //对于包装流来说,只需要关闭最外层的流就行。里面的节点流会自动关闭。
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    
    

2.InputStreamReader(转换流):

  1. InputStreamReader:转化流,可以将字节流转为字符流。

                //字节流
                FileInputStream fis=new FileInputStream("tempfile");
                //通过转换流:InputStreamReader 将字节流转换成字符流
                //fis是节点流 isr是包装流
                InputStreamReader isr=new InputStreamReader(fis);
                //这个只能传一个字符流。不能转字节流
                //isr是节点流,br是包装流。
                BufferedReader br=new BufferedReader(isr);
    
  2. 合并写法:

    BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("tempfile")));
    
  3. 具体代码演示:

    public class BufferedReaderTest02 {
        public static void main(String[] args) {
            FileInputStream fis=null;
            BufferedReader br=null;
            try {
    /*            //字节流
                fis=new FileInputStream("tempfile");
                //通过转换流:InputStreamReader 将字节流转换成字符流
                //fis是节点流 isr是包装流
                InputStreamReader isr=new InputStreamReader(fis);
                //这个只能传一个字符流。不能转字节流
                //isr是节点流,br是包装流。
                br=new BufferedReader(isr);*/
    
            br=new BufferedReader(new InputStreamReader(new FileInputStream("tempfile")));
    
                String s=null;
                while ((s=br.readLine())!=null){
                    System.out.println(s);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(br!=null){
                    try {
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    
    

3.BufferedWriter:

  1. BufferedWriter:带有缓冲的字符输出流。

  2. OutputStreamWriter:输出转化流

  3. 代码演示:

    public class BufferedWriterTest {
        public static void main(String[] args) {
            BufferedWriter bw=null;
            try {
              //  bw=new BufferedWriter(new FileWriter("tempfile"));
                bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("tempfile")));
                bw.write("小马同学");
                bw.write("\n");
                bw.write("小赵同学");
                bw.write("\n");
                bw.write("一起");
                //刷新
                bw.flush();
    
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(bw!=null)
                {
                    try {
                        //关闭流
                        bw.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    

7. 数据流:

1. DataOutputStream:

  1. 介绍:java.io.DataOutputStream是一个数据专属的流。这个流可以将数据连同数据的类型一并写入文件
    注意:这个文件不是普通文本文档(这个文件使用记事本打不开)。

  2. 代码演示:

    /*
    java.io.DataOutputStream是一个数据专属的流。
    这个流可以将数据连同数据的类型一并写入文件
    注意:这个文件不是普通文本文档(这个文件使用记事本打不开)
    *
    * */
    public class DataOutputStreamTest {
        public static void main(String[] args) {
            DataOutputStream dos=null;
            try {
                //创建数据专属的字节输出流
                dos=new DataOutputStream(new FileOutputStream("data"));
                //创建数据
                byte b=100;
                short s=200;
                int i=300;
                long l=400L;
                float f=3.0F;
                double d=3.14;
                boolean sex=false;
                char c='a';
    
                //写  把数据以及数据的类型一并写入到文件当中
                dos.writeByte(b);
                dos.writeShort(s);
                dos.writeInt(i);
                dos.writeLong(l);
                dos.writeFloat(f);
                dos.writeDouble(d);
                dos.writeBoolean(sex);
                dos.writeChar(c);
                
                //刷新
                dos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(dos!=null){
                    try {
                        dos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    

2. DataInputStream:

  1. 介绍: DataInputStream:数据字节输入流。DataOutputStream写的文件,只能使用DataInputStream去读,并且读的时候,你需要提前知道写入的顺序。读的顺序需要和写的顺序一致,才能正常取出数据

  2. 代码演示:

    /*
     DataInputStream:数据字节输入流
     DataOutputStream写的文件,只能使用DataInputStream去读,并且读的时候,你需要提前知道写入的
     顺序。读的顺序需要和写的顺序一致,才能正常取出数据。
    * */
    public class DataInputStreamTest01 {
        public static void main(String[] args) {
            DataInputStream dis=null;
            try {
                dis=new DataInputStream(new FileInputStream("data"));
                //开始读
                byte b=dis.readByte();
                short s=dis.readShort();
                int i=dis.readInt();
                long l=dis.readLong();
                float f=dis.readFloat();
                double d=dis.readDouble();
                boolean sex=dis.readBoolean();
                char c=dis.readChar();
    
                System.out.println(b);
                System.out.println(s);
                System.out.println(i);
                System.out.println(l);
                System.out.println(f);
                System.out.println(d);
                System.out.println(sex);
                System.out.println(c);
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(dis!=null){
                    try {
                        dis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    

8. 标准输出流:

1. PrintStream:

  1. 介绍:java.io.PrintStream:标准的字节输出流,默认输出到控制台。标准输出流,不需要手动close()关闭

  2. 可以改变标准输出流的输出方向。如:使标准输出流不再指向控制台,指向’log’文件:System.out()

    // 标准输出流不再指向控制台,指向'log'文件。
    PrintStream pss=new PrintStream(new FileOutputStream("log"));
    //修改输出方向,将输出方向修改到‘log’文件。
    System.setOut(pss);
    
  3. 具体代码演示:

    public class PrintStreamTest {
        public static void main(String[] args) {
            //联合起来写:
            System.out.println("xiaoma");
    
            //分开写:
            PrintStream ps=System.out;
            ps.println("xiaozhao");
    
            //可以改变标准输出流的输出方向
            try {
    
                // 标准输出流不再指向控制台,指向'log'文件。
                 PrintStream pss=new PrintStream(new FileOutputStream("log"));
                //修改输出方向,将输出方向修改到‘log’文件。
                System.setOut(pss);
                //再输出
                System.out.println("小马同学"); //输出到文件
                System.out.println("小赵同学");
                System.out.println("一起玩哈");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
    
        }
    }
    
1. 编写日志功能:
/*
* 日志工具
* */
public class Logger {
    public static void log(String msg){
        /*
        * 记录日志的方法
        * */
        try {
            //指向一个日志文件
            PrintStream pss=new PrintStream(new FileOutputStream("logFile",true));
            //改变输出方向
            System.setOut(pss);
            //日期当前时间
            Date nowTime=new Date();
            //格式化当前时间
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            //转换为字符串
            String strTime=sdf.format(nowTime);

            System.out.println(strTime+":"+msg);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}


/*
* 日志测试类
* */
public class LogTest {
    public static void main(String[] args) {
        //测试工具类是否好用
        Logger.log("调用System类的gc()方法,建议启动垃圾回收");
        Logger.log("调用了UserService的doSome()方法");
        Logger.log("用户尝试登录,验证失败");
    }
}

9. File类:

1.File类的理解:

  1. File类和四大家族没有关系,所有File类不能完成文件的读和写。
  2. File对象代表:**文件和目录路径名的抽象表示形式。**一个File对象有可能对应的是目录,也可能是文件。File只是一个路径名的抽象表示形式。

2. File类的常用方法:

 boolean exists(); //判断文件或目录是否存在;
 boolean createNewFile(); //当指定路径文件不存在时,则以文件的形式创建出来
 boolean mkdir(); //创建此抽象路径名指定的目录。
 boolean mkdirs();//创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。
 String getParent();//获取文件的父路径
 File getParentFile() ;//获取文件的父路径,返回的是一个file对象
 String getAbsolutePath(); //获取绝对路径
 String getName() ;//获取文件或目录的名称
 boolean isDirectory() ;//判断是否是一个目录
 boolean isFile()  ;//判断是否是一个文件
 long lastModified();//获取文件最后一次修改时间
 long length();//获取文件长度
 boolean renameTo(File dest);//重命名
 File[] listFiles() ;//获取当前目录下所有的子文件

3. 目录拷贝(重点):

  1. 代码:
/*
* 拷贝目录
* */
public class CopyAll {
    public static void main(String[] args) {
        //拷贝源
        File srcFile=new File("D:\\Data");
        //拷贝目标
        File destFile=new File("E:\\");
        //调用方法拷贝
        copyDir(srcFile,destFile);
    }

    /**
     * 拷贝目录
     * @param srcFile  拷贝源
     * @param destFile 拷贝目标
     */
    private static void copyDir(File srcFile, File destFile) {
        if (srcFile.isFile()){
            //srcFile如果是一个文件的话递归结束
            //是文件的时候需要拷贝
            //...一边读一边写
            FileInputStream fis=null;
            FileOutputStream fos=null;
            try {
                //读这个文件
                fis=new FileInputStream(srcFile);
                //写到这个文件中
                String path=(destFile.getAbsolutePath().endsWith("\\")?destFile.getAbsolutePath():destFile.getAbsolutePath()+"\\")+srcFile.getAbsolutePath().substring(3);
                //System.out.println(path);
                fos=new FileOutputStream(path);
                //一边读一边写
                byte[]bytes=new byte[1024*1024]; //一次复制1MB
                int readCount=0;
                while ((readCount=fis.read(bytes))!=-1){
                    fos.write(bytes,0,readCount);
                }
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(fis!=null){
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fos!=null){
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return;
        }
        //获取源下面的子目录
        File[]files=srcFile.listFiles();
        for (File file:
             files) {
            //获取所有文件的(包括目录和文件)的绝对路径
            //System.out.println(file.getAbsolutePath());
            if (file.isDirectory()){
                //新建对应目录
                //1.获取拷贝源的绝对路径
                String srcDir=file.getAbsolutePath();
                //System.out.println(srcDir.substring(3));

                //字符串拼接目标目录的路径:
                String destDir=(destFile.getAbsolutePath().endsWith("\\")?destFile.getAbsolutePath():destFile.getAbsolutePath()+"\\")+srcDir.substring(3);
                //System.out.println(destDir);
                File newFile=new File(destDir);
                if (!newFile.exists()){
                    newFile.mkdirs();
                }
            }
            //file有可能是文件也有可能是目录
            //递归调用
            copyDir(file,destFile);
        }
    }
}

10:序列化和反序列化:

1. 介绍:

  1. 序列化:Serialize 将java对象存储到文件中,将java对象的状态保存下来的过程。 (ObjectOutputStream)

  2. 反序列化:DeSerialize 将硬盘上的数据重新恢复到内存当中,恢复成java对象 (ObjectInputStream)

  3. 注意:参与序列化和反序列化的对象,必须实现Serializable接口

  4. 通过源代码发现,Serializable接口只是一个标志接口:

    public interface Serializable {
    }
    
  5. 这个Serializable接口起到一个标志的作用,java虚拟机看到这个类实现这个接口,可能会对这个类进行特殊待遇。会为该类自动生成一个序列化版本号。

2. 代码演示:

public class Student implements Serializable {
    private int no;
    private String name;

    public Student() {
    }

    public Student(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}




public class ObjectOutputStreamTest01 {
    public static void main(String[] args) {

        //创建java对象
        Student s=new Student(111,"xiaoma");
        ObjectOutputStream oos=null;
        //序列化
        try {
            oos=new ObjectOutputStream(new FileOutputStream("students"));
            //序列化对象
            oos.writeObject(s);
            //刷新
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(oos!=null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

3. 反序列化代码:

public class ObjectInputStreamTest01 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("students"));
        //开始反序列化,读
        Object obj=ois.readObject();
        //反序列化回来是一个学生对象,所以会调用学生对象的toString方法
        System.out.println(obj);  //Student{no=111, name='xiaoma'}
        ois.close();
    }
}

4. 序列化多个对象:

  1. 将对象放到集合中,序列化集合。

    序列化集合代码:

    public class ObjectOutputStreamTest02 {
        public static void main(String[] args) throws IOException {
            List<User> userList=new ArrayList<>();
            userList.add(new User(1,"xiaoma"));
            userList.add(new User(2,"xiaozhao"));
            userList.add(new User(3,"xiaochen"));
            ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("user"));
            //序列化集合,这个集合中放了很多其他对象
            oos.writeObject(userList);
            oos.flush();
            oos.close();
        }
    
    }
    
  2. 反序列化集合:

    /*
    * 反序列化集合
    * */
    public class ObjectInputStreamTest02 {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            ObjectInputStream ois=new ObjectInputStream(new FileInputStream("user"));
            Object obj=ois.readObject();
            System.out.println(obj);
            ois.close();
        }
    }
    

5. transient关键字:

  1. transient:表示游离的,不参与序列化。

如:

    //transient:表示游离的,不参与序列化
    private transient String name; //name不参与序列化操作

6. 序列化版本号:

  1. java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号。

  2. java语言中是采用什么机制来区分类的:

    • 首先通过类名进行比对,如果类名不一样,肯定不是同一个类。
    • 如果类名一样,再靠序列化版本号进行区分。
  3. 自动生成序列化版本号的缺陷:一旦代码确定之后,不能进行后续的修改,因为只有修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类,这样就不好了。

  4. 结论:凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号,以后这个类即使修改了,但是版本号不变,java虚拟机会认为是同一个类。

  5. 建议将序列化版本号手动的写出来,不建议自动生成:

    private static final long serialVersionUID = 8683452581122892189L;
    

11.IO和Properties联合使用:

1.介绍:

  1. 非常好的一个设计理念:

    以后经常改变的数据,可以单独写到一个文件中,使用程序动态读取。将来只需要修改这个文件的内容,java代码不需要改动,不需要编译,服务器也不需要重启。就可以拿到动态的信息。类似这样的文件被称为配置文件,并且配置文件中的内容格式是:key=value时,我们把这种文件叫做属性配置文件。

  2. java规范中有要求:属性配置文件建议以:.properties结尾,但这不是必须的。其中Properties是专门存放属性配置文件内容的一个类。

  3. 在属性配置文件中以 “ # ”注释,key重复的话,value会自动覆盖。

2.代码演示:

  1. 在项目中新建一个useinfo文件:

    username=root
    password=123
    
  2. 新建一个类:IOPropertiesTest

    public class IOPropertiesTest {
        public static void main(String[] args) throws IOException {
            /*
            * Properties是一个Map集合,key和value都是String类型。
            * 想将useinfo文件中的数据加载到Properties对象当中
            *
            * */
    
            //新建一个输入流对象
            FileReader reader=new FileReader("IO流/useinfo");
    
            //新建一个Map集合
            Properties pro=new Properties();
    
            //调用Properties对象的load方法将文件中的数据加载到Map集合中。
            pro.load(reader); //文件中的数据顺着管道,加载到Map集合中,其中=左边是key 右边是value
    
            //通过key,获取value
            String username=pro.getProperty("username");
            System.out.println(username);
        }
    }
    
    

1.介绍:

  1. 非常好的一个设计理念:

    以后经常改变的数据,可以单独写到一个文件中,使用程序动态读取。将来只需要修改这个文件的内容,java代码不需要改动,不需要编译,服务器也不需要重启。就可以拿到动态的信息。类似这样的文件被称为配置文件,并且配置文件中的内容格式是:key=value时,我们把这种文件叫做属性配置文件。

  2. java规范中有要求:属性配置文件建议以:.properties结尾,但这不是必须的。其中Properties是专门存放属性配置文件内容的一个类。

  3. 在属性配置文件中以 “ # ”注释,key重复的话,value会自动覆盖。

2.代码演示:

  1. 在项目中新建一个useinfo文件:

    username=root
    password=123
    
  2. 新建一个类:IOPropertiesTest

    public class IOPropertiesTest {
        public static void main(String[] args) throws IOException {
            /*
            * Properties是一个Map集合,key和value都是String类型。
            * 想将useinfo文件中的数据加载到Properties对象当中
            *
            * */
    
            //新建一个输入流对象
            FileReader reader=new FileReader("IO流/useinfo");
    
            //新建一个Map集合
            Properties pro=new Properties();
    
            //调用Properties对象的load方法将文件中的数据加载到Map集合中。
            pro.load(reader); //文件中的数据顺着管道,加载到Map集合中,其中=左边是key 右边是value
    
            //通过key,获取value
            String username=pro.getProperty("username");
            System.out.println(username);
        }
    }
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值