• 【JAVA学习笔记】65 - 文件类,IO流--节点流、处理流、对象流、转换流、打印流


    项目代码

    https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter19/src/com/yinhai

    目录

    项目代码

    文件

    一、文件,流

    二、常用的文件操作

    1.创建文件对象相关构造器

    2.获取文件的相关信息

    3.目录的操作和文件删除

    IO流

    一、IO流原理及流的分类

    IO流的原理

    流的分类

    二、节点流

    1.字节节点FileInputStream和FileOutputStream

    1.文件字节输入流FileInputStream

    2.文件字节输出流FileOutputStream

    3.使用FileInput和FileOutput完成文件拷贝

    2.字符节点流FileReader和FileWriter

    三、处理流

    1.基本介绍

    2.节点流和处理流的区别和联系

    3.字符处理流BufferedReader和BufferedWriter

    BufferedReader

    BufferedWriter

    使用BufferedReader和BufferedWriter完成拷贝

    4.字节处理流BufferedInputStream和BufferedOutputStream

    四、对象流

    1. ObjectOutputStream 序列化

    2. ObjectInputStream 反序列化

    3.注意事项和细节说明

    五、标准输入输出流

    六、转换流

    1.引入

    2.介绍

    3.InputStreamReader使用

    4.OutputStreamWriter的使用

    七、打印流(只有输出流,没有输入流)

    1.PrintStream的使用

    2.PrintWriter的使用

    八、Properties类

    1.引入

    2.介绍

    3.应用


    文件

    一、文件,流

    文件,对我们并不陌生,文件是保存数据的地方,比如大家经常使用的word文档,txt文件,excel文件..都是文件。它既可以保存一张图片, 也可以保持视频,声

    文件在程序中是以流的形式来操作的

    流:数据在数据源(文件)和程序(内存)之间经历的路径

    输入流:数据从数据源(文件)到程序(内存)的路径

    输出流:数据从程序(内存)到数据源(文件)的路径

    二、常用的文件操作

    1.创建文件对象相关构造器

            new File(String pathname) //根据路径构建一个File对象

            new File(File parent,String child) //根据父目录文件+子路径构建

            new File(String parent,String child) //根据父目录+子路径构建

    1. public class FileCreate {
    2. public static void main(String[] args) {
    3. }
    4. //1 new File (String pathname)
    5. @Test
    6. public void create01(){
    7. String filePath = "e:\\new1.txt";
    8. File file = new File(filePath);
    9. try {
    10. file.createNewFile();
    11. System.out.println("文件创建成功");
    12. } catch (IOException e) {
    13. e.printStackTrace();
    14. }
    15. }
    16. //new File(File parent,String child) //根据父目录文件+子路径构建
    17. @Test
    18. public void create02(){
    19. File parentFile = new File("e:\\");
    20. String fileName = "new2.txt";
    21. File file = new File(parentFile, fileName);
    22. try {
    23. file.createNewFile();
    24. System.out.println("创建成功");
    25. } catch (IOException e) {
    26. e.printStackTrace();
    27. }
    28. }
    29. @Test
    30. public void create03(){
    31. String parentPath = "e:\\";
    32. String filePath = "news3.txt";
    33. File file = new File (parentPath,filePath);
    34. try {
    35. file.createNewFile();
    36. } catch (IOException e) {
    37. e.printStackTrace();
    38. }
    39. }
    40. }

    2.获取文件的相关信息

    1. public class FileInformation {
    2. public static void main(String[] args) {
    3. }
    4. public void info(){
    5. File file = new File("e\\new1.txt");
    6. System.out.println(file.getName());
    7. //调用相应的方法,得到对应信息
    8. //获取文件名字getName
    9. System.out.println("文件名字=" + file.getName());
    10. //文件绝对路径getAbsolutePath
    11. System.out.println("文件绝对路径=" + file.getAbsolutePath());
    12. //文件父级目录getParent
    13. System.out.println("文件父级目录=" + file.getParent());
    14. //文件大小(字节)length
    15. System.out.println("文件大小(字节)=" + file.length());
    16. //文件是否存在exists
    17. System.out.println("文件是否存在=" + file.exists());//T
    18. //是不是一个文件isFile
    19. System.out.println("是不是一个文件=" + file.isFile());//T
    20. //是不是一个目录isDirectory
    21. System.out.println("是不是一个目录=" + file.isDirectory());//F
    22. }
    23. }

    3.目录的操作和文件删除

    1. public class Directory_ {
    2. public static void main(String[] args) {
    3. //
    4. }
    5. //判断 d:\\news1.txt 是否存在,如果存在就删除
    6. @Test
    7. public void m1() {
    8. String filePath = "e:\\new1.txt";
    9. File file = new File(filePath);
    10. if (file.exists()) {
    11. if (file.delete()) {
    12. System.out.println(filePath + "删除成功");
    13. } else {
    14. System.out.println(filePath + "删除失败");
    15. }
    16. } else {
    17. System.out.println("该文件不存在...");
    18. }
    19. }
    20. //判断 D:\\demo02 是否存在,存在就删除,否则提示不存在
    21. //这里我们需要体会到,在java编程中,目录也被当做文件
    22. @Test
    23. public void m2() {
    24. String filePath = "D:\\demo02";
    25. File file = new File(filePath);
    26. if (file.exists()) {
    27. if (file.delete()) {
    28. System.out.println(filePath + "删除成功");
    29. } else {
    30. System.out.println(filePath + "删除失败");
    31. }
    32. } else {
    33. System.out.println("该目录不存在...");
    34. }
    35. }
    36. //判断 D:\\demo\\a\\b\\c 目录是否存在,如果存在就提示已经存在,否则就创建
    37. @Test
    38. public void m3() {
    39. String directoryPath = "E:\\demo\\a\\b\\c";
    40. File file = new File(directoryPath);
    41. if (file.exists()) {
    42. System.out.println(directoryPath + "存在..");
    43. } else {
    44. if (file.mkdirs()) { //"E:\demo"创建一级目录使用mkdir() ,创建多级目录使用mkdirs()
    45. System.out.println(directoryPath + "创建成功..");
    46. } else {
    47. System.out.println(directoryPath + "创建失败...");
    48. }
    49. }
    50. }
    51. }

    IO流

    一、IO流原理及流的分类

    IO流的原理

    1. I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯等。

    2. Java程序中,对于数据的输入/输出操作以”流(stream)"的方式进行。

    3. java.io包下提供了各种"流"类和接口,用以获取不同种类的数据,并通过方法输入或输出数据

    4.输入input:读取外部数据(磁盘、 光盘等存储设备的数据)到程序(内存)中。

    5.输出output:将程序(内存) 数据输出到磁盘、光盘等存储设备中

    流的分类

    按操作数据单位不同分为:字节流(8 bit),字符流(按字符,对应几个字节根据编码决定大小)

    按数据流的流向不同分为:输入流,输出流

    按流的角色的不同分为:节点流,处理流/包装流

    1) Java的I0流共涉及40多个类,实际上非常规则,都是从如上4个抽象基类派生的。

    2)由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。

    二、节点流

    1.字节节点FileInputStream和FileOutputStream

    1.文件字节输入流FileInputStream

    InputStream抽象类是所有类字节输入流的超类

    InputStream 常用的子类

    1. FileInputStream:文件输入流

    2. BufferedInputStream:缓冲字节输入流

    3. ObjectInputStream:对象字节输入流

    1. public class FileInputStream_ {
    2. public static void main(String[] args) {
    3. }
    4. @Test
    5. public void readFile01() {
    6. String filePath = "e:\\hello.txt";
    7. FileInputStream fileInputStream = null;
    8. int readDate = 0;
    9. try {
    10. fileInputStream = new FileInputStream(filePath);
    11. //如何返回-1,表示读取完毕
    12. while ((readDate = fileInputStream.read()) != -1) {
    13. System.out.print((char) readDate);
    14. }
    15. } catch (IOException e) {
    16. e.printStackTrace();
    17. } finally {
    18. try {
    19. fileInputStream.close();
    20. } catch (Exception e) {
    21. e.printStackTrace();
    22. }
    23. }
    24. }
    25. @Test
    26. public void readFile02() {
    27. String filePath = "e:\\hello.txt";
    28. FileInputStream fileInputStream = null;
    29. int readDate = 0;
    30. byte[] buf = new byte[8];
    31. int readLen = 0;
    32. try {
    33. fileInputStream = new FileInputStream(filePath);
    34. //如何返回-1,表示读取完毕
    35. while ((readLen = fileInputStream.read(buf)) != -1) {
    36. System.out.print(new String(buf, 0, readLen));
    37. }
    38. } catch (IOException e) {
    39. e.printStackTrace();
    40. } finally {
    41. try {
    42. fileInputStream.close();
    43. } catch (Exception e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. }
    48. }
    2.文件字节输出流FileOutputStream

    1. public class FileOutputStream01 {
    2. public static void main(String[] args) {
    3. }
    4. /**
    5. * 演示使用FileOutputStream 将数据写到文件中,
    6. * 如果该文件不存在,则创建该文件
    7. */
    8. @Test
    9. public void writeFile() {
    10. //创建 FileOutputStream对象
    11. String filePath = "e:\\a.txt";
    12. FileOutputStream fileOutputStream = null;
    13. try {
    14. //得到 FileOutputStream对象 对象
    15. //1. new FileOutputStream(filePath) 创建方式,当写入内容是,会覆盖原来的内容
    16. //2. new FileOutputStream(filePath, true) 创建方式,当写入内容是,是追加到文件后面
    17. fileOutputStream = new FileOutputStream(filePath,true);
    18. //写入一个字节
    19. fileOutputStream.write('H');//
    20. //写入字符串
    21. String str = "hello,world!";
    22. //str.getBytes() 可以把 字符串-> 字节数组
    23. //fileOutputStream.write(str.getBytes());
    24. /*
    25. write(byte[] b, int off, int len) 将 len字节从位于偏移量 off的指定字节数组写入此文件输出流
    26. */
    27. fileOutputStream.write(str.getBytes(), 0, str.length());
    28. } catch (IOException e) {
    29. e.printStackTrace();
    30. } finally {
    31. try {
    32. fileOutputStream.close();
    33. } catch (IOException e) {
    34. e.printStackTrace();
    35. }
    36. }
    37. }
    38. }
    3.使用FileInput和FileOutput完成文件拷贝

            

    1. public class FileCopy_ {
    2. public static void main(String[] args) {
    3. String filePath = "e:\\test\\miku.jpg";
    4. String destFilePath = "e:\\\\mikucopy.jpg";
    5. //将该文件复制到e:\\miku.jpg
    6. FileInputStream fileInputStream =null;
    7. FileOutputStream fileOutputStream =null;
    8. try {
    9. fileInputStream = new FileInputStream(filePath);
    10. fileOutputStream = new FileOutputStream(destFilePath);
    11. //定义一个字节数组提高读取效率
    12. byte[] buf = new byte[1024];
    13. int readLen = 0;
    14. while ((readLen = fileInputStream.read(buf)) != -1){
    15. //读取到后就写入文件
    16. fileOutputStream.write(buf,0,readLen);//readLen接受到的是当前读取的长度
    17. //fileOutputStream.write(buf);//不能使用该方法,会导致及使不够也会抓到1024的长度的内容
    18. }
    19. System.out.println("拷贝完成");
    20. } catch (IOException e) {
    21. e.printStackTrace();
    22. }finally {
    23. try {
    24. //关闭输入流和输出流
    25. if(fileInputStream != null){
    26. fileInputStream.close();
    27. }
    28. if(fileOutputStream != null){
    29. fileOutputStream.close();
    30. }
    31. } catch (IOException e) {
    32. e.printStackTrace();
    33. }
    34. }
    35. }
    36. }

            

    2.字符节点流FileReader和FileWriter

    FileReader和FileWriter 是字符流,即按照字符来操作io

    FileReader常用方法:

            1) new FileReader(File/String)

            2) read:每次读取单个字符,返回该字符,如果到文件末尾返回-1

            3) read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1

    相关API:

            1) new String(char[]):将char[]转换成String

            2) new String(char[],off,len):将char[的指定部分转换成String

    FileReader应用案例

    1. public class FileReader_ {
    2. public static void main(String[] args) {
    3. }
    4. /**
    5. * 单个字符读取文件
    6. */
    7. @Test
    8. public void readFile01() {
    9. String filePath = "e:\\test\\story.txt";
    10. FileReader fileReader = null;
    11. int data = 0;
    12. //1. 创建FileReader对象
    13. try {
    14. fileReader = new FileReader(filePath);
    15. //循环读取 使用read, 单个字符读取
    16. while ((data = fileReader.read()) != -1) {
    17. System.out.print((char) data);
    18. }
    19. } catch (IOException e) {
    20. e.printStackTrace();
    21. } finally {
    22. try {
    23. if (fileReader != null) {
    24. fileReader.close();
    25. }
    26. } catch (IOException e) {
    27. e.printStackTrace();
    28. }
    29. }
    30. }
    31. /**
    32. * 字符数组读取文件
    33. */
    34. @Test
    35. public void readFile02() {
    36. System.out.println("~~~readFile02 ~~~");
    37. String filePath = "e:\\story.txt";
    38. FileReader fileReader = null;
    39. int readLen = 0;
    40. char[] buf = new char[8];
    41. //1. 创建FileReader对象
    42. try {
    43. fileReader = new FileReader(filePath);
    44. //循环读取 使用read(buf), 返回的是实际读取到的字符数
    45. //如果返回-1, 说明到文件结束
    46. while ((readLen = fileReader.read(buf)) != -1) {
    47. System.out.print(new String(buf, 0, readLen));
    48. }
    49. } catch (IOException e) {
    50. e.printStackTrace();
    51. } finally {
    52. try {
    53. if (fileReader != null) {
    54. fileReader.close();
    55. }
    56. } catch (IOException e) {
    57. e.printStackTrace();
    58. }
    59. }
    60. }
    61. }

    FileWriter常用方法:

            1) new FileWriter(File/String) : 覆盖模相当于流的指针在首端

            2) new FileWriter(File/String.true) :追加模式,相当于流的指针在尾端

            3) write(int):写入单个字符

            4) write(char[]):写入指定数组

            5) write(charD,offlen):写入指定数组的指定部分

            6) write (string) :写入整个字符串

            7) write(string,off,len):写入字符串的指定部分

    相关API: String类: toCharArray:将String转换成char[]

    注意:FileWriter使用后,必须要关闭(close)或刷新(flush), 否则写入不到指定的文件!

    1. public class FileWriter_ {
    2. public static void main(String[] args) {
    3. String filePath = "e:\\note.txt";
    4. //创建FileWriter对象
    5. FileWriter fileWriter = null;
    6. char[] chars = {'a', 'b', 'c'};
    7. try {
    8. fileWriter = new FileWriter(filePath);//默认是覆盖写入
    9. // 3) write(int):写入单个字符
    10. fileWriter.write('H');
    11. // 4) write(char[]):写入指定数组
    12. fileWriter.write(chars);
    13. // 5) write(char[],off,len):写入指定数组的指定部分
    14. fileWriter.write("韩顺平教育".toCharArray(), 0, 3);
    15. // 6) write(string):写入整个字符串
    16. fileWriter.write(" 你好北京~");
    17. fileWriter.write("风雨之后,定见彩虹");
    18. // 7) write(string,off,len):写入字符串的指定部分
    19. fileWriter.write("上海天津", 0, 2);
    20. //在数据量大的情况下,可以使用循环操作.
    21. } catch (IOException e) {
    22. e.printStackTrace();
    23. } finally {
    24. try {
    25. //fileWriter.flush();
    26. //关闭文件流,等价 flush() + 关闭
    27. fileWriter.close();
    28. //对应FileWriter , 一定要关闭流,或者flush才能真正的把数据写入到文件
    29. //老韩看源码就知道原因.
    30. /*
    31. 看看代码
    32. private void writeBytes() throws IOException {
    33. this.bb.flip();
    34. int var1 = this.bb.limit();
    35. int var2 = this.bb.position();
    36. assert var2 <= var1;
    37. int var3 = var2 <= var1 ? var1 - var2 : 0;
    38. if (var3 > 0) {
    39. if (this.ch != null) {
    40. assert this.ch.write(this.bb) == var3 : var3;
    41. } else {
    42. this.out.write(this.bb.array(), this.bb.arrayOffset() + var2, var3);
    43. }
    44. }
    45. this.bb.clear();
    46. }
    47. */
    48. } catch (IOException e) {
    49. e.printStackTrace();
    50. }
    51. }
    52. System.out.println("程序结束...");
    53. }
    54. }

    三、处理流

    1.基本介绍

            1)节点流可以从一个特定的数据源读写数据,如FileReader、 FileWriter [源码]

                    

            2)处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,如BufferedReader. BufferedWriter [源码]

                    

    2.节点流和处理流的区别和联系

            1)节点流是底层流/低级流,直接跟数据源相接。

            2)处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。(面向对象,存进去后就只调用BufferedReader即可)

            3)处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连(模拟修饰器设计模式

    处理流的功能主要体现在以下两个方面:

            1)性能的提高:主要以增加缓冲的方式来提高输入输出的效率。

            2)操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便

    1. public class Test_ {
    2. public static void main(String[] args) {
    3. BufferedReader_ bufferedReader = new BufferedReader_(new FileReader_());
    4. BufferedReader_ bufferedReader1 = new BufferedReader_(new StringReader_());
    5. bufferedReader.readFile(5);
    6. bufferedReader.readString(5);
    7. }
    8. }
    9. public class BufferedReader_ extends Reader_{
    10. private Reader_ reader_;
    11. public BufferedReader_(Reader_ reader_) {
    12. this.reader_ = reader_;
    13. }
    14. //让方法更灵活多次读取
    15. public void readFile(int num){
    16. for (int i = 0; i < num; i++) {
    17. reader_.readFile();
    18. }
    19. }
    20. public void readString(int num){
    21. for (int i = 0; i < num; i++) {
    22. reader_.readString();
    23. }
    24. }
    25. }
    26. public abstract class Reader_ {//抽象类
    27. public void readString(){
    28. }
    29. public void readFile(){
    30. }
    31. }
    32. public class StringReader_ extends Reader_{
    33. public void readString(){
    34. }
    35. }
    36. public class FileReader_ extends Reader_{
    37. public void readFile(){
    38. }
    39. }

    3.字符处理流BufferedReader和BufferedWriter

    BufferedReader

    BufferedReader和BufferedWriter属于字符流,是按照字符来读取数据的关闭时处理流,只需要关闭外层流印可

            1)使用BufferedReader读取文本文件,并显示在控制台

    1. public class BufferedReader_ {
    2. public static void main(String[] args) throws Exception {
    3. String filePath = "e:\\test\\BufferedReader_.java";
    4. //创建bufferedReader
    5. BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
    6. //读取
    7. String line; //按行读取, 效率高
    8. //说明
    9. //1. bufferedReader.readLine() 是按行读取文件
    10. //2. 当返回null 时,表示文件读取完毕
    11. while ((line = bufferedReader.readLine()) != null) {
    12. System.out.println(line);
    13. }
    14. //关闭流, 这里注意,只需要关闭 BufferedReader ,因为底层会自动的去关闭 节点流
    15. //FileReader。
    16. /*
    17. public void close() throws IOException {
    18. synchronized (lock) {
    19. if (in == null)
    20. return;
    21. try {
    22. in.close();//in 就是我们传入的 new FileReader(filePath), 关闭了.
    23. } finally {
    24. in = null;
    25. cb = null;
    26. }
    27. }
    28. }
    29. */
    30. bufferedReader.close();
    31. }
    32. }

    BufferedWriter
    1. public class BufferedWriter_ {
    2. public static void main(String[] args) throws IOException {
    3. String filePath = "e:\\test\\testBufferedWriter_.txt";
    4. //创建BufferedWriter
    5. //说明:
    6. //1. new FileWriter(filePath, true) 表示以追加的方式写入
    7. //2. new FileWriter(filePath) , 表示以覆盖的方式写入
    8. BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath/*,true*/));
    9. bufferedWriter.write("hello, 韩顺平教育!");
    10. bufferedWriter.newLine();//插入一个和系统相关的换行
    11. bufferedWriter.write("hello2, 韩顺平教育!");
    12. bufferedWriter.newLine();
    13. bufferedWriter.write("hello3, 韩顺平教育!");
    14. bufferedWriter.newLine();
    15. //说明:关闭外层流即可 , 传入的 new FileWriter(filePath) ,会在底层关闭
    16. bufferedWriter.close();
    17. }
    18. }

                     

    使用BufferedReader和BufferedWriter完成拷贝
    1. public class BufferedCopy_ {
    2. public static void main(String[] args) {
    3. //Buffered是字符流 所以不要去操作二进制文件[声音,视频,doc,pdf等等]
    4. String srcFilePath = "e:\\test\\story.txt";
    5. String destFilePath = "e:\\test\\testBufferedCopy.txt";
    6. String line;
    7. BufferedReader bufferedReader = null;
    8. BufferedWriter bufferedWriter = null;
    9. try {
    10. bufferedReader = new BufferedReader(new FileReader(srcFilePath));
    11. bufferedWriter = new BufferedWriter(new FileWriter(destFilePath));
    12. //读取写入 readLine是读取一行的内容,但是没有换行
    13. while ((line = bufferedReader.readLine()) != null) {
    14. //每读取一行就写入
    15. bufferedWriter.write(line);
    16. bufferedWriter.newLine();
    17. }
    18. } catch (IOException e) {
    19. e.printStackTrace();
    20. } finally {
    21. try {
    22. if (bufferedReader != null) {
    23. bufferedReader.close();
    24. }
    25. if (bufferedWriter != null) {
    26. bufferedWriter.close();
    27. }
    28. } catch (IOException e) {
    29. e.printStackTrace();
    30. }
    31. }
    32. }
    33. }

    4.字节处理流BufferedInputStream和BufferedOutputStream

    BufferedInputStream是字节流在创建BufferedInputStream会创建一个内部缓冲区数组.

    BufferedOutputStream是字节流,实现缓冲的输出流,可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统

    1. public class BufferedCopy02 {
    2. public static void main(String[] args) {
    3. // String srcFilePath = "e:\\Koala.jpg";
    4. // String destFilePath = "e:\\hsp.jpg";
    5. // String srcFilePath = "e:\\0245_韩顺平零基础学Java_引出this.avi";
    6. // String destFilePath = "e:\\hsp.avi";
    7. String srcFilePath = "e:\\a.java";
    8. String destFilePath = "e:\\a3.java";
    9. //创建BufferedOutputStream对象BufferedInputStream对象
    10. BufferedInputStream bis = null;
    11. BufferedOutputStream bos = null;
    12. try {
    13. //因为 FileInputStream 是 InputStream 子类
    14. bis = new BufferedInputStream(new FileInputStream(srcFilePath));
    15. bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
    16. //循环的读取文件,并写入到 destFilePath
    17. byte[] buff = new byte[1024];
    18. int readLen = 0;
    19. //当返回 -1 时,就表示文件读取完毕
    20. while ((readLen = bis.read(buff)) != -1) {
    21. bos.write(buff, 0, readLen);
    22. }
    23. System.out.println("文件拷贝完毕~~~");
    24. } catch (IOException e) {
    25. e.printStackTrace();
    26. } finally {
    27. //关闭流 , 关闭外层的处理流即可,底层会去关闭节点流
    28. try {
    29. if(bis != null) {
    30. bis.close();
    31. }
    32. if(bos != null) {
    33. bos.close();
    34. }
    35. } catch (IOException e) {
    36. e.printStackTrace();
    37. }
    38. }
    39. }
    40. }

    四、对象流

    看一个需求

    1.将int num = 100这个int数据保存到文件中,注意不是100数字,而是int 100,并且,能够从文件直接恢复int 100

    2.将Dog dog = new Dog(”小黄”, 3)这个dog对象保存到文件中,并且能够从文件恢复,

    3.上面的要求, 就是能够将基本数据类型或者对象进行序列化和反序列化操作

    序列化和反序列化

    1.序列化就是在保存数据时,保存数据的值和数据类型

    2.反序列化就是在恢复数据时,恢复数据的值和数据类型

    3.需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之-:

            Serializable //这是一 个标记接口(推荐使用该接口)

            Externalizable //该接口有两个方法需要实现

    功能:提供了对基本类型或对象类型的序列化和反序列化的方法

    1. ObjectOutputStream 提供序列化功能

    2. ObjectInputStream 提供反序列化功能

    1. ObjectOutputStream 序列化

    Dog类需要放在可以引用的位置 不然反序列化调用不到

    1. public class ObjectOutStream_ {
    2. public static void main(String[] args) throws Exception {
    3. //序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存
    4. String filePath = "e:\\test\\objectData.dat";
    5. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
    6. //序列化数据到 e:\data.dat
    7. oos.writeInt(100);// int -> Integer (实现了 Serializable)
    8. oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)
    9. oos.writeChar('a');// char -> Character (实现了 Serializable)
    10. oos.writeDouble(9.5);// double -> Double (实现了 Serializable)
    11. oos.writeUTF("韩顺平教育");//String(实现了 Serializable)
    12. //保存一个dog对象
    13. oos.writeObject(new Dog("旺财", 10, "日本", "白色"));
    14. oos.close();
    15. System.out.println("数据保存完毕(序列化形式)");
    16. }
    17. }
    18. class Dog implements Serializable {
    19. private String name;
    20. private int age;
    21. private String form;
    22. private String color;
    23. public Dog(String name, int age, String form, String color) {
    24. this.name = name;
    25. this.age = age;
    26. this.form = form;
    27. this.color = color;
    28. }
    29. }

    2. ObjectInputStream 反序列化

    1. public class ObjectInputStream_ {
    2. public static void main(String[] args) throws IOException, ClassNotFoundException {
    3. //指定反序列化的文件
    4. String filePath = "e:\\test\\objectData.dat";
    5. ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
    6. //读取
    7. //1. 读取(反序列化)的顺序需要和你保存数据(序列化)的顺序一致
    8. //2. 否则会出现异常
    9. System.out.println(ois.readInt());
    10. System.out.println(ois.readBoolean());
    11. System.out.println(ois.readChar());
    12. System.out.println(ois.readDouble());
    13. System.out.println(ois.readUTF());
    14. //dog 的编译类型是 Object , dog 的运行类型是 Dog
    15. Object dog = ois.readObject();
    16. System.out.println("运行类型=" + dog.getClass());
    17. System.out.println("dog信息=" + dog);//底层 Object -> Dog
    18. //这里是特别重要的细节:
    19. //1. 如果我们希望调用Dog的方法, 需要向下转型
    20. //2. 需要我们将Dog类的定义,放在到可以引用的位置,Dog类公有化
    21. Dog dog2 = (Dog)dog;
    22. System.out.println(dog2.getName()); //旺财..
    23. //关闭流, 关闭外层流即可,底层会关闭 FileInputStream 流
    24. ois.close();
    25. }
    26. }

    3.注意事项和细节说明

            1)读写顺序要一致

            2)要求实现序列化或反序列化对象,需要实现Serializable

            3)序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性

            4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员

            5)序列化对象时,要求里面属性的类型也需要实现序列化接口

            6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

    五、标准输入输出流

    1. public class InputAndOutput {
    2. public static void main(String[] args) {
    3. //System 类 的 public final static InputStream in = null;
    4. // System.in 编译类型 InputStream
    5. // System.in 运行类型 BufferedInputStream
    6. // 表示的是标准输入 键盘
    7. System.out.println(System.in.getClass());
    8. //1. System.out public final static PrintStream out = null;
    9. //2. 编译类型 PrintStream
    10. //3. 运行类型 PrintStream
    11. //4. 表示标准输出 显示器
    12. System.out.println(System.out.getClass());
    13. //传统方法System.out.println(); 是使用out对象将数据输出到显示器
    14. System.out.println("hello, 韩顺平教育~");
    15. //传统的方法,Scanner是从标准输入键盘接收数据
    16. Scanner scanner = new Scanner(System.in);
    17. System.out.println("输入内容");
    18. String next = scanner.next();
    19. System.out.println("next=" + next);
    20. }
    21. }

    六、转换流

    1.引入

    1. public class CodeQuestion {
    2. public static void main(String[] args) throws IOException {
    3. //读取e:\\a.txt 文件到程序
    4. //思路
    5. //1. 创建字符输入流 BufferedReader [处理流]
    6. //2. 使用 BufferedReader 对象读取a.txt
    7. //3. 默认情况下,读取文件是按照 utf-8 编码,但可能不一定是utf-8编码,就会出现乱码情况
    8. String filePath = "e:\\a.txt";
    9. BufferedReader br = new BufferedReader(new FileReader(filePath));
    10. String s = br.readLine();
    11. System.out.println("读取到的内容: " + s);
    12. br.close();
    13. }
    14. }

                    

    2.介绍

    1. InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成(转换)成Reader(字符流)

    2. OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流)

    3.当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流

    4.可以在使用时指定编码格式(比如utf-8, gbk, gb2312, IS08859-1等)

    3.InputStreamReader使用

    1. public class InputStreamReader_ {
    2. public static void main(String[] args) throws IOException {
    3. String filePath = "e:\\a.txt";
    4. //解读
    5. //1. 把 FileInputStream 转成 InputStreamReader
    6. //2. 指定编码 gbk
    7. //InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
    8. //3. 把 InputStreamReader 传入 BufferedReader
    9. //BufferedReader br = new BufferedReader(isr);
    10. //将2 和 3 合在一起
    11. BufferedReader br = new BufferedReader(new InputStreamReader(
    12. new FileInputStream(filePath), "gbk"));
    13. //4. 读取
    14. String s = br.readLine();
    15. System.out.println("读取内容=" + s);
    16. //5. 关闭外层流
    17. br.close();
    18. }
    19. }

    4.OutputStreamWriter的使用

    1. public class OutputStreamWriter_ {
    2. public static void main(String[] args) throws IOException {
    3. String filePath = "e:\\test\\nihao.txt";
    4. String charSet = "utf-8";
    5. BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath), charSet));
    6. bufferedWriter.write("hi, 你好");
    7. bufferedWriter.close();
    8. System.out.println("按照 " + charSet + " 保存文件成功~");
    9. }
    10. }

                    

    七、打印流(只有输出流,没有输入流)

    1.PrintStream的使用

    1. public class PrintStream_ {
    2. public static void main(String[] args) throws IOException {
    3. PrintStream out = System.out;
    4. //在默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器
    5. /*
    6. public void print(String s) {
    7. if (s == null) {
    8. s = "null";
    9. }
    10. write(s);
    11. }
    12. */
    13. out.print("john, hello");
    14. //因为print底层使用的是write , 所以我们可以直接调用write进行打印/输出
    15. out.write("韩顺平,你好".getBytes());
    16. out.close();
    17. //我们可以去修改打印流输出的位置/设备
    18. //1. 输出修改成到 "e:\\f1.txt"
    19. //2. "hello, 韩顺平教育~" 就会输出到 e:\f1.txt
    20. //3. public static void setOut(PrintStream out) {
    21. // checkIO();
    22. // setOut0(out); // native 方法,修改了out
    23. // }
    24. System.setOut(new PrintStream("e:\\test\\f1.txt"));
    25. System.out.println("hello, 韩顺平教育~");
    26. }
    27. }

    2.PrintWriter的使用

                    

    1. public class PrintWriter_ {
    2. public static void main(String[] args) throws IOException {
    3. //PrintWriter printWriter = new PrintWriter(System.out);//打印到显示器 标准输出
    4. PrintWriter printWriter = new PrintWriter(new FileWriter("e:\\f2.txt"));
    5. printWriter.print("hi, 北京你好~~~~");
    6. printWriter.close();//flush + 关闭流, 才会将数据写入到文件..
    7. }
    8. }

    八、Properties类

    1.引入

    如下一个配置文件mysql.properties

            ip = 192.168.0.13

            user = root

            pwd = 12345

    请问编程读取ip、user 和pwd的值是多少

    分析

    1. 传统的方法

    2. 使用Properties类可以方便实现

    2.介绍

    1)专门用于读写配置文件的集合类

    配置文件的格式:

            键=值

            键=值

    2)注意:键值对不需要有空格,值不需要用引号一起来。 默认类型是String

    3) Properties的常见方法

            load:加载配置文件的键值对到Properties对象

            list:将数据显示到指定设备/流对象

            getProperty(key):根据键获取值

            setProperty(key,value);:设置键值对到Properties对象

            store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为unicode码

    3.应用

    1.使用Properties类完成对mysql.properties的读取,看老师代码演示

    1. public class Properties02 {
    2. public static void main(String[] args) throws IOException {
    3. //使用Properties 类来读取mysql.properties 文件
    4. //1. 创建Properties 对象
    5. Properties properties = new Properties();
    6. //2. 加载指定配置文件
    7. properties.load(new FileReader("src\\mysql.properties"));
    8. //3. 把k-v显示控制台
    9. properties.list(System.out);
    10. //4. 根据key 获取对应的值
    11. String user = properties.getProperty("user");
    12. String pwd = properties.getProperty("pwd");
    13. System.out.println("用户名=" + user);
    14. System.out.println("密码是=" + pwd);
    15. }
    16. }

    2.使用Proper ties类添加key-val到新文件mysql2.properties中

    3.使用Properties类完成对mysql2.properties的读取,并修改某个key-val

    1. public class Properties03 {
    2. public static void main(String[] args) throws IOException {
    3. //使用Properties 类来创建 配置文件, 修改配置文件内容
    4. Properties properties = new Properties();
    5. //创建
    6. //1.如果该文件没有key 就是创建
    7. //2.如果该文件有key ,就是修改
    8. /*
    9. Properties 父类是 Hashtable , 底层就是Hashtable 核心方法
    10. public synchronized V put(K key, V value) {
    11. // Make sure the value is not null
    12. if (value == null) {
    13. throw new NullPointerException();
    14. }
    15. // Makes sure the key is not already in the hashtable.
    16. Entry tab[] = table;
    17. int hash = key.hashCode();
    18. int index = (hash & 0x7FFFFFFF) % tab.length;
    19. @SuppressWarnings("unchecked")
    20. Entry entry = (Entry)tab[index];
    21. for(; entry != null ; entry = entry.next) {
    22. if ((entry.hash == hash) && entry.key.equals(key)) {
    23. V old = entry.value;
    24. entry.value = value;//如果key 存在,就替换
    25. return old;
    26. }
    27. }
    28. addEntry(hash, key, value, index);//如果是新k, 就addEntry
    29. return null;
    30. }
    31. */
    32. properties.setProperty("charset", "utf8");
    33. properties.setProperty("user", "汤姆");//注意保存时,是中文的 unicode码值
    34. properties.setProperty("pwd", "888888");//底层就是hashTable,所以set就是替换K-V
    35. //将k-v 存储文件中即可
    36. properties.store(new FileOutputStream("src\\mysql2.properties"), "hello,world");//comments代表注释
    37. System.out.println("保存配置文件成功~");
    38. }
    39. }

  • 相关阅读:
    《多线程案例》阻塞队列、定时器、线程池、饿汉与懒汉模式
    链表OJ练习(2)
    RabbitMQ 入门系列:5、基础编码:交换机的进阶介绍及编码方式。
    分布式计算实验5:HDFS论文阅读
    php的curl请求,包含了post,get,put,delete
    java中的垃圾回收算法与垃圾回收器
    Java中的static关键字
    数据仓库应该用什么方案——数据仓库实施方案概述
    概率论的学习和整理13--方差和协方差(未完成)
    孩子升年级难适应?猿辅导语文金牌教研来支招
  • 原文地址:https://blog.csdn.net/qq_41891655/article/details/134255933