文件传输基础 ~ Java I/O 流。+ Serializable 序列化。

文件传输基础~Java I/O 流。



文件的编码。

eg. 文件内容都是“移动”。

在这里插入图片描述

UTF-8 一个中文占 3 个字节。

ANSI 一个中文占 2 个字节。

在这里插入图片描述

package com.geek.encode;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.SortedMap;

public class EncodeDemo {

    public static void main(String[] args) throws UnsupportedEncodingException {

        // TODO Auto-generated method stub

        String s = "幕课 ABC";
        byte[] bytes1 = s.getBytes();
        for (byte b : bytes1) {
            // 把字节(转换成了 int)以 16 进制的方式显示。
            System.out.print(Integer.toHexString(b) + " ");
//            System.out.println(Integer.toHexString(b & 0xff));
            // ffffffe5 ffffffb9 ffffff95 ffffffe8 ffffffaf ffffffbe 20 41 42 43
        }
        System.out.println();
        // gbk 编码中文占用 2 个字节。英文占用 1 个字节。
        byte[] bytes2 = s.getBytes("gbk");
        for (byte aByte : bytes2) {
            System.out.print(aByte + " ");
            // -60 -69 -65 -50 32 65 66 67
        }
        System.out.println();
        // utf-8 编码中文占用 3 个字节。英文占用 1 个字节。
        byte[] bytes3 = s.getBytes(StandardCharsets.UTF_8);
        for (byte aByte : bytes3) {
            System.out.print(aByte + " ");
            // -27 -71 -107 -24 -81 -66 32 65 66 67
        }
        System.out.println();
        // Java 是双字节编码。utf-16be。
        // utf-16be 编码中文占用 2 个字节。英文占用 2 个字节。
        byte[] bytes4 = s.getBytes(StandardCharsets.UTF_16BE);
        for (byte aByte : bytes4) {
            System.out.print(aByte + " ");
            // 94 85 -117 -2 0 32 0 65 0 66 0 67
        }
        System.out.println();
        // 当字节序列以某种编码晨,想把 ta 转换为字符串,
        // 也必须使用该编码方式,否则出现乱码。
        String string = new String(bytes4);// 使用项目默认编码。
        System.out.println("string = " + string);
        // string = ^U��   A B C
        String string2 = new String(bytes4, "utf-16be");// 使用项目默认编码。
        System.out.println("string2 = " + string2);
        // string2 = 幕课 ABC

        System.out.println();

        /**
         * 文本文件 就是字节序列。
         * 可以是任意编码的字节序列。
         * 如果我们在中文机器中直接创建文本文件,只认识 ansi 编码。
         * 从其他位置来的文件,都认识。eg. 复制过来的文件。
         */
        SortedMap<String, Charset> stringCharsetSortedMap = Charset.availableCharsets();
        System.out.println("stringCharsetSortedMap = " + stringCharsetSortedMap);
        // stringCharsetSortedMap = {Big5=Big5, Big5-HKSCS=Big5-HKSCS, CESU-8=CESU-8, EUC-JP=EUC-JP, EUC-KR=EUC-KR, GB18030=GB18030, GB2312=GB2312, GBK=GBK, IBM-Thai=IBM-Thai, IBM00858=IBM00858, IBM01140=IBM01140, IBM01141=IBM01141, IBM01142=IBM01142, IBM01143=IBM01143, IBM01144=IBM01144, IBM01145=IBM01145, IBM01146=IBM01146, IBM01147=IBM01147, IBM01148=IBM01148, IBM01149=IBM01149, IBM037=IBM037, IBM1026=IBM1026, IBM1047=IBM1047, IBM273=IBM273, IBM277=IBM277, IBM278=IBM278, IBM280=IBM280, IBM284=IBM284, IBM285=IBM285, IBM290=IBM290, IBM297=IBM297, IBM420=IBM420, IBM424=IBM424, IBM437=IBM437, IBM500=IBM500, IBM775=IBM775, IBM850=IBM850, IBM852=IBM852, IBM855=IBM855, IBM857=IBM857, IBM860=IBM860, IBM861=IBM861, IBM862=IBM862, IBM863=IBM863, IBM864=IBM864, IBM865=IBM865, IBM866=IBM866, IBM868=IBM868, IBM869=IBM869, IBM870=IBM870, IBM871=IBM871, IBM918=IBM918, ISO-2022-CN=ISO-2022-CN, ISO-2022-JP=ISO-2022-JP, ISO-2022-JP-2=ISO-2022-JP-2, ISO-2022-KR=ISO-2022-KR, ISO-8859-1=ISO-8859-1, ISO-8859-13=ISO-8859-13, ISO-8859-15=ISO-8859-15, ISO-8859-2=ISO-8859-2, ISO-8859-3=ISO-8859-3, ISO-8859-4=ISO-8859-4, ISO-8859-5=ISO-8859-5, ISO-8859-6=ISO-8859-6, ISO-8859-7=ISO-8859-7, ISO-8859-8=ISO-8859-8, ISO-8859-9=ISO-8859-9, JIS_X0201=JIS_X0201, JIS_X0212-1990=JIS_X0212-1990, KOI8-R=KOI8-R, KOI8-U=KOI8-U, Shift_JIS=Shift_JIS, TIS-620=TIS-620, US-ASCII=US-ASCII, UTF-16=UTF-16, UTF-16BE=UTF-16BE, UTF-16LE=UTF-16LE, UTF-32=UTF-32, UTF-32BE=UTF-32BE, UTF-32LE=UTF-32LE, UTF-8=UTF-8, windows-1250=windows-1250, windows-1251=windows-1251, windows-1252=windows-1252, windows-1253=windows-1253, windows-1254=windows-1254, windows-1255=windows-1255, windows-1256=windows-1256, windows-1257=windows-1257, windows-1258=windows-1258, windows-31j=windows-31j, x-Big5-HKSCS-2001=x-Big5-HKSCS-2001, x-Big5-Solaris=x-Big5-Solaris, x-euc-jp-linux=x-euc-jp-linux, x-EUC-TW=x-EUC-TW, x-eucJP-Open=x-eucJP-Open, x-IBM1006=x-IBM1006, x-IBM1025=x-IBM1025, x-IBM1046=x-IBM1046, x-IBM1097=x-IBM1097, x-IBM1098=x-IBM1098, x-IBM1112=x-IBM1112, x-IBM1122=x-IBM1122, x-IBM1123=x-IBM1123, x-IBM1124=x-IBM1124, x-IBM1166=x-IBM1166, x-IBM1364=x-IBM1364, x-IBM1381=x-IBM1381, x-IBM1383=x-IBM1383, x-IBM300=x-IBM300, x-IBM33722=x-IBM33722, x-IBM737=x-IBM737, x-IBM833=x-IBM833, x-IBM834=x-IBM834, x-IBM856=x-IBM856, x-IBM874=x-IBM874, x-IBM875=x-IBM875, x-IBM921=x-IBM921, x-IBM922=x-IBM922, x-IBM930=x-IBM930, x-IBM933=x-IBM933, x-IBM935=x-IBM935, x-IBM937=x-IBM937, x-IBM939=x-IBM939, x-IBM942=x-IBM942, x-IBM942C=x-IBM942C, x-IBM943=x-IBM943, x-IBM943C=x-IBM943C, x-IBM948=x-IBM948, x-IBM949=x-IBM949, x-IBM949C=x-IBM949C, x-IBM950=x-IBM950, x-IBM964=x-IBM964, x-IBM970=x-IBM970, x-ISCII91=x-ISCII91, x-ISO-2022-CN-CNS=x-ISO-2022-CN-CNS, x-ISO-2022-CN-GB=x-ISO-2022-CN-GB, x-iso-8859-11=x-iso-8859-11, x-JIS0208=x-JIS0208, x-JISAutoDetect=x-JISAutoDetect, x-Johab=x-Johab, x-MacArabic=x-MacArabic, x-MacCentralEurope=x-MacCentralEurope, x-MacCroatian=x-MacCroatian, x-MacCyrillic=x-MacCyrillic, x-MacDingbat=x-MacDingbat, x-MacGreek=x-MacGreek, x-MacHebrew=x-MacHebrew, x-MacIceland=x-MacIceland, x-MacRoman=x-MacRoman, x-MacRomania=x-MacRomania, x-MacSymbol=x-MacSymbol, x-MacThai=x-MacThai, x-MacTurkish=x-MacTurkish, x-MacUkraine=x-MacUkraine, x-MS932_0213=x-MS932_0213, x-MS950-HKSCS=x-MS950-HKSCS, x-MS950-HKSCS-XP=x-MS950-HKSCS-XP, x-mswin-936=x-mswin-936, x-PCK=x-PCK, x-SJIS_0213=x-SJIS_0213, x-UTF-16LE-BOM=x-UTF-16LE-BOM, X-UTF-32BE-BOM=X-UTF-32BE-BOM, X-UTF-32LE-BOM=X-UTF-32LE-BOM, x-windows-50220=x-windows-50220, x-windows-50221=x-windows-50221, x-windows-874=x-windows-874, x-windows-949=x-windows-949, x-windows-950=x-windows-950, x-windows-iso2022jp=x-windows-iso2022jp}
    }

}



File 类。

package com.geek.file;

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

public class FileDemo {

    public static void main(String[] args) {

        String separator = File.separator;
        System.out.println("separator = " + separator);
        // /
        String pathSeparator = File.pathSeparator;
        System.out.println("pathSeparator = " + pathSeparator);
        // :
        char separatorChar = File.separatorChar;
        System.out.println("separatorChar = " + separatorChar);
        // /
        char pathSeparatorChar = File.pathSeparatorChar;
        System.out.println("pathSeparatorChar = " + pathSeparatorChar);
        // ;

        // 构造方法。
        File file = new File("/home/geek/geek/javaio/test");
        boolean exists = file.exists();
        System.out.println("exists = " + exists);
        if (!file.exists()) {
            boolean mkdir = file.mkdir();
            System.out.println("mkdir = " + mkdir);
        } else {
            boolean delete = file.delete();
            System.out.println("delete = " + delete);
        }

        // 构造方式 2。
//        new File("home/geek/geek/javaio/txt/日记.txt");
        File file1 = new File("/home/geek/geek/javaio/", "日记.txt");
        if (!file1.exists()) {
            try {
                file1.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            file1.delete();
        }

        // 常用 api。
        System.out.println("file = " + file);// file = /home/geek/geek/javaio/test
        String absolutePath = file.getAbsolutePath();
        System.out.println(absolutePath);// /home/geek/geek/javaio/test
        String name = file.getName();
        System.out.println(name);
        String parent = file.getParent();
        System.out.println(parent);
    }

}

package com.geek.file;

import java.io.File;

public class FileUtils {

    /**
     * 列出指定目录下(包括其子目录)的所有文件。
     *
     * @param dir
     */
    public static void listDirectory(File dir) {
        // 目录不存在。
        if (!dir.exists()) {
            throw new RuntimeException("目录" + dir + "不存在。");
        }
        // 不是目录。
        if (!dir.isDirectory()) {
            throw new RuntimeException(dir + "不是目录。");
        }

        String[] list = dir.list();// 字符串数组。
        assert list != null;
        for (String string : list) {
            System.out.println(dir + "/" + string);
        }

        // 如果要遍历子目录下的内容就要构造成 File 对象做递归操作。File 提供了直接返回 File 对象的 api。
        File[] files = dir.listFiles();// 返回的是直接子目录的对象。
        if (files != null && files.length > 0) {

            for (File file : files) {
//                System.out.println(file);
                if (file.isDirectory()) {
                    // 递归。
                    listDirectory(file);
                } else {
                    System.out.println("file = " + file);
                }
            }
        }
    }

}

package com.geek.file;

import java.io.File;

public class FileUtilsTest {

    public static void main(String[] args) {
        FileUtils.listDirectory(new File("/home/geek/IdeaProjects/geek_file/geek-file"));

    }

}



RandomAccessFile。

常用:多线程下载文件。

package com.geek;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;

public class RandomAccessFileDemo {

    // RandomAccessFile。Java 提供的对文件内容的访问,既可以读文件也可以写文件。
//    RandomAccessFile 支持随机访问文件,可以访问文件任意位置。

    // Java 文件模型。
    //         在硬盘上的文件是 byte byte byte 存储的。是数据的集合。
    // 打开文件。
    //         两种模式。rw 读写。r 只读。
    //         文件指针。打开文件时指针在开头。
    // 写文件。
    //      raf.write(int);。只写一个字节(后 8 位),同时指针指向下一个位置,准备再次写入。
    // 读方法。
    //      int b = raf.read();。
    // 文件操作完毕一定要关闭。Oracle 官方文档说明。

    public static void main(String[] args) throws IOException {

        // 创建文件夹。
        File demo = new File("demo");
        if (!demo.exists()) {
            demo.mkdir();
        }

        // 创建文件。
        File file = new File(demo, "raf.dat");
        if (!file.exists()) {
            file.createNewFile();
        }

        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
        // 指针的位置。
        long filePointer = randomAccessFile.getFilePointer();
        System.out.println(filePointer);// 0。

        randomAccessFile.write('A');
        // write(); 只写入一个字节。
        // 一个 char 2 字节。所以先写入 A 的后 8 位。
        System.out.println(randomAccessFile.getFilePointer());// 1

        randomAccessFile.write('B');
        System.out.println(randomAccessFile.getFilePointer());// 2

        int i = 0x7fffffff;// Java 最大整数。
        // 用 write() 方法,每次只能写一个字节,写入 i 要写 4 次。
        randomAccessFile.write(i >>> 24);// 高八位。
        randomAccessFile.write(i >>> 16);
        randomAccessFile.write(i >>> 8);
        randomAccessFile.write(i);
        System.out.println(randomAccessFile.getFilePointer());// 6

        // 直接写入 int。
        randomAccessFile.writeInt(i);

        String s = "中";
        byte[] gbk = s.getBytes("gbk");
        randomAccessFile.write(gbk);
        System.out.println(randomAccessFile.length());// 12

        // 读文件,必须把指针移到头部。
        randomAccessFile.seek(0);
        // 一次性读取。
        byte[] buf = new byte[(int) randomAccessFile.length()];
        randomAccessFile.read(buf);
        System.out.println(Arrays.toString(buf));
        // [65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]
        String s1 = Arrays.toString(buf);
        System.out.println("s1 = " + s1);
        // s1 = [65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]

        for (byte b : buf) {
            System.out.print(Integer.toHexString(b & 0xff) + " ");
            // 41 42 7f ff ff ff 7f ff ff ff d6 d0
        }
        randomAccessFile.close();
    }

}



IO 流。(输入流、输出流)。

字节流。
InputSream、OutputStream。

InputSream 抽象了应用程序读取数据的方式。

OutputStream 抽象了应用程序写出数据的方式。



EOF。

EOF = End。读到 -1 就到结尾。



FileInputStream 具体实现了在文件上的读取数据。
package com.geek.io;

import java.io.*;

public class IOUtil {

    /**
     * 读取文件内容,按照 16 进制输出到控制台。
     */
    // IOUtilTest。
    public static void printHex(String fileName) throws IOException {
        // 把文件作为字节流进行读操作。
        FileInputStream inputStream = new FileInputStream(fileName);
        int b;
        int i = 1;
        while ((b = inputStream.read()) != -1) {
            if (b < 0xf) {
                // 单位数前补 0。
                System.out.print("0");
            }
            System.out.print(Integer.toHexString(b) + "  ");
            if (i+- % 10 == 0) {
                System.out.println();
            }
        }
        inputStream.close();
    }
}

  • 测试。
package com.geek.io;

import java.io.IOException;

public class IOUtilTest {

    public static void main(String[] args) {
        try {
            IOUtil.printHex("/home/geek/IdeaProjects/geek_file/geek-file/src/com/geek/io/IOUtil.java");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package com.geek.io;

import java.io.*;

public class IOUtil {

    /**
     * 读取文件内容。字节数组。按照 16 进制输出到控制台。
     *
     * @param fileName
     * @throws IOException
     */
    // IOUtilTest02。
    public static void printHexByByteArray(String fileName) throws IOException {
        FileInputStream inputStream = new FileInputStream(fileName);
        byte[] buf = new byte[8 * 1024];
        // 从 inputStream 中批量读取字节,放入到 buf 字节数组中,
        // 从第 0 个位置开始,最多放 buf.length 个。
        // 返回的是读到的字节个数。
        /*
        int read = inputStream.read(buf, 0, buf.length);// 一次性读完,说明字节数组足够大。
        int j = 1;
        for (int i = 0; i < read; i++) {
            if (buf[i] <= 0xf) {
                System.out.print("0");// 补 0。
            }
            System.out.print(Integer.toHexString(buf[i]) + "  ");
            if (j+- % 10 == 0) {
                System.out.println();
            }
        }
         */

        int bytes = 0;
        int j = 0;
        while ((bytes = inputStream.read(buf, 0, buf.length)) != -1) {
            for (int i = 0; i < bytes; i++) {
                System.out.print(Integer.toHexString(buf[i] & 0xff) + "  ");
                if (j+- % 10 == 0) {
                    System.out.println();
                }
            }
        }
    }
}

package com.geek.io;

import java.io.IOException;

public class IOUtilTest02 {

    public static void main(String[] args) {
        try {
            IOUtil.printHexByByteArray("/home/geek/IdeaProjects/geek_file/geek-file/src/com/geek/io/IOUtil.java");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}



FileOutputStream 具体实现了在文件上的写入数据。
package com.geek.out;

import com.geek.io.IOUtil;

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

public class FileOutDemo {

    public static void main(String[] args) throws IOException {
        // 如果不存在,则直接创建。如果存在,删除后创建。
        FileOutputStream fileOutputStream = new FileOutputStream("geek-file/out.dat");
        fileOutputStream.write('A');// 写出 A 字符的低 8 位。
        fileOutputStream.write('B');// 写出 B 字符的低 8 位。
        int a = 10;
        // write(); 方法只能写出低 8 位。写一个 int 需要写 4 次。
        fileOutputStream.write(a >>> 24);
        fileOutputStream.write(a >>> 16);
        fileOutputStream.write(a >>> 8);
        fileOutputStream.write(a);

        byte[] gbk = "中国".getBytes("utf-8");
        fileOutputStream.write(gbk);

        fileOutputStream.close();

        IOUtil.printHex("geek-file/out.dat");
    }
}

  • copy。
package com.geek.io;

import java.io.*;

public class IOUtil {

    /**
     * 读取文件内容,按照 16 进制输出到控制台。
     */
    // IOUtil
    public static void printHex(String fileName) throws IOException {
        // 把文件作为字节流进行读操作。
        FileInputStream inputStream = new FileInputStream(fileName);
        int b;
        int i = 1;
        while ((b = inputStream.read()) != -1) {
            if (b < 0xf) {
                // 单位数前补 0。
                System.out.print("0");
            }
            System.out.print(Integer.toHexString(b) + "  ");
            if (i+- % 10 == 0) {
                System.out.println();
            }
        }
        inputStream.close();
    }

    /**
     * 读取文件内容。字节数组。按照 16 进制输出到控制台。
     *
     * @param fileName
     * @throws IOException
     */
    // IOUtilTest02。
    public static void printHexByByteArray(String fileName) throws IOException {
        FileInputStream inputStream = new FileInputStream(fileName);
        byte[] buf = new byte[8 * 1024];
        // 从 inputStream 中批量读取字节,放入到 buf 字节数组中,
        // 从第 0 个位置开始,最多放 buf.length 个。
        // 返回的是读到的字节个数。
        /*
        int read = inputStream.read(buf, 0, buf.length);// 一次性读完,说明字节数组足够大。
        int j = 1;
        for (int i = 0; i < read; i++) {
            if (buf[i] <= 0xf) {
                System.out.print("0");// 补 0。
            }
            System.out.print(Integer.toHexString(buf[i]) + "  ");
            if (j+- % 10 == 0) {
                System.out.println();
            }
        }
         */

        int bytes = 0;
        int j = 0;
        while ((bytes = inputStream.read(buf, 0, buf.length)) != -1) {
            for (int i = 0; i < bytes; i++) {
                System.out.print(Integer.toHexString(buf[i] & 0xff) + "  ");
                if (j+- % 10 == 0) {
                    System.out.println();
                }
            }
        }
    }

    // CopyTest。
    public static void copyFile(File srcFile, File destFile) throws IOException {
        if (!srcFile.exists()) {
            throw new IllegalArgumentException("文件" + srcFile + "不存在。");
        }
        if (!srcFile.isFile()) {
            throw new IllegalArgumentException(srcFile + "不是文件。");
        }
        FileInputStream inputStream = new FileInputStream(srcFile);
        FileOutputStream outputStream = new FileOutputStream(destFile);
        byte[] buf = new byte[8 * 1024];
        int b;
        while ((b = inputStream.read(buf, 0, buf.length)) != -1) {
            outputStream.write(buf, 0, b);
            outputStream.flush();
        }
        outputStream.close();
        inputStream.close();
    }
}

  • 测试。
package com.geek.out;

import com.geek.io.IOUtil;

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

public class CopyTest {

    public static void main(String[] args) {
        try {
            IOUtil.copyFile(new File("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt"), new File("/home/geek/IdeaProjects/geek_file/geek-file/geek01.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}



DataOutputStream、DataInputStream。

对流的扩展。更加方便的读取 int, long,字符等类型的数据。

package com.geek.io;

import java.io.*;

public class IOUtil {

    /**
     * 读取文件内容,按照 16 进制输出到控制台。
     */
    // IOUtil
    public static void printHex(String fileName) throws IOException {
        // 把文件作为字节流进行读操作。
        FileInputStream inputStream = new FileInputStream(fileName);
        int b;
        int i = 1;
        while ((b = inputStream.read()) != -1) {
            if (b < 0xf) {
                // 单位数前补 0。
                System.out.print("0");
            }
            System.out.print(Integer.toHexString(b) + "  ");
            if (i+- % 10 == 0) {
                System.out.println();
            }
        }
        inputStream.close();
    }

    /**
     * 读取文件内容。字节数组。按照 16 进制输出到控制台。
     *
     * @param fileName
     * @throws IOException
     */
    // IOUtilTest02。
    public static void printHexByByteArray(String fileName) throws IOException {
        FileInputStream inputStream = new FileInputStream(fileName);
        byte[] buf = new byte[8 * 1024];
        // 从 inputStream 中批量读取字节,放入到 buf 字节数组中,
        // 从第 0 个位置开始,最多放 buf.length 个。
        // 返回的是读到的字节个数。
        /*
        int read = inputStream.read(buf, 0, buf.length);// 一次性读完,说明字节数组足够大。
        int j = 1;
        for (int i = 0; i < read; i++) {
            if (buf[i] <= 0xf) {
                System.out.print("0");// 补 0。
            }
            System.out.print(Integer.toHexString(buf[i]) + "  ");
            if (j+- % 10 == 0) {
                System.out.println();
            }
        }
         */

        int bytes = 0;
        int j = 0;
        while ((bytes = inputStream.read(buf, 0, buf.length)) != -1) {
            for (int i = 0; i < bytes; i++) {
                System.out.print(Integer.toHexString(buf[i] & 0xff) + "  ");
                if (j+- % 10 == 0) {
                    System.out.println();
                }
            }
        }
    }

    /**
     * 文件 copy。字节批量读取。
     *
     * @param srcFile
     * @param destFile
     * @throws IOException
     */
    // CopyTest。
    public static void copyFile(File srcFile, File destFile) throws IOException {
        if (!srcFile.exists()) {
            throw new IllegalArgumentException("文件" + srcFile + "不存在。");
        }
        if (!srcFile.isFile()) {
            throw new IllegalArgumentException(srcFile + "不是文件。");
        }
        FileInputStream inputStream = new FileInputStream(srcFile);
        FileOutputStream outputStream = new FileOutputStream(destFile);
        byte[] buf = new byte[8 * 1024];
        int b;
        while ((b = inputStream.read(buf, 0, buf.length)) != -1) {
            outputStream.write(buf, 0, b);
            outputStream.flush();
        }
        outputStream.close();
        inputStream.close();
    }

    /**
     * 进行文件拷贝,利用带缓冲的字节流。
     *
     * @param srcFile
     * @param destFile
     */
    // CopyTest02。
    public static void copyFileByBuffer(File srcFile, File destFile) throws IOException {
        if (!srcFile.exists()) {
            throw new IllegalArgumentException("文件" + srcFile + "不存在。");
        }
        if (!srcFile.isFile()) {
            throw new IllegalArgumentException(srcFile + "不是文件。");
        }
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFile));
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFile));
        int c;
        while ((c = bufferedInputStream.read()) != -1) {
            bufferedOutputStream.write(c);
            bufferedOutputStream.flush();// 刷新缓冲区。
        }

        bufferedOutputStream.close();
        bufferedInputStream.close();
    }
}

package com.geek.dataIO;

import com.geek.io.IOUtil;

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

public class DataInStreamDemo {

    public static void main(String[] args) throws IOException {
        String file = "geek-file/dos.dat";
        IOUtil.printHex(file);
        System.out.println();

        DataInputStream dataInputStream = new DataInputStream(new FileInputStream(file));
        int i = dataInputStream.readInt();
        System.out.println("i = " + i);
        // 10
        i = dataInputStream.readInt();
        System.out.println("i = " + i);
        // -10
        long l = dataInputStream.readLong();
        System.out.println("l = " + l);
        // 10
        double v = dataInputStream.readDouble();
        System.out.println("v = " + v);
        // 10.5
        String utf = dataInputStream.readUTF();
        System.out.println("utf = " + utf);
        // 中国
        dataInputStream.close();
    }
}



字节缓冲流~BufferedInputStream & BufferedOutputStream。

为 io 提供了带缓冲区的操作。一般打开文件进行定稿或读取操作时都会加上缓冲。这种流模式提高了 IO 的性能。

eg. 从应用程序中把输入放入文件相当于将一缸水倒入到另一个缸中。
FileOutputStream -> write(); 方法相当于一滴一滴地把水转移过去。
DataOutputStream -> writeXxx(); 方法会方便一些,相当于一瓢一瓢把水转移过去。
BufferedOutputStream -> write(); 方法会更方便,相当于一瓢一瓢先把水转移到一个桶中,再把一桶水转移到另一缸。

package com.geek.io;

import java.io.*;

public class IOUtil {

    /**
     * 进行文件拷贝,利用带缓冲的字节流。
     *
     * @param srcFile
     * @param destFile
     */
    // CopyTest02。
    public static void copyFileByBuffer(File srcFile, File destFile) throws IOException {
        if (!srcFile.exists()) {
            throw new IllegalArgumentException("文件" + srcFile + "不存在。");
        }
        if (!srcFile.isFile()) {
            throw new IllegalArgumentException(srcFile + "不是文件。");
        }
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFile));
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFile));
        int c;
        while ((c = bufferedInputStream.read()) != -1) {
            bufferedOutputStream.write(c);
            bufferedOutputStream.flush();// 刷新缓冲区。
        }

        bufferedOutputStream.close();
        bufferedInputStream.close();
    }
}

  • test。
package com.geek.out;

import com.geek.io.IOUtil;

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

public class CopyTest02 {

    public static void main(String[] args) {
        try {
            IOUtil.copyFileByBuffer(new File("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt"), new File("/home/geek/IdeaProjects/geek_file/geek-file/geek01.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package com.geek.io;

import java.io.*;

public class IOUtil {

    /**
     * 单字节,不带缓冲进行文件拷贝。
     *
     * @param srcFile
     * @param destFile
     * @throws IOException
     */
    // CopyTest03。
    public static void copyFileByByte(File srcFile, File destFile) throws IOException {
        if (!srcFile.exists()) {
            throw new IllegalArgumentException("文件" + srcFile + "不存在。");
        }
        if (!srcFile.isFile()) {
            throw new IllegalArgumentException(srcFile + "不是文件。");
        }
        FileInputStream fileInputStream = new FileInputStream(srcFile);
        FileOutputStream fileOutputStream = new FileOutputStream(destFile);
        int c;
        while ((c = fileInputStream.read()) != -1) {
            fileOutputStream.write(c);
            fileOutputStream.flush();// 刷新缓冲区。
        }

        fileOutputStream.close();
        fileInputStream.close();
    }
}

  • test。
package com.geek.out;

import com.geek.io.IOUtil;

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

public class CopyTest02 {

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        try {
            IOUtil.copyFileByByte(new File("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt"), new File("/home/geek/IdeaProjects/geek_file/geek-file/geek02.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println((end + start) + " ms...");
    }
}



字符流。

编码问题。
文本 & 文本文件。
  • Java 文本(char)是 16 位无符号整数,是字符的 unicode 编码(双字节编码)。

  • 文件是 byte byte byte 的数据序列。

  • 文本文件是文本(char)序列按照某种编码方案(utf-8, utf-16be, gbk)序列化为 byte 的存储结果。

  • 字符流(Reader,Write)

字符的处理,一次处理一个字符。

字符的底层仍然是基本的字节序列。



字符流的基本实现~操作文本文件。
字符字节转换流~InputStreamReader & OutputSreamWriter。
  • InputStreamReader。

完成 byte 流解析为 char 流。按照编码解析。

  • OutputSreamWriter。

提供 char 流 ——> byte 流。按照编码处理。

  • 读取。
package com.geek.stream;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class InputStreamReaderAndOutputStreamWriterDemo {

    public static void main(String[] args) throws IOException {
        InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt"), "utf-8");// 默认项目编码.
//        int c;
//        while ((c = inputStreamReader.read()) != -1) {
//            System.out.print((char) c);
//            // Hello, Geek.
//        }

        char[] buffer = new char[8 * 1024];
        int c;
        // 从 inputStreamReader 中批量读取字节,放入到 buf 字节数组中,
        // 从第 0 个位置开始,最多放 buf.length 个。
        // 返回的是读到的字符个数。
        while ((c = inputStreamReader.read(buffer, 0, buffer.length)) != -1) {
            String s = new String(buffer, 0, c);
            System.out.print(s);
        }
    }
}

  • 读取 + 复制。
package com.geek.stream;

import java.io.*;

public class InputStreamReaderAndOutputStreamWriterDemo {

    public static void main(String[] args) throws IOException {
        InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt"), "utf-8");// 默认项目编码.

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek03.txt"), "utf-8");// 默认项目编码.


//        int c;
//        while ((c = inputStreamReader.read()) != -1) {
//            System.out.print((char) c);
//            // Hello, Geek.
//        }

        char[] buffer = new char[8 * 1024];
        int c;
        // 从 inputStreamReader 中批量读取字节,放入到 buf 字节数组中,
        // 从第 0 个位置开始,最多放 buf.length 个。
        // 返回的是读到的字符个数。
        while ((c = inputStreamReader.read(buffer, 0, buffer.length)) != -1) {
            String s = new String(buffer, 0, c);
            System.out.print(s);
            outputStreamWriter.write(buffer, 0, c);
            outputStreamWriter.flush();
        }

        outputStreamWriter.close();
        inputStreamReader.close();
    }
}



字符流~文件读写流~FileReader & FileWriter。
package com.geek.charstream;

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

public class FileReaderANdFileWriterDemo {

    public static void main(String[] args) throws IOException {
        FileReader fileReader = new FileReader("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt");

        FileWriter fileWriter = new FileWriter("/home/geek/IdeaProjects/geek_file/geek-file/geek04.txt");
        FileWriter fileWriter1 = new FileWriter("/home/geek/IdeaProjects/geek_file/geek-file/geek04.txt", true);

        char[] buffer = new char[2056];
        int c;
        while ((c = fileReader.read()) != -1) {
            fileWriter.write(buffer, 0, c);
            fileWriter.flush();
        }
        fileWriter.close();
        fileReader.close();
    }
}



字符流过滤器~BufferedReader & BufferedWriter。

package com.geek.charstream;

import java.io.*;

public class BufferedReaderAndBufferedWriterOrPrintWriterDemo {

    public static void main(String[] args) throws IOException {
        // 对文件进行读写操作。
        BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(
                        new FileInputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt")
                ));

        BufferedWriter bufferedWriter = new BufferedWriter(
                new OutputStreamWriter(
                        new FileOutputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek5.txt")
                ));

        String line;
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);// 并不能识别换行。
            bufferedWriter.write(line);
            // 单独换行。
            bufferedWriter.newLine();
            bufferedWriter.flush();
        }
        bufferedWriter.close();
        bufferedReader.close();
    }
}

PrintWriter。
package com.geek.charstream;

import java.io.*;

public class BufferedReaderAndBufferedWriterOrPrintWriterDemo {

    public static void main(String[] args) throws IOException {
        // 对文件进行读写操作。
        BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(
                        new FileInputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek.txt")
                ));

//        BufferedWriter bufferedWriter = new BufferedWriter(
//                new OutputStreamWriter(
//                        new FileOutputStream("/home/geek/IdeaProjects/geek_file/geek-file/geek5.txt")
//                ));

        PrintWriter printWriter = new PrintWriter("/home/geek/IdeaProjects/geek_file/geek-file/geek6.txt.txt");

        String line;
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);// 并不能识别换行。

//            bufferedWriter.write(line);
//            // 单独换行。
//            bufferedWriter.newLine();
//            bufferedWriter.flush();

            printWriter.println(line);
            printWriter.flush();
        }

//        bufferedWriter.close();
        printWriter.close();
        bufferedReader.close();
    }
}

  • 构造。
    public PrintWriter(OutputStream out, boolean autoFlush) {
        this(out, autoFlush, Charset.defaultCharset());
    }



对象的序列化和反序列化。

  • 对象的序列化,就是将 Object 转化为 byte 序列,反之叫对象的反序列化。

  • 序列化流(ObjectOutputStream),是过滤流~writeObject();。
    反列化流(ObjectInputStream),readObject();。



序列化接口~Serializable。

对象必须实现序列化接口,才能进行序列化,否则将出现异常。

这个接口没有任何方法,只是一个标准。

package com.geek.serialzable;

public class Student {
    
    private String stuno;
    private String stuname;
    private int stuage;

    public Student() {
    }

    public Student(String stuno, String stuname, int stuage) {
        this.stuno = stuno;
        this.stuname = stuname;
        this.stuage = stuage;
    }

    public String getStuno() {
        return stuno;
    }

    public void setStuno(String stuno) {
        this.stuno = stuno;
    }

    public String getStuname() {
        return stuname;
    }

    public void setStuname(String stuname) {
        this.stuname = stuname;
    }

    public int getStuage() {
        return stuage;
    }

    public void setStuage(int stuage) {
        this.stuage = stuage;
    }
}

package com.geek.serializable;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/**
 * 序列化。
 */
public class ObjectSerializeDemo {

    public static void main(String[] args) throws IOException {
        String file = "geek-file/obj.dat";

        // 对象的序列化。
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
        Student student = new Student("10001", "张三", 20);
        objectOutputStream.writeObject(student);
        objectOutputStream.flush();
        objectOutputStream.close();

        // Exception in thread "main" java.io.NotSerializableException: com.geek.serializable.Student
    }
}

Exception in thread “main” java.io.NotSerializableException: com.geek.serializable.Student

public class Student implements Serializable {

网络传输也需要 implements Serializable。



反序列化。
package com.geek.serializable;

import java.io.*;

/**
 * 序列化 & 反序列化。
 */
public class ObjectSerializeDemo {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
//        objectOutputStream();// 序列化。
        objectInputStream();// 反序列化。
    }

    private static void objectOutputStream() throws IOException {
        String file = "geek-file/obj.dat";

        // 对象的序列化。
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
        Student student = new Student("10001", "张三", 20);
        objectOutputStream.writeObject(student);
        objectOutputStream.flush();
        objectOutputStream.close();

        // Exception in thread "main" java.io.NotSerializableException: com.geek.serializable.Student
    }

    private static void objectInputStream() throws IOException, ClassNotFoundException {
        String file = "geek-file/obj.dat";

        // 对象的反序列化。
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
        Object o = objectInputStream.readObject();
        System.out.println("o = " + o);
        Student student = (Student) o;
        System.out.println("student = " + student);
        objectInputStream.close();
    }
}



transient。

adj. 短暂的;转瞬即逝的;倏忽;暂住的;过往的;临时的
n. 暂住某地的人;过往旅客;临时工

该元素不会进行 jvm 默认的序列化。

package com.geek.serializable;

import java.io.*;

/**
 * 序列化 & 反序列化。
 */
public class ObjectSerializeDemo {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
//        objectOutputStream();// 序列化。
        objectInputStream();// 反序列化。
        // 增加 transient 后不重新序列化。(修改 Class Student)。
        // Exception in thread "main" java.io.InvalidClassException: com.geek.serializable.Student; local class incompatible: stream classdesc serialVersionUID = 2455853989772884997, local class serialVersionUID = -9089186181677793641

//        private transient int stuage;// 该元素不会进行 jvm 默认的序列化。
        // student = Student{stuno='10001', stuname='张三', stuage=0}
    }

    private static void objectOutputStream() throws IOException {
        String file = "geek-file/obj.dat";

        // 对象的序列化。
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
        Student student = new Student("10001", "张三", 20);
        objectOutputStream.writeObject(student);
        objectOutputStream.flush();
        objectOutputStream.close();

        // Exception in thread "main" java.io.NotSerializableException: com.geek.serializable.Student
    }

    private static void objectInputStream() throws IOException, ClassNotFoundException {
        String file = "geek-file/obj.dat";

        // 对象的反序列化。
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
        Object o = objectInputStream.readObject();
        System.out.println("o = " + o);
        Student student = (Student) o;
        System.out.println("student = " + student);
        objectInputStream.close();
    }
}



也可以自己序列化。

参考 ArrayList 源码。

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    private static final long serialVersionUID = 8683452581122892189L;
    private static final int DEFAULT_CAPACITY = 10;
    private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
    transient Object[] elementData;
    private int size;
    private static final int MAX_ARRAY_SIZE = 2147483639;

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {

    private void writeObject(ObjectOutputStream s) throws IOException {
        int expectedModCount = this.modCount;
        s.defaultWriteObject();
        s.writeInt(this.size);

        for(int i = 0; i < this.size; ++i) {
            s.writeObject(this.elementData[i]);
        }

        if (this.modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
  • 序列化。
package com.geek.serializable;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Student implements Serializable {

    private String stuno;
    private String stuname;
    private transient int stuage;// 该元素不会进行 jvm 默认的序列化。

    private void writeObject(ObjectOutputStream s) throws IOException {
        s.defaultWriteObject();// 把 jvm 能默认序列化的元素进行序列化操作。
        s.writeInt(this.stuage);// 自己完成 stuage 的序列化。

    }
    
    public Student() {
    }

    public Student(String stuno, String stuname, int stuage) {
        this.stuno = stuno;
        this.stuname = stuname;
        this.stuage = stuage;
    }

    public String getStuno() {
        return stuno;
    }

    public void setStuno(String stuno) {
        this.stuno = stuno;
    }

    public String getStuname() {
        return stuname;
    }

    public void setStuname(String stuname) {
        this.stuname = stuname;
    }

    public int getStuage() {
        return stuage;
    }

    public void setStuage(int stuage) {
        this.stuage = stuage;
    }

    @Override
    public String toString() {
        return "Student{" +
                "stuno='" + stuno + '\'' +
                ", stuname='" + stuname + '\'' +
                ", stuage=" + stuage +
                '}';
    }
}

  • 反序列化。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {

    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        s.readInt();
        if (this.size > 0) {
            SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, this.size);
            Object[] elements = new Object[this.size];

            for(int i = 0; i < this.size; ++i) {
                elements[i] = s.readObject();
            }

            this.elementData = elements;
        } else {
            if (this.size != 0) {
                throw new InvalidObjectException("Invalid size: " + this.size);
            }

            this.elementData = EMPTY_ELEMENTDATA;
        }

    }
package com.geek.serializable;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Student implements Serializable {

    private String stuno;
    private String stuname;
    private transient int stuage;// 该元素不会进行 jvm 默认的序列化。

    private void writeObject(ObjectOutputStream s) throws IOException {
        s.defaultWriteObject();// 把 jvm 能默认序列化的元素进行序列化操作。
        s.writeInt(this.stuage);// 自己完成 stuage 的序列化。

    }

    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
        s.defaultReadObject();// 把虚拟机默认能反序列化的元素进行反序列化操作。
        this.stuage = s.readInt();// 自己完成 stuage 的反序列化操作。

    }

    public Student() {
    }

    public Student(String stuno, String stuname, int stuage) {
        this.stuno = stuno;
        this.stuname = stuname;
        this.stuage = stuage;
    }

    public String getStuno() {
        return stuno;
    }

    public void setStuno(String stuno) {
        this.stuno = stuno;
    }

    public String getStuname() {
        return stuname;
    }

    public void setStuname(String stuname) {
        this.stuname = stuname;
    }

    public int getStuage() {
        return stuage;
    }

    public void setStuage(int stuage) {
        this.stuage = stuage;
    }

    @Override
    public String toString() {
        return "Student{" +
                "stuno='" + stuno + '\'' +
                ", stuname='" + stuname + '\'' +
                ", stuage=" + stuage +
                '}';
    }
}

// student = Student{stuno=‘10001’, stuname=‘张三’, stuage=0}
// student = Student{stuno=‘10001’, stuname=‘张三’, stuage=20}

禁止某些字段序列化可提高程序效率。

ArrayList 手动对有效元素进行序列化。

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    private static final long serialVersionUID = 8683452581122892189L;
    private static final int DEFAULT_CAPACITY = 10;
    private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
    transient Object[] elementData;
    private int size;
    private static final int MAX_ARRAY_SIZE = 2147483639;


    private void writeObject(ObjectOutputStream s) throws IOException {
        int expectedModCount = this.modCount;
        s.defaultWriteObject();
        s.writeInt(this.size);

        for(int i = 0; i < this.size; ++i) {
            s.writeObject(this.elementData[i]);
        }

        if (this.modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        s.readInt();
        if (this.size > 0) {
            SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, this.size);
            Object[] elements = new Object[this.size];

            for(int i = 0; i < this.size; ++i) {
                elements[i] = s.readObject();
            }

            this.elementData = elements;
        } else {
            if (this.size != 0) {
                throw new InvalidObjectException("Invalid size: " + this.size);
            }

            this.elementData = EMPTY_ELEMENTDATA;
        }

    }


序列化中子父类构造函数的问题。

package com.geek.serializable;

import java.io.*;

/**
 * 序列化 & 反序列化。
 */
public class ObjectSerializeDemo02 {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
//        oos();// 序列化。
        ois();// 反序列化。
    }

    // 序列化。
    private static void oos() throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(
//                new FileOutputStream("geek-file/obj1.dat"));
                new FileOutputStream("geek-file/obj2.dat"));
//        Foo2 foo2 = new Foo2();
        Bar2 bar2 = new Bar2();
//        objectOutputStream.writeObject(foo2);
        objectOutputStream.writeObject(bar2);
        objectOutputStream.flush();
        objectOutputStream.close();
    }

    // 反序列化是否递归调用父类的构造函数。
    // Foo 2。
    //      foo...
    //      Foo1...
    //      Foo2...
    //      foo2 = com.geek.serializable.Foo2@5056dfcb

    // Bar 2。
    //      (Bar 1 实现序列化接口)。
    //      Bar...
    //      bar2 = com.geek.serializable.Bar2@337d0578
    //
    // Bar 没有显式 implements Serializable。
    //  构造方法被调用。
    // 
    // 如果 Bar 2 显式 implements Serializable。
    // 其他没有。
    //      Bar...
    //      Bar1...
    //      bar2 = com.geek.serializable.Bar2@13a57a3b
    // ==> 
    // 对自类对象进行反序列化操作时,
    // 如果其父类没有实现序列化接口,
    // 那么其父类的构造函数会被调用。

    // 反序列化。
    private static void ois() throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(
//                new FileInputStream("geek-file/obj1.dat")
                new FileInputStream("geek-file/obj2.dat")
        );
//        Foo2 foo2 = (Foo2) objectInputStream.readObject();
        Bar2 bar2 = (Bar2) objectInputStream.readObject();
//        System.out.println("foo2 = " + foo2);
        System.out.println("bar2 = " + bar2);
        objectInputStream.close();
    }
}

// 一个类实现了序列化接口,其自类都可以进行序列化。


class Foo implements Serializable {
    public Foo() {
        System.out.println("foo...");
    }
}

class Foo1 extends Foo {
    public Foo1() {
        System.out.println("Foo1...");
    }
}

class Foo2 extends Foo1 {
    public Foo2() {
        System.out.println("Foo2...");
    }
}

class Bar {
    public Bar() {
        System.out.println("Bar...");
    }
}

class Bar1 extends Bar {
    public Bar1() {
        System.out.println("Bar1...");
    }
}

class Bar2 extends Bar1 implements Serializable {
    public Bar2() {
        System.out.println("Bar2...");
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lyfGeek

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值