Java-IO

目录

1、IO流。什么是IO?

2、IO流的分类?

3、IO流中主要需要掌握什么? 

4、Java IO流有四大家族  

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

6、IO中部分实现类解析

6.1、FileInputStream:字节输入流

6.2、FileOutputStream:字节输出流

6.3、使用FileInputStream + FileOutStream完成文件的拷贝

6.4、FileReader:文本字符输入流

6.5、FileWriter,文件字符输出流

6.6、使用FileReader + FileWriter完成文件的拷贝

6.7、BufferedReader :带有缓冲区的字符输入流

6.8、BufferedWriter:带有缓冲的字符输出流

6.9、java.io.DataOutputStream:数据专属的流 + DataInputStream:数据字节输入流

6.10、PrintStream:标准的字节输出流

7、File类

7.1、File类常用的方法。

7.2、文件的拷贝(复制)

8、Serialize序列化

8.1、序列化概述

8.2、序列化版本号作用?

8.3、IO + Properties的联合使用


1、IO流。什么是IO?

  • I : Input
  • O : Outout
  • 通过IO可以完成硬盘的读和写

2、IO流的分类?

IO流的分类有多种分类方式:

(1)、一种方式是按照流的方向进行分类 以内存作为参照物

  • 往内存中去,叫做输入(Input),或者叫做读
  • 从内存中出,叫做输出(Output),或作叫做写

 (2)、另一种方式是按照读取数据方式不同进行分类:

  • 有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制,这种流是万能的,什么类型的文件都可以读取,包括:文本文件、图片。声音文件,视频
  • 有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取文本文件,而存在的。这种流不能读取:图片、声音、视频等文件,只能读取纯文本文件,链Word文件都无法读取。

  (3)、综上所示:流的分类

  •       输入流,输出流
  •       字节流,字符流

3、IO流中主要需要掌握什么? 

  • Java中所有的流都是在:java.io.*;下 ,其中IO流都已经写好了;
  • 我们程序员不需要关心,最主要掌握在Java中已经掌握哪些流,每个流的特点是什么,每个流对象的特点有哪些?
  • Java中主要还是研究:怎么new流对象,调用流对象的那个方法是读,那个方法是写;

4、Java IO流有四大家族  

(1)、 java.io.InputStreame  字节输入流

(2)、 java,io,OutoutStreame  字节输出流

(3)、java.io.Reader  字符输入流

(4)、java.io.Writer  字节输出流

四大家族的首领都是抽象类(abastract class), java中只要“类名”以Stream结尾的都是字节流,以“Readar/Writer”结尾的都是字符流

注意:

  • 所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法,流毕竟是一个管道,是内存与硬盘之间的通道,用完之后一定眼观鼻,否则会耗费大量资源。
  • 所有的java.io.Flushable接口,都是可刷新的,都有Flush()方法。养成一个好习惯,输出流在最终输出之后,一定要记得flush(), 刷新一下。刷新表示将通道/管道当中剩余未输出的数据强行输出完(清空管道)
  •  注意:没有fluse()可能会导致丢失数据

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

 (1)、文件专属:

  •  java.io.FileInputStream(掌握)
  •  java.io.FileOutputStream(掌握)
  •  java.io.FileReader
  •  java.io.FileWriter

(2)、转换流:(将字节转换成字符流)

  •  java.io.InputStreamReader
  •  java.io.OutputStreamReader

(3)缓冲流专属:

  •  java.io.BufferedReader
  •  java.io.BufferedWriter
  •  java.io.BufferedInputStream
  •  java.io.BufferedOutputStream

(4)、数据流专属:

  •  java.io.DataInputStream
  •  java.io.DateOutputStream

(5)、标准输出流:

  •  java.io.PrintWriter
  •  java.io.PrintStream(掌握)

(6)、对象专属流:

  •  java.io.ObjectInputStream(掌握)
  •  java.io.ObjectOutputStream(掌握)

6、IO中部分实现类解析

6.1、FileInputStream:字节输入流

(1)、

public class Main {
    public static void main(String[] args) {
        try {
            fis = new FileInputStream("文件的具体路径");
            while(true){
                int fist = fis.read();
                if(fist == -1){
                    break;
                }
                System.out.println(fist);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

分析这程序缺点:一次读取一个字节byte,内存与硬盘交互太频繁,耗费时间资源

(2)、对以上程序进行改进:

public class Main {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("文件路径");
            // 准备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));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

(3)、FileInputStream类的其他常用方法

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

6.2、FileOutputStream:字节输出流

(负责写,从内存到硬盘)

(1)、

public class Main {
    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};
            // 将byte数组全部写出
            fos.write(bytes);// 先写出abcd

            // 将byte数组一部分输出
            fos.write(bytes,0,2); // 再写出ef

            String s = "我是一个中国人";

            // 将字符串转为byte数组
            byte[] bs = s.getBytes();
            fos.write(bs);

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

6.3、使用FileInputStream + FileOutStream完成文件的拷贝

  • 拷贝的过程应该是一边读,一边写
  • 使用以上的字节流拷贝文件的时候,文件类型随意,万能型,什么样的文件都可以拷贝
public class Main {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            // 创建输入流对象
            fis = new FileInputStream("F:\\Java_非凡\\数据结构\\DataStructure\\DataStructure.iml"); // 被拷贝文件路径
            fos = new FileOutputStream("E:\\f盘拷贝文件"); // 需要给出拷贝路径
            // 一边读一边写(核心)
            byte[] bytes = new byte[1024 * 1024]; // 每次最多拷贝1MB
            int count = 0; // 定义变量,读入字节的数量
            while ((count = fis.read(bytes)) != -1) { // 向bytes数组里读入内容
                fos.write(bytes, 0, count); // 读多少写多少
            }
            // 刷新,输出流最后需要进行刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            System.out.println("文件路径错误");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 分开try,不要一起try
            // 一起try的时候,其中一个出现异常,可能影响另一个流的关闭
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

6.4、FileReader:文本字符输入流

  • 只能读取普通文本,读取文本内容时,比较方便,快捷
public class Main {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            // 创建文本字符输入流
            reader = new FileReader("文本路径");
            // 准备一个char[]数组
            char[] chars = new char[4];
            // 往char数组中读
            reader.read(chars); // 按字符方式读
            for(char c : chars){
                System.out.println(c);
            }
            /*// 开始读
            char[] chars = new char[4];
            int readCount = 0;
            while ((readCount = reader.read(chars)) != -1) {
                System.out.print(new String(chars, 0, readCount)); // 将字符数组转为字符串
            }*/
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

6.5、FileWriter,文件字符输出流

  • 只能输出普通文本
public class Main {
    public static void main(String[] args) {
        FileWriter writer = null;
        try {
            // 创建文本字符输出流对象
            // writer = new FileWriter("FileWrite"); // 对源文件进行清空
            writer = new FileWriter("FileWrite",true); // 对原文件追加

            // 开始写
            char[] chars = {'我','是','中','国','人'};
            writer.write("我是一名java软件工程师!");

            // 添加一个换行符
            writer.write("\n");
            writer.write(chars);
            writer.write("hello world");

            // 刷新
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(writer != null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

6.6、使用FileReader + FileWriter完成文件的拷贝

  • 只能拷贝“普通文本”文件
public class Main {
    public static void main(String[] args) {
        FileReader in = null;
        FileWriter out = null;
        try {
            in = new FileReader("文件具体路径");
            out = new FileWriter("拷贝路径");
            char[] chars = new char[1024 * 512]; // 1mb
            int readCount = 0;
            while((readCount = in.read(chars)) != -1){
                out.write(chars,0,readCount);
            }
            out.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(in != null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

6.7、BufferedReader :带有缓冲区的字符输入流

  • 使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组,自带缓冲

(1)FileReader读入缓冲区的字符输入流

public class Main {
    public static void main(String[] args) throws Exception{
        FileReader reader = new FileReader("CopyTest02"); // 读入某个文件
        // 当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流
        // 外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流
        // 对当前这个程序来说:FileReader就是一个节点流。BuffereReader就是包装流/处理流
        BufferedReader br = new BufferedReader(reader); // BufferedReader需要Reader参数
       
        /*
        String Lind01 = br.readLine(); // 读一行
        System.out.println(Lind01);

        // 第二行
        String Lind02 = br.readLine();
        System.out.println(Lind02);

        // 第三行
        String Lind03 = br.readLine();
        System.out.println(Lind03);
        */

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

        // 关闭流, 对于包装类来说,只需要关闭最外层流就行,里面的节点流会自动关闭。(可以看源代码)
        br.close();
    }
}

 (2)、FileInputStream字节输入流读入字符流,需要使用InputStreamReader转换流

public class BufferedReaderTest02 {
    public static void main(String[] args) throws Exception {
        /*// 字节流
        FileInputStream in = new FileInputStream("CopyTest02");

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

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

        // 合并
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("写入文件路径名")));

        String line = null;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }
        // 关闭最外层流
        br.close();
    }
}

6.8、BufferedWriter:带有缓冲的字符输出流

public class BufferedWriterTest01 {
    public static void main(String[] args) throws Exception{
        // 带有缓冲流的字符输出流
        // BufferedWriter out = new BufferedWriter(new FileWriter("文件路径名"));

        // 将字节流转换为字符流,写出
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("文件路径名",true)));

        // 开始写
        out.write("hello world!");
        out.write("\n");
        out.write("hello kity");

        // 刷新
        out.flush();
        // 关闭
        out.close();
    }
}

6.9、java.io.DataOutputStream:数据专属的流 + DataInputStream:数据字节输入流

  • DataOutputStream这个流可以将数据的类型一并写入文件。注意:这个文件不是普通的文本文档。(这个文档使用记事本打不开)
public class DataOutputStreamTest01 {
    public static void main(String[] args) throws  Exception {
        // 创建数据专属的字节输出流
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("date"));

        // 写数据
        byte b = 100;
        short s = 200;
        int i = 300;
        long l = 400l;
        float f = 3.0f;
        double d = 3.12;
        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();
        // 关闭最外层流
        dos.close();
    }
}
  • DataOutputStream:写的文件,只能通过DataInputStream去读。并且读的时候你需要提前知道写入的顺序(读的顺序要和写的顺序一致,才可以正常取出数据)

public class DataInputStreamTest01 {
    public static void main(String[] args) throws Exception {
        DataInputStream dis = new DataInputStream(new FileInputStream("date"));

        // 开始读
        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 + 1000);
        System.out.println(l);
        System.out.println(f);
        System.out.println(d);
        System.out.println(sex);
        System.out.println(c);

        // 关闭
        dis.close();
    }
}

6.10、PrintStream:标准的字节输出流

  • 默认输出为控制台
public class PrintStreamTest01 {
    public static void main(String[] args) throws Exception{

        // 联合起来写
        System.out.println("Hello world");

        // 分开写
        PrintStream ps = System.out;

        ps.println("zhangsan");
        ps.println("lisi");
        ps.println("wangwu");
        System.out.println("------------");

        // 标准输出流不需要手动close();

        // 可以改变标准输出流的输出方向吗? 可以
        /*System.gc();
        System.currentTimeMillis();
        PrintStream ps2 = System.out;
        System.exit(0);
        System.arraycopy(...);*/

        // 标准输出流不再指向控制台,指向“Log"文件
        PrintStream ps2 = new PrintStream(new FileOutputStream("log"));
        // 修改输出方向,将输出方向修改到"log"文件
        System.setOut(ps2);
        // 在输出
        System.out.println("hello kitty");
        System.out.println("hello zhangsan");
        System.out.println("hello world");
    }
}

对PrintStream的例子(记录日志),此处可以武略

class Logger {
    /*
    记录日志的方法
     */
    public static void log(String msg){
        try {
            // 指定日志文件
            PrintStream out = new PrintStream((new FileOutputStream("log.txt",true))); // true为追加
            // 改变输出方向
            System.setOut(out);
            // 日前当前时间
            Date nowDate = new Date(); // 1980年至现在的时间
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss sss");
            String strTime = sdf.format(nowDate);
            System.out.println(strTime + ":" + msg);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

// 测试类
public class LoggerTest{
    public static void main(String[] args) {
        // 测试工具类是否好用
        Logger.log("调用了System类的gc()方法,建议启动垃圾回收!");
        Logger.log("调用了UserSeervice的doSome()方法!");
        Logger.log("用户尝试进行登录,验证失败!");
        Logger.log("我非常喜欢这个记录日志的工具哦!!");
    }
}

7、File类

(1)、File类和四大家家族没有关系,所以File类不能完成文件的读写。
(2)、File对象代表什么?

  • 文件和目录名的抽象表示形式
  • 一个File对象有可能对应的是目录,也可能是文件
  • File只是一个路径名的抽象表示形式。

7.1、File类常用的方法。

方法名说明
boolean exists()判断文件是否存在
String getAbsolutePath()获取绝对路径
String getName()返回此抽象路径名表示的文件或目录的名称。
String getParent()获取文件的上一级目录名的字符串
File getParentFile()返回此抽象路径名的父
String getPath()将此抽象路径名转换为路径名字符串。
boolean isAbsolute()判断抽象路径名是否是绝对的
boolean isDirectory()测试此抽象路径名表示的文件是否为目录。
boolean isFile()测试此抽象路径名表示的文件是否为普通文件。
long lastModified()返回此抽象路径名表示的文件上次修改的时间。
long length()返回由此抽象路径名表示的文件的长度
File[] listFiles()返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件
boolean mkdirs()创建由此抽象路径名命名的目录。
boolean mkdir()

创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录

对以上部分方法使用:

public class FileTest01 {
    public static void main(String[] args) throws IOException {
        // 创建一个File对象
        File f1 = new File("F:\\file");

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

        // 如果 F:\file 不存在,则以文件的形式创建出来
        /*if(!f1.exist()){
            // 以文件形式创建
            f1.createNewFile();
        }*/

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

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

        File f3 = new File("F:\\JavaSE-Project");
        // 获取文件的父路径
        String parentPath = f3.getParent(); // F:\
        System.out.println(parentPath);

        // 获取文件绝对路径
        File parentfile = f3.getParentFile();
        System.out.println(parentfile);
        System.out.println("获取绝对路径:" + parentfile.getAbsolutePath());
        File f4 = new File("date");
        System.out.println(f4.getAbsoluteFile());
    }
}

7.2、文件的拷贝(复制)

public class Main {
    public static void main(String[] args) {
        File srcFile = new File("F:\\Java_非凡");// 拷贝源
        File destFile = new File("E:\\");
        copyDir(srcFile, destFile);
    }

    private static void copyDir(File srcFile, File destFile) {
        if (srcFile.isFile()) { // srcFile如果是一个文件,递归结束
            FileInputStream in = null;
            FileOutputStream out = null;
            try {
                // 读这个文件
                in = new FileInputStream(srcFile);

                String path = (destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\\") + srcFile.getAbsolutePath().substring(3);
                // 写入这个文件
                out = new FileOutputStream(path);
                // 一边读,一边写
                byte[] bytes = new byte[1024 * 1024];
                int readCount = 0;
                while ((readCount = in.read(bytes)) != -1) {
                    out.write(bytes, 0, readCount);
                }
                out.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (out != null) {
                    try {
                        out.flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return;
        }
        // 获取源下面的子目录
        File[] files = srcFile.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                // 新建对应的目录
                System.out.println();
                String strDir = file.getAbsolutePath();
                // String destDir = "动态获取路径" + strDir.substring(3);
                String destDir = (destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\\") + strDir.substring(3);
                File newFile = new File(destDir);
                if (!newFile.exists()) {
                    newFile.mkdirs(); // 如果该文件不存在,则创建该文件
                }
            }
            // System.out.println(file.getAbsolutePath()); // 获取所有文件(包括目录和文件),递归结束
            copyDir(file, destFile);// 递归调用
        }
    }
}

8、Serialize序列化

8.1、序列化概述

  • 对象的寿命通常随着生成该对象的程序的终止而终止。 有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。
  • 对象的输入输出流 (ObjectInputStream、ObjectOutStream),主要的作用是用于写入对象信息与读取对象信息,对象信息 一旦写到文 件上那么对象的信息就可以做到持久化了.

8.2、序列化版本号作用?

(1)、java语言中来区分类的机制:

  • 第一:首先通过类名进行比对,如果类名不一样,肯定不是同一类
  • 第二:如果类名一样,考序列化版本号区分。

(2)、自动生成自动化序列化的缺点:

  • 不能随意修改代码,一旦代码确定之后,不能进行后续的修改,因为一旦修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候Java虚拟机会认为这是一个全新的类。
  • 结论:
    凡是一个类实现了Serializeable接口,建议给该类提供一个固定不变的序列化版本号。
    这样,以后这个类即便代码修改了,但是版本号不变,Java虚拟机会认为是同一个类。

简单例题说:

(1)、创建User对象


public class User implements Serializable {
    private int no;
    // transient 关键早表示游离的,不参与序列化
    private transient String name;

    public User(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 + '\'' +
                '}';
    }
}

(2)、创建ObjectOutputStream,序列化

一次序列化多个对象:
     可以将对象放到集合中,序列化集合。

 参与序列化的ArrayList集合以及集合中的元素User都需要实现 java,io,Serializeable接口。
 */
public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws Exception {
        List<User> userList = new ArrayList<>();
        userList.add(new User(1,"zhangsan"));
        userList.add(new User(2,"lisi"));
        userList.add(new User(3,"wangwu"));
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("users"));

        // 序列化一个集合,这个集合对象放了很多其他对象
        oos.writeObject(userList);

        oos.flush();
        oos.close();
    }
}

(3)、反序列化集合

public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("users"));
        // Object obj = ois.readObject();
        // System.out.println(obj instanceof List); // true

        List<User> userList = (List<User>) ois.readObject();
        for(User user : userList){
            System.out.println(user);
        }
        ois.close();
    }
}

(4)、反序列化输出:

8.3、IO + Properties的联合使用

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

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

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

       属性配置文件中 # 是注释
       key重复的话,value自动覆盖
 */
public class IoPropertiesTest01 {
    public static void main(String[] args) throws Exception {
        /*
        Properties是一个Map集合,key和value都是String类型
        想将userinfo文件中的数据加载到Properties对象当中。
         */
        // 新建一个输入流
        FileInputStream reader = new FileInputStream("F:\\JavaSE-基础段\\JavaSE-Project\\Java-IDEA-进阶代码\\chapter23\\userinfo.properties");

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

        // 使用Propeerties对象的load方法讲文件中的数据加载到Map集合中
        pro.load(reader); // 文件中的数据局顺着管道加载到Map集合中,其中等号左边做key,右边做value

        // 通过key获取value
        String username = pro.getProperty("username");
        System.out.println(username);

        String password = pro.getProperty("password");
        System.out.println(password);
    }
}

输出:

 

 以上文件路径内容:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我来回答你的问题。 首先,让我们来了解一下什么是 EAV 模型。EAV 模型是一种数据建模的方法,它将所有的数据存储在一个三元组 (实体、属性、值) 中。其中,实体表示存储的对象,属性表示实体的某个特征,值则表示该属性的具体取值。这种模型可以用于存储非结构化数据和动态的数据,但是在查询和维护方面会存在一些挑战。 接下来,让我们来看一下如何实现简单的转存。Java 中提供了许多用于文件操作的类和方法,其中最常用的是 java.io 包中的类。我们可以使用 FileInputStream 和 FileOutputStream 类来实现文件的读写操作。 例如,我们可以通过以下代码将源文件的内容复制到目标文件中: ```java import java.io.*; public class FileCopy { public static void main(String[] args) { try { FileInputStream in = new FileInputStream("source.txt"); FileOutputStream out = new FileOutputStream("target.txt"); byte[] buffer = new byte[1024]; int length; while ((length = in.read(buffer)) > 0) { out.write(buffer, 0, length); } in.close(); out.close(); System.out.println("File copied successfully!"); } catch (IOException e) { e.printStackTrace(); } } } ``` 在上面的代码中,我们首先创建了一个 FileInputStream 对象来读取源文件,然后创建了一个 FileOutputStream 对象来写入目标文件。接着,我们使用一个字节数组作为缓冲区,每次读取 1024 个字节,并将其写入目标文件中。最后,我们关闭了输入输出流,完成了文件复制操作。 希望这个简单的例子能够帮助你入门 Java IO 操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值