1. File介绍

  File是“文件”和“目录路径名”的抽象表示形式。

  File直接继承Object,实现Serializable和Comparable接口,表示File对象既支持序列化,也可以File对象之间比较大小,可以直接存储在有序集合中(TreeSet,TreeMap)。

  File构造方法列表

public File(String pathname)    //给定路径名字符串创建File实例

public File(String parent, String child)

public File(File parent, String child)

public File(URI uri)

  File常用方法列表

boolean exists()    //文件是否存在,返回boolean

createNewFile()    //文件不存在则创建文件

mkdir()     //创建文件夹

mkdirs()  //递归创建文件夹

getParent()   //获取父文件的路径

getParentFile()   //获取父文件

getAbsolutePath()    //获取绝对路径

getName()    //获取文件名

isDirectory()   //判断是否是一个目录

isFile()    //判断是否是一个文件

lastModified()   //获取上一次修改时间,返回一个long的毫秒,从1970年到修改时间

listFiles()    //获取当前文件夹下所有子文件 ,返回一个File数组;

 

2. File实例

public class FileTest01{
    public static void main(String[] args) throws IOException{
        File f1 = new File("C:\\Users\\THINK\\Desktop\\JavaTest\\Temp09.txt");
    //    System.out.println(f1.exists());    //false
        
    //    if(!f1.exists()){
    //        f1.createNewFile();    //文件不存在则创建文件
    //    }
        
        File f2 = new File("C:\\Users\\THINK\\Desktop\\JavaTest\\file");
    //    if(!f2.exists()){
    //        f2.mkdir();   //文件夹不存在则创建文件夹
    //    }
    
        File f3 = new File("C:\\Users\\THINK\\Desktop\\JavaTest\\a\\b\\c");
    //    if(!f3.exists()){
    //        f3.mkdirs();    //文件夹不存在则递归创建文件夹
    //    }
    
        File f4 = new File("C:\\Users\\THINK\\Desktop\\JavaTest\\Temp09.txt");
        String f4ParentPath = f4.getParent();
        System.out.println("获取父路径:"+f4ParentPath);    //C:\\Users\\THINK\\Desktop\\JavaTest
        
        File f4Parent = f4.getParentFile();
        System.out.println("获取父文件绝对路径:"+f4Parent.getAbsolutePath());    //C:\\Users\\THINK\\Desktop\\JavaTest
        
        System.out.println("获取文件绝对路径:"+f4.getAbsolutePath());    //C:\\Users\\THINK\\Desktop\\JavaTest\\Temp09.txt
    
        File f5 = new File("C:\\Users\\THINK\\Desktop\\JavaTest\\chapter19.iml");
        
        System.out.println(f5.getName());    //chapter19.iml
        
        System.out.println(f5.isDirectory());    //false
        
        System.out.println(f5.isFile());    //true
        
        long time = f5.lastModified();
        Date date = new Date(time);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String str = sdf.format(date);
        System.out.println(str);
        
        File f6 = new File("C:\\Users\\THINK\\Desktop\\JavaTest\\file");
        File[] files = f6.listFiles();
        
        for(File f : files){
            System.out.println(f.getName());
            System.out.println(f.getAbsolutePath());
        }
    
    }
}

 

3. 目录拷贝

public class CopyTest03{
    public static void main(String[] args){
        File srcfile = new File("D:\\pyproject");
        File desfile = new File("C:\\Users\\THINK\\Desktop\\JavaTest\\file1");
        copyfile(srcfile,desfile);
    }
    
    public static void copyfile(File srcfile,File desfile){
        if(srcfile.isFile()){
            FileInputStream fis = null;
            FileOutputStream fos = null;
            try{
                fis = new FileInputStream(srcfile);
                String path = (desfile.getAbsolutePath().endsWith("\\")? desfile.getAbsolutePath():desfile.getAbsolutePath()+"\\") + srcfile.getAbsolutePath().substring(3);
                fos = new FileOutputStream(path);
                byte[] bytes = new byte[1024*1024];
                int readData = 0;
                while((readData = fis.read(bytes)) != -1){
                    fos.write(bytes,0,readData);
                }
                fos.flush();
            }catch(FileNotFoundException e){
                e.printStackTrace();
            }catch(IOException e){
                e.printStackTrace();
            }finally{
                if(fos != null){
                    try{
                        fos.close();
                    }catch(IOException e){
                        e.printStackTrace();
                    }
                }
                if(fis != null){
                    try{
                        fis.close();
                    }catch(IOException e){
                        e.printStackTrace();
                    }
                }
            }
            return;
        }
        
        File[] files = srcfile.listFiles();
        for(File fi:files){
            if(fi.isDirectory()){
                String srcDir = fi.getAbsolutePath();
                String desDir = (desfile.getAbsolutePath().endsWith("\\")? desfile.getAbsolutePath():desfile.getAbsolutePath()+"\\")+srcDir.substring(3);
                File newfile = new File(desDir);
                if(!newfile.exists()){
                    newfile.mkdirs();
                }
            }
            copyfile(fi,desfile);
        }
        
    }
}

 

4. 序列化和反序列化ObjectInputStream和ObjectOutputStream

  ObjectInputStream和ObjectOutputStream的作用是对基本数据和对象进行序列化操作。

  序列化就是为了保存对象的状态,反序列化可以把保存的对象状态再读出来。

  序列化和反序列化时Java提供的一种专门保存/恢复对象形态的机制。

  

  ObjectOutputStream方法列表

public ObjectOutputStream(OutputStream out) throws IOException    //构造方法,参数是一个输出字节变量

public final void writeObject(Object obj)    //写入对象

public void flush()    //刷新

 

  ObjectInputStream方法列表

public ObjectInputStream(InputStream in) throws IOException    //构造方法,参数是一个输入字节变量

public final Object readObject()    //读取对象

public void close()    //关闭字节流

 

  ObjectOutputStream序列化实例

public class ObjectOutputStreamTest01{
    public static void main(String[] args) throws Exception{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\THINK\\Desktop\\JavaTest\\Temp10"));
        oos.writeObject(new Student(18,"zhangsan"));
        oos.flush();
        oos.close();
    }
}

class Student implements Serializable{
    private int age;
    private String name;
    
    public Student(){}
    
    public Student(int age, String name){
        this.age = age;
        this.name = name;
    }
    
    public String toString(){
        return "Student{ age = " + age + ", name = " + name + "}";
    }
}

 

  ObjectInputStream反序列化实例

public class ObjectInputStreamTest01{
    public static void main(String[] args) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\THINK\\Desktop\\JavaTest\\Temp10"));
        Object obj = ois.readObject();
        System.out.println(obj);    //Student{ age = 18, name = zhangsan},反序列化对象是由JVM生成的,不通过构造方法生成
        ois.close();
    }
}

  程序序列化了Student对象到文件中,序列化对象必须实现Serializable接口

  Serializable接口中没有抽象方法,只是一个表示给JVM,JVM根据标识会生成序列号。

  

  序列化版本号SerialVersionUID

  随着项目的进行可能当之前实现序列化的类发生变化时,class文件也会发生变化,没有固定的版本号这时就不能直接反序列化出对象。

public class OtherStudent implements Serializable {
    private int age;
    private String name;
    private String address;    //Student已经发生了变化,添加了新属性

    public OtherStudent(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public OtherStudent() {
    }

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

  在IDEA中再次执行反序列化(不用执行序列化),就会抛出异常,在文件流中的class字节码文件已经和classpath中的class不在兼容了。

Exception in thread "main" java.io.InvalidClassException: lewang.javase.OtherStudent; local class incompatible: 
stream classdesc serialVersionUID = -9037750848657185009, local class serialVersionUID = -5541357443907101828

  

  如果我们真的有需求在序列化后修改字段和方法,就需要指定一个SeriaVerionID告诉JVM这是同一个文件,就可以再次反序列化了。

  重新修改程序,我们固定化一个序列化版本号,然后执行序列化和反序列化,此时是可以反序列化出对象的。在我们固定化版本号的基础上,我们再次添加属性,这次也可以反序列化出对象了。

public class OtherStudent implements Serializable {

    private static final long serialVersionUID = 1226762205367173625L;    //在类名上alt+enter,可以自动生成
    private int age;
    private String name;
    private String address;    //在固定化版本号基础上,再次添加属性

    public OtherStudent(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public OtherStudent() {
    }

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

 

5. 序列化和反序列化多个对象

public class OtherUser implements Serializable {
    private int age;
    private transient String name;

    public OtherUser() {
    }

    public OtherUser(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "OtherUser{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws Exception{
        List<OtherUser> list = new ArrayList<>();
        list.add(0,new OtherUser(11,"zhangsan"));
        list.add(1,new OtherUser(12,"lisi"));
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("practice/src/lewang/javase/Temp02"));
        oos.writeObject(list);
        oos.flush();
        oos.close();
    }
}
public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("practice/src/lewang/javase/Temp02"));
        List<OtherUser> lists = (List<OtherUser>)ois.readObject();
        for(OtherUser o : lists){
            System.out.println(o);    //OtherUser{age=11, name='null'}  OtherUser{age=12, name='null'}
        }
    }
}

  (1)使用transient修饰属性表示该属性不参与序列化,所以在反序列化时输出为默认值;

  (2)当多个对象参与序列化时可以使用List,对象需要实现Serialiable接口,ArrayList已经实现了Serizliable接口  

 

6. IO和Properties联合使用

  可以直接读取属性配置文件,一般以.properties结尾,设计经常改动的部分可以放在属性配置文件中,使用程序动态读取,不需要修改代码,也不需要重新编译,不需要重启,就可以获取改动的数据。

  程序实例

public class IOProperties{
    public static void main(String[] args) throws Exception{
        FileReader fr = new FileReader("C:\\Users\\THINK\\Desktop\\JavaTest\\userinfo.properties");
        Properties p = new Properties();
        p.load(fr);
        
        String username = p.getProperty("username");
        System.out.println(username);
        String password = p.getProperty("password");
        System.out.println(password);
        String user = p.getProperty("user");    //null
        System.out.println(user);
    }
}
#userinfo.properties文件

#key和value之间不要有空格 username
=abc password=123 # properties配置文件使用#注释 # 有重复的key时,value会覆盖 #password=234 #也可以使用:分割,但是不推荐使用 #user:eee

  当修改属性配置文件中password=13时,不需要重新编译,直接执行就可以获取到修改后的password值。

 

posted on 2021-08-08 17:04  homle  阅读(42)  评论(0编辑  收藏  举报