java中的io流

文章目录

      • 1. IO流,什么是IO?
      • 2.IO流的分类?
      • 3.IO流都在java.io.*包下
      • 4.java IO流有四个家族
      • 5.java.io包下需要掌握的流有16个
      • 6.FileInputStream的1个字节读入法
      • 7.FileInputStream的byte[]读入法
      • 8.FileInputStream的其他方法
      • 9.FileOutputStream用法
      • 10.文件复制
      • 11.FileReader用法
      • 12.复制普通文本文件(Reader/Writer)
      • 13.带有缓冲区的字符输入流
      • 14.包装流和节点流(即转换流)
      • 15.带有缓冲区的字符输出流
      • 16.数据流
      • 17.标准输出流
      • 18.File类的理解以及常用方法
      • 19.目录拷贝
      • 20.序列化和反序列化
      • 21.序列化多个对象
      • 22.transient关键字
      • 23.序列化版本号
      • 24.IO和Properties的联合使用

1. IO流,什么是IO?

I : Input
O: Output
通过IO可以完成硬盘文件的读和写。

2.IO流的分类?

有多种分类方式:
1)一种方式是按照流的方向进行分类:
以内存作为参照物,
往内存中去,叫做输入。或者叫做读(Read)。
从内存中出来,叫做输出。或者叫做写(Write)。

2)另一种方式是按照读取数据方式不同进行分类:
有的流是按照字节的方式读取数据,一次读取1个字节byte等同于一次读取8个二进制位。
这种流是万能的,什么类型的文件都可以读取。包括文本文件、图片、声音文件、视频文件等等…
假设文件file1.txt,采用字符流的话是这样读的:
a中国bc张三fe
第一次读:1个字节,正好读到’a’
第二次读:1个字节,正好读到’中’字符的一半
第三次都:1个字节,正好读到’中’字符的另外一半

有的流是按照字符的方式读取数据,一次读取一个字符,这种流是为了方便读取普通文本文件存在的。这种流不能读取:图片、声音、视频等文件,只能读取纯文本文件,连word文件都无法读取。
假设文件file1.txt,采用字符流的话是这样读的:
a中国bc张三fe
第一次读: 'a’字符('a’字符在windows系统中占用1个字节)
第二次读: '中’字符('中’字符在windows系统中占用2个字节)

综上所述: 流的分类
输入流、输出流(按照流的方向进行分类)
字节流、字符流(按照读取的方式进行分类)

3.IO流都在java.io.*包下

java中的IO流都已经写好了,我们程序员不需要关心,我们最主要还是掌握,在java中已经提供了哪些流,每个流的特点是什么,每个流对象上的常用方法有哪些?
java中所有的流都是在: java.io.*下。

java中主要还是研究:
怎么new流对象。
调用流对象的哪个方法是读,哪个方法是写。

4.java IO流有四个家族

java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流

java.io.Reader 字符输入流
java.io.Writer 字符输出流

注意: 在java中只要"类名"以Stream结尾的都是字节流。以"Reader/Writer"结尾的都是字符流。

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

文件专属:
java.io.FileInputStream
java.io.FileOutputStream
java.io.FileReader
java.io.FileWriter

转换流:(将字节流转换成字符流)
java.io.InputStreamReader
java.io.OutputStreamWriter

缓冲流专属:
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream

数据流专属:
java.io.DateInputStream
java.io.DateOutputStream

标准输出流:
java.io.printWriter
java.io.printStream

对象专属流:
java.io.ObjectInputStream
java.io.ObjectOutputStream

6.FileInputStream的1个字节读入法

package com.jmpower.javase.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
java.io.FileInputStream:
    1.文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。
    2.字节的方式,完成输入的操作,完成读的操作。(硬盘-->内存)
 */
public class FileInputStreamTest01 {
    public static void main(String[] args) {
        FileInputStream fis=null;
        try {
            //创建字节输入流对象
            //文件路径:C:\Users\Jm\Desktop\Java\doSome.txt
            //文件内容为:abcedf
            //FileInputStream fis=new FileInputStream("C:\\Users\\Jm\\Desktop\\Java\\doSome.txt");
            //都采用了: 绝对路径
            //将"\\"写成"/"也是可以的
            fis=new FileInputStream("C:/Users/Jm/Desktop/Java/doSome.txt");

            int readDate=fis.read();//这个方法的返回值是读到字节本身
            System.out.println(readDate);// 97

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //在finally语句块中确保流一定要关闭
            if (fis != null) {
                //关闭流的前提是:流不是空。流是null的时候没必要关闭。
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
}

7.FileInputStream的byte[]读入法

package com.jmpower.javase.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
int read(byte[] b)
    一次最多读取b.length个字节。
    减少硬盘和内存之间的交互,提高程序的执行效率。
    往byte[]数组当中读。
 */
public class FileInputStreamTest02 {
    public static void main(String[] args) {
        FileInputStream fis=null;
        try {
            //相对路径的话呢?相对路径一定是从当前所在的位置作为起点开始找!
            //IDEA默认的当前路径是工程Object的根就是IDEA的默认当前路径。
            //文件内容:abcdef
            fis=new FileInputStream("text02.txt");

            byte[] bytes=new byte[4];//准备一个4个长度的byte数组,一次最多读取4个字节。
            //这个方法的返回值是,读取到的字节数量。(不是字节本身)
            //int readCount=fis.read(bytes);
            //System.out.println(readCount);// 第一次读到4个字节

            //将字节数组全部转换成字符串
            //System.out.println(new String(bytes));

            //不应该全部转换,应该读取了多少个字节,转换多少个。
            //System.out.println(new String(bytes,0,readCount));// abcd

            //最终版本,读取文件
            int readCount=0;
            while((readCount = fis.read(bytes))!=-1)
            {
                System.out.print(new String(bytes,0,readCount));
            }

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
}

8.FileInputStream的其他方法

1)int available(): 返回流当中剩余的没有读取到的字节的数量

package com.jmpower.javase.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest03 {
    public static void main(String[] args) {
        FileInputStream fis=null;
        try {
            fis=new FileInputStream("test03");
            System.out.println("总字节数量:"+fis.available());// 41
            //读一个字节
            //int readDate=fis.read();
            //还剩下的可读字节为40
            //System.out.println("还剩下的可读字节的数量:"+fis.available());// 40
            //这个方法有什么用?
            byte[] bytes=new byte[fis.available()];
            //不需要循环了!
            //直接读一次就行了。
            int readCount=fis.read(bytes);// 6
            System.out.println(new String(bytes)); // abcdef
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

2)long stip(long n): 跳过几个字节不读

package com.jmpower.javase.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest04 {
    public static void main(String[] args) {
        FileInputStream fis=null;
        try {
            fis=new FileInputStream("text02.txt");
            //a   b  c  d   e   f
            //97 98 99 100 101 102
            System.out.println(fis.read());// 97
            fis.skip(3);//跳过三个字节
            System.out.println(fis.read());// 101
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

9.FileOutputStream用法

package com.jmpower.javase.io;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest01 {
    public static void main(String[] args) {
        FileOutputStream fos=null;
        try {
            //file01文件不存在会自动新建!
            //这种方式慎用,这种方式会先将文件清空,然后重新写入。
            //fos=new FileOutputStream("file01");

            //以追加的方式在文件末尾写入。不会清空原文件的内容。
            fos=new FileOutputStream("text02.txt",true);
            //开始写
            byte[] bytes={97,98,99,100};
            //将byte数组全部写出!
            fos.write(bytes);// abcd
            //将bute数组的一部分写出!
            fos.write(bytes,0,2);// ab

            //字符串
            String s="我是中国人!";
            //将字符串转换成数组
            byte[] bs=s.getBytes();
            //写
            fos.write(bs);

            //写完之后一定要刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
}

10.文件复制

package com.jmpower.javase.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/*
使用FileInputStream + FileOutputStream完成文件的拷贝。
拷贝的过程一定是一边读,一边写。
使用以上的字节流拷贝文件的时候,文件类型随意,万能的。什么样的文件都可以拷贝。
 */
public class Copy01 {
    public static void main(String[] args) {
        FileInputStream fis=null;
        FileOutputStream fos=null;
        try {
            //创建一个输入流对象
            fis=new FileInputStream("C:\\Users\\Jm\\Pictures\\自建\\十三届蓝桥杯省一.jpg");
            //创建一个输出流对象
            fos=new FileOutputStream("C:\\Users\\Jm\\Desktop\\Java\\十三届蓝桥杯省一.jpg");

            //最核心的: 一边读,一边写
            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) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //分开try,不要一起try
            //一起try的时候,其中一个出现异常,可能会影响到另一个流的关闭
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

11.FileReader用法

package com.jmpower.javase.io;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/*
FileReader:
    读取文本内容时,比较方便,快捷。
    一次读取一个字符。
 */
public class FileReaderTest {
    public static void main(String[] args) {
        FileReader reader=null;
        try {
            //创建文件字符输入流
            reader=new FileReader("text02.txt");
            //开始读
            char[] chars=new char[4];//一次读取4个字符(1个字符2个字节)
            int readCount=0;
            while((readCount=reader.read(chars))!=-1)
            {
                System.out.print(new String(chars,0,readCount));
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
}

12.复制普通文本文件(Reader/Writer)

package com.jmpower.javase.io;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Copy02 {
    public static void main(String[] args) {
        FileReader in=null;
        FileWriter out=null;
        try {
            //读
            in=new FileReader("src/com/jmpower/javase/io/FileInputStreamTest02.java");
            //写
            out=new FileWriter("reader");

            //一边读一边写
            char[] chars=new char[1024*512];//1MB
            int readCount=0;
            while((readCount=in.read(chars))!=-1)
            {
                out.write(new String(chars,0,readCount));
            }

            //刷新
            out.flush();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //关闭流
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

13.带有缓冲区的字符输入流

package com.jmpower.javase.io;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/*
BufferedReader:
    带有缓冲区的字符输入流。
    使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组。自带缓冲。
 */
public class BufferedReaderTest01 {
    public static void main(String[] args) {
        FileReader reader=null;
        BufferedReader br=null;
        try {
            reader=new FileReader("src/com/jmpower/javase/io/Copy02.java");
            //当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做: 节点流。
            //外部负责包装的这个流,叫做: 包装流,还有一个名字叫做: 处理流。
            //像当前这个程序来说: FileReader叫做一个节点流。BufferedReader就是包装流/处理流。
            br=new BufferedReader(reader);
            /*//第一行
            String firstLine=br.readLine();
            System.out.println(firstLine);
            //第二行
            String secondLine=br.readLine();
            System.out.println(secondLine);*/

            //br.readLine()方法读取一个文本行,但不带换行符。
            String line=null;
            while((line=br.readLine())!=null)
            {
                System.out.println(line);
            }

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //关闭流
            //对于包装流来说,只需要关闭最外层流就行,里面的节点流会自动关闭。(可以看源代码)
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

14.包装流和节点流(即转换流)

package com.jmpower.javase.io;

import java.io.*;

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

        BufferedReader br=null;
        try {
            //字节流
            FileInputStream in=new FileInputStream("src/com/jmpower/javase/io/Copy02.java");

            //通过转换流转换(InputStreamReader将字节流转换成字符流)
            //in是节点流。reader是包装流。
            InputStreamReader reader=new InputStreamReader(in);

            //这个构造方法只能传一个字符流。不能传字节流。
            //reader是节点流。br是包装流。
            br=new BufferedReader(reader);

            String line=null;
            while((line=br.readLine())!=null)
            {
                System.out.println(line);
            }

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //关闭最外层
            try {
                br.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

15.带有缓冲区的字符输出流

package com.jmpower.javase.io;

import java.io.*;
/*
BufferedWriter: 带有缓冲的字符输出流
OutputStreamWriter: 转换流
 */
public class BufferedWriterTest01 {
    public static void main(String[] args) {
        BufferedWriter out=null;
        try {
            //带有缓冲的字符输出流
            //out=new BufferedWriter(new FileWriter("bo"));
            out=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("doSome"/*,true*/)));
            //开始写
            out.write("123");
            out.write("\n");
            out.write("456");
            //刷新(输出流记得刷新)
            out.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

16.数据流

1)写

package com.jmpower.javase.io;

import java.io.*;

/*
java.io.DataOutputStream:数据专属的流
这个流可以将数据连通数据的类型一并写入文件。
注意: 这个文件不是普通文本文档。(这个文件使用记事本打不开)
 */
public class DataOutputStreamTest01 {
    public static void main(String[] args) {

        DataOutputStream dos=null;
        try {
            //创建数据专属的字节输出流
            dos=new DataOutputStream(new FileOutputStream("data"));
            //写数据
            byte b=100;
            short s=400;
            int i=200;
            long l=300;
            float f=3.0f;
            double d=3.14;
            boolean sex=false;
            char c='0';
            //写
            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) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (dos != null) {
                try {
                    dos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

2)读

package com.jmpower.javase.io;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
java.io.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) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (dis != null) {
                try {
                    dis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

17.标准输出流

package com.jmpower.javase.io;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

/*
java.io.PrintStream: 标准的字节输出流。默认输出到控制台。
 */
public class PrintStreamTest {
    public static void main(String[] args) {
        //联合起来写
        System.out.println("hello world!");

        //分开写
        java.io.PrintStream ps=System.out;
        ps.println("hello zhangsan");
        ps.println("hello lisi");
        ps.println("hello wangwu");

        //标准输出流不需要手动colse()关闭。
        //可以改变标准输出流的输出方向吗?可以
        
        try {
            //标准输出流不再指向控制台,指向“log”文件
            PrintStream printStream=new PrintStream(new FileOutputStream("log"));
            //修改输出方向,将输出方向修改到"log"文件
            System.setOut(printStream);
            //再输出,输入到了"log"文件中
            System.out.println("hello lisi");
            System.out.println("hello zhangsan");
            System.out.println("hello wangwu");
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

18.File类的理解以及常用方法

1)
boolean exists() 测试此抽象路径名表示的文件或目录是否存在。
boolean createNewFile() 当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
boolean mkdir() 创建由此抽象路径名命名的目录。
boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。
String getParent() 返回此抽象路径名的父 null的路径名字符串,如果此路径名未命名为父目录,则返回null。
File getParentFile() 返回此抽象路径名的父,或抽象路径名 null如果此路径名没有指定父目录。
String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。
String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。

package com.jmpower.javase.io;

import java.io.File;
import java.io.IOException;

/*
File
    1.File类和四大家族没有关系,所以File类不能完成文件的读和写
    2.File对象代表什么?
        文件和目录路径名的抽象表示方式。
        C:\Users\Jm\Desktop\Java 这是一个File对象
        C:\Users\Jm\Desktop\Java\学习笔记(Java) 这也是一个File对象
        一个File对象有可能对应的目录,也可能是文件
        File只是一个路径名的抽象表达形式
    3.需要掌握File类中常用的方法
        boolean exists() 测试此抽象路径名表示的文件或目录是否存在。
        boolean createNewFile() 当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
        boolean mkdir() 创建由此抽象路径名命名的目录。
        boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。
        String getParent() 返回此抽象路径名的父 null的路径名字符串,如果此路径名未命名为父目录,则返回null。
        File getParentFile() 返回此抽象路径名的父,或抽象路径名 null如果此路径名没有指定父目录。
        String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。
        String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。  
 */
public class FileTest01 {
    public static void main(String[] args) {
        //创建一个File对象
        File f1=new File("D:\\file");

        //判断是否存在
        System.out.println(f1.exists()); // false

        //如果D:\file不存在,则以文件的形式创建出来
        /*if(!f1.exists())
        {
            try {
                //以文件的形式创建出来
                f1.createNewFile();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }*/

        //如果D:\\file不存在,则以目录的形式创建出来
        /*if(!f1.exists())
        {
            //以目录的形式创建出来
            f1.mkdir();
        }*/

        //可以创建多重目录吗?
        /*File f2=new File("D:\\a\\b\\c\\d");
        if(!f2.exists())
        {
            f2.mkdirs();
        }*/

        File f3=new File("C:\\Users\\Jm\\Desktop\\Java\\学习笔记(Java)");
        //获取文件的父路径
        String fatherPath=f3.getParent();
        System.out.println(fatherPath);// C:\Users\Jm\Desktop\Java
        File parentFile=f3.getParentFile();
        System.out.println("获得绝对路径: "+parentFile.getAbsolutePath());

        File f4=new File("doSome");
        System.out.println("绝对路径: "+f4.getAbsolutePath());
        
    }
}

2)
String getName() 返回由此抽象路径名表示的文件或目录的名称。
boolean isDirectory() 测试此抽象路径名表示的文件是否为目录。
boolean isFile() 测试此抽象路径名表示的文件是否为普通文件。
long lastModified() 返回此抽象路径名表示的文件上次修改的时间。
long length() 返回由此抽象路径名表示的文件的长度。

package com.jmpower.javase.io;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
File常用方法:
    String getName() 返回由此抽象路径名表示的文件或目录的名称。
    boolean isDirectory() 测试此抽象路径名表示的文件是否为目录。
    boolean isFile() 测试此抽象路径名表示的文件是否为普通文件。
    long lastModified() 返回此抽象路径名表示的文件上次修改的时间。
    long length() 返回由此抽象路径名表示的文件的长度。  
 */
public class FileTest02 {
    public static void main(String[] args) {
        File f1=new File("C:\\Users\\Jm\\Desktop\\Java\\学习笔记(Java)\\day01.txt");
        //获取文件名
        System.out.println("文件名: "+f1.getName());

        //判断是否是一个目录
        System.out.println(f1.isDirectory());// false

        //判断是否是一个文件
        System.out.println(f1.isFile());// true

        //判断文件最后一次修改时时间
        long haoMiao=f1.lastModified();
        Date time=new Date(haoMiao);
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String strTime=sdf.format(time);
        System.out.println(strTime);

        //获取文件的大小
        System.out.println(f1.length());// 2155字节
    }
}

3)
File[] listFiles() 返回一个抽象路径名数组,表示由该抽象路径名表示的目录中的文件。

package com.jmpower.javase.io;

import java.io.File;

/*
File中的lastFiles方法。
    File[] listFiles() 返回一个抽象路径名数组,表示由该抽象路径名表示的目录中的文件。  
 */
public class FileTest03 {
    public static void main(String[] args) {
        File f1=new File("C:\\Users\\Jm\\Desktop\\Java\\学习笔记(Java)");
        File[] files=f1.listFiles();
        //foreach
        for(File file:files)
        {
            //获取绝对路径
            //System.out.println(file.getAbsolutePath());
            //获取名字
            System.out.println(file.getName());
        }
    }
}

19.目录拷贝

package com.jmpower.javase.io;

import java.io.*;
//程序BUG:拷贝源目录下的第一个文件无法拷贝
public class CopyAll {
    public static void main(String[] args) {
        //拷贝源
        File srcFile=new File("D:\\666\\c语言");
        //拷贝目标
        File destFile=new File("C:\\Users\\Jm\\Desktop\\Java");
        //调用方法拷贝
        copyDir(srcFile,destFile);
    }
    /**
     * 拷贝目录
     * @param srcFile   拷贝源
     * @param destFile  拷贝目标
     */
    private static void copyDir(File srcFile,File destFile){
        if(srcFile.isFile())
        {
            //srcFile如果是一个文件的话,递归结束
            //是文件需要拷贝
            //....一边读一边写
            FileInputStream in=null;
            FileOutputStream out=null;
            try {
                //读这个文件
                //D:\666\c语言\算法模板\map函数.txt
                in=new FileInputStream(srcFile);
                //写到这个文件中
                //C:\Users\Jm\Desktop\Java\666\c语言\算法模板\map函数.txt
                String path=(destFile.getAbsolutePath().endsWith("\\")?destFile.getAbsolutePath():destFile.getAbsolutePath()+"\\")+srcFile.getAbsolutePath().substring(3);
                out=new FileOutputStream(path);
                //一边读一边写
                byte[] bytes=new byte[1024*1024];//1MB
                int readCount=0;
                while((readCount=in.read(bytes))!=-1)
                {
                    out.write(bytes,0,readCount);
                }
                //刷新
                out.flush();
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
            return ;
        }
        //获取源下面的子目录
        File[] files=srcFile.listFiles();
        for(File file:files)
        {
            if(file.isDirectory())
            {
                //新建对应目录
                //System.out.println(file.getAbsolutePath());
                //D:\666\c语言\算法模板                           源目录
                //C:\Users\Jm\Desktop\Java\666\c语言\算法模板     目标目录
                String srcDir=file.getAbsolutePath();
                String destDir=(destFile.getAbsolutePath().endsWith("\\")?destFile.getAbsolutePath():destFile.getAbsolutePath()+"\\")+srcDir.substring(3);
                File newFile=new File(destDir);
                if(!newFile.exists())
                {
                    newFile.mkdirs();
                }
            }
            else {
                //保证拷贝目录下第一个是文件时,不会出现FileNotFound的异常
                File newFile=new File((destFile.getAbsolutePath().endsWith("\\")?destFile.getAbsolutePath():destFile.getAbsolutePath()+"\\")+srcFile.getAbsolutePath().substring(3));
                if(!newFile.exists())
                {
                    newFile.mkdirs();
                }
            }
            //递归调用
            copyDir(file,destFile);
        }
    }
}

20.序列化和反序列化

序列化: Serialize java对象存储到文件中。将java对象的状态保存下来的过程。
反序列化:DeSerialize 将硬盘上的数据重新恢复到内存当中,恢复成java对象。
java中的io流_第1张图片

1)序列化的实现:

package com.jmpower.javase.io;

import com.jmpower.javase.bean.Student;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/*
1.参与序列化和反序列化的对象,必须实现Serializable接口。

2.注意: 通过源码发现,Serializable接只是一个标志接口:
    public interface Serializable{
    }
    这个接口当中什么代码都没有。
    他只是起到一个标识的作用,标志的作用,java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊待遇。

3.序列化版本号有什么用呢?
    java.io.InvalidClassException:
        com.jmpower.javase.bean.Student;
        local class incompatible:
            stream classdesc serialVersionUID = -6680413217747085692, (10年前)
            local class serialVersionUID = -1967551671371379446(10年后)

    java语言是采用什么机制来区分类的?
        第一,首先通过类名进行比对,如果类名不一样,肯定不是同一个类。
        第二,如果类名一样,再根据序列化版本号进行区分。

    自动生成序列化版本号的好处:
        java虚拟机会自动区分不同人相同的实现了Serializable接口的类,都有默认的序列化版本号,
        他们的序列化版本号不一样。所以区分开了。

    自动生成序列化版本号的坏处:
        这种自动生成的序列化版本号,一旦代码确定之后,不能进行后续的修改,
        因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候
        java虚拟机会认为这是一个全新的类。(不利于以后的修改)
 */
public class ObjectOutputStreamTest01 {
    public static void main(String[] args) {
        //创建java对象
        Student s=new Student(1111,"zhansan");
        ObjectOutputStream oos=null;
        try {
            //序列化
            oos=new ObjectOutputStream(new FileOutputStream("students"));

            //序列化对象
            oos.writeObject(s);

            //刷新
            oos.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
}

2)反序列化的实现

package com.jmpower.javase.io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/*
反序列化
 */
public class ObjectInputStreamTest01 {
    public static void main(String[] args) {
        ObjectInputStream ois=null;
        try {
            ois=new ObjectInputStream(new FileInputStream("students"));
            //开始反序列化,读
            Object obj=ois.readObject();
            //反序列化回来是一个学生对象,所以会调用学生对象的toString方法。
            System.out.println(obj);
            ois.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
}

3)Student类

package com.jmpower.javase.bean;

import java.io.Serializable;

public class Student implements Serializable {
    private int age;
    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 + '\'' +
                '}';
    }
}

21.序列化多个对象

1)序列化

package com.jmpower.javase.io;

import com.jmpower.javase.bean.User;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
/*
一次序列化多个对象呢?
    可以,可以将对象放到集合当中,序列化对象。
提示:
    参与序列化的ArrayList集合以及集合中的元素User都需要实现java.io.Serializable接口。
 */
public class ObjectOutputStreamTest02 {
    public static void main(String[] args) {
        List<User> list=new ArrayList<>();
        list.add(new User(1111,"zhangsan"));
        list.add(new User(2222,"lisi"));
        list.add(new User(3333,"wangwu"));
        list.add(new User(4444,"zhaoliu"));
        ObjectOutputStream oos=null;
        try {
            oos=new ObjectOutputStream(new FileOutputStream("users"));
            //序列化一个集合,这个集合对象中放了很多其他对象。
            oos.writeObject(list);
            //刷新
            oos.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

2)反序列化

package com.jmpower.javase.io;

import com.jmpower.javase.bean.User;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;

public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws FileNotFoundException {
        ObjectInputStream ois=null;
        try {
            //反序列化
            ois=new ObjectInputStream(new FileInputStream("users"));
            List<User> list= (List<User>) ois.readObject();
            for(User user:list)
            {
                System.out.println(user);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

22.transient关键字

变量被transient关键词修饰,不会参与序列化。

package com.jmpower.javase.bean;

import java.io.Serializable;

public class User implements Serializable {
    //java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号
    //这里没有手动写出来,java虚拟机会默认提供这个序列化版本号。
    //建议将序列化版本号手动的写出来。不建议自动生成。
    private static final long serialVersionUID=1L;//java虚拟机识别一个类的时候,先看类名,类名一样再看序列化版本号。
    private int age;
    //若不手动写序列化版本号,过了很久,Student这个类源代码改动了。
    //源代码改动之后,需要重新编译,编译之后生成了全新的字节码文件。
    //并且class文件再次运行的时候,java虚拟机生成的序列化版本号也会发生相应的改变。
    private int no;
    //transient关键字表示游离的,不参与序列化。
    private transient String name;//name不参与序列化操作!
}

23.序列化版本号

序列化版本号有什么用呢?
java.io.InvalidClassException:
com.jmpower.javase.bean.Student;
local class incompatible:
stream classdesc serialVersionUID = -6680413217747085692,
(10年前)
local class serialVersionUID = -1967551671371379446
(10年后)

java语言是采用什么机制来区分类的?
第一,首先通过类名进行比对,如果类名不一样,肯定不是同一个类。
第二,如果类名一样,再根据序列化版本号进行区分。

自动生成序列化版本号处:
java虚拟机会自动区分不同人相同的实现了Serializable接口的类,都有默认的序列化版本号,
他们的序列化版本号不一样。所以区分开了。

自动生成序列化版本号处:
这种自动生成的序列化版本号,一旦代码确定之后,不能进行后续的修改,
因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候
java虚拟机会认为这是一个全新的类。(不利于以后的修改)

所以我们应该手动生成序列化版本号,以后修改源代码的时候,可以不用重新编译,直接运行,不会使得java虚拟机产生新的类,便于程序的修改。

package com.jmpower.javase.bean;

import java.io.Serializable;

public class User implements Serializable {
    //java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号
    //这里没有手动写出来,java虚拟机会默认提供这个序列化版本号。
    //建议将序列化版本号手动的写出来。不建议自动生成。
    private static final long serialVersionUID=1L;//java虚拟机识别一个类的时候,先看类名,类名一样再看序列化版本号。
    private int age;
    //若不手动写序列化版本号,过了很久,Student这个类源代码改动了。
    //源代码改动之后,需要重新编译,编译之后生成了全新的字节码文件。
    //并且class文件再次运行的时候,java虚拟机生成的序列化版本号也会发生相应的改变。
    private int no;
    //transient关键字表示游离的,不参与序列化。
    private transient String name;//name不参与序列化操作!
}

24.IO和Properties的联合使用

package com.jmpower.javase.io;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/*
IO+Properties的联合应用:
非常好的一个设计理念:
    以后经常改变的数据,可以单独写到一个文件中,使用程序动态读取。
    将来只需要修改这个文件的内容,java代码不需要改动,不需要重新编译,
    服务器也不需要重启。就可以拿到动态的信息。

    类似于以上机制的这种文件被称为配置文件。
    并且当配置文件中的内容格式是:
        key1=value
        key2=value
    的时候,我们把这种配置文件叫做属性配置文件。

    java规范中要求: 属性配置文件建议以.properties结尾,但这不是必须的。
    这种以.properties结尾的文件在java中称为: 属性配属文件。
    其中Properties是专门存放属性配置文件内容的一个类。
 */
public class IopropertiesTest01 {
    public static void main(String[] args) {
        /*
        Properties是一个Map集合,key和value都是String类型。
        想将doSome文件中的数据加载得到Properties的对象当中。
         */
        FileReader reader=null;
        try {
            //创建输入流对象
            reader=new FileReader("doSome1.properties");

            //创建一个Map集合
            Properties pro=new Properties();

            //调用Properties对象的load方法将文件中的数据加载到Map集合中。
            pro.load(reader);//文件中的数据顺着管道加载到Map集合中,其中=左边做key,右边做value

            //通过key来的调用value
            System.out.println(pro.getProperty("age"));

            //遍历
            Set<Map.Entry<Object, Object>> s=pro.entrySet();
            for(Map.Entry<Object,Object> o:s)
            {
                System.out.println(o.getKey()+"="+o.getValue());
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

属性配置文件的使用:

#在属性配置文件中井号是注释
#建议key和value之间使用=的方式,不建议使用 age:40
#=左边是key,=右边是value
#最好不要有空格
username=zhangsan
age=40

你可能感兴趣的:(Java基础,java,jvm,开发语言,javase)