Java文件与IO流

File类

  • java.io.File 类是文件和目录,路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作
  • File可以表示目录,也可以表示文件

构造方法

方法名 作用
public File(String pathname) 通过给定的路径名,字符串转换为抽象路径名来创建新的 File实例
public File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例,根据父路径加子路径的意思
public File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例
public class Demo {
    public static void main(String[] args) {
        File file = new File("F:/IdeaProjectTwo/IT6666-Web/vue.config.js");
        System.out.println(file);

        File fileTwo = new File("F:/IdeaProjectTwo/IT6666-Web", "/vue.config.js");
        System.out.println(fileTwo);

        File fileThree = new File(file, "/a.txt");
        System.out.println(fileThree);
    }

}

🐤注意事项

  • 一个 File 对象代表硬盘中实际存在的一个文件或者目录
  • 无论该路径下是否存在文件或者目录,都不影响 File 对象的创建

File类常用方法

方法名 作用
public String getAbsolutePath() 返回此 File 的绝对路径名字符串,返回绝对路径
public String getPath() 将此 File 转换为路径名字符串获取路径
public String getName() 返回由此 File 表示的文件或目录的名称
public long length() 返回由此 File 表示的文件的长度
public class Demo {
    public static void main(String[] args) {
        File file = new File("F:/IdeaProjectTwo/IT6666-Web/vue.config.js");
        System.out.println(file.getAbsolutePath());

        File fileTwo = new File("F:/IdeaProjectTwo/IT6666-Web", "/vue.config.js");
        System.out.println(fileTwo.getPath());

        File fileThree = new File(file, "/a.txt");
        System.out.println(fileThree.getName());
        System.out.println(file.length());
    }

}

绝对路径和相对路径

  • 绝对路径:从盘符开始的路径,这是一个完整的路径
  • 相对路径:相对于项目目录的路径,不是从盘符开始,从项目名称的位置开始,不带项目名称
public class Demo {
    public static void main(String[] args) {
        File file = new File("F:/IdeaProjectTwo/IT6666-Web/vue.config.js");
        System.out.println(file);

        File fileTwo = new File("src/a.text");
        System.out.println(fileTwo);
    }

}

判断相关方法

方法名 作用
public boolean exists() 用于判断此 File 表示的文件或目录是否实际存在
public boolean isDirectory() 此 File 表示的是否为目录
public boolean isFile() 此 File 表示的是否为文件
public class Demo {
    public static void main(String[] args) {
        File file = new File("F:/IdeaProjectTwo/IT6666-Web/vue.config.js");
        System.out.println(file.exists());
        System.out.println(file.isDirectory());
        System.out.println(file.isFile());

        File fileTwo = new File("F:/IdeaProjectTwo/IT6666-Web");
        System.out.println(fileTwo.exists());
        System.out.println(fileTwo.isDirectory());
        System.out.println(fileTwo.isFile());
    }
}

创建删除相关方法

方法名 作用
public boolean createNewFile() 当且仅当具有该名称的文件尚不存在时,创建一个新的空文件
public boolean delete() 删除由此 File 表示的文件或目录
public boolean mkdir() 创建由此 File 表示的目录
public boolean mkdirs() 创建由此 File 表示的目录,包括任何必需但不存在的父目录
public class Demo {
    public static void main(String[] args) throws Exception {
        File file = new File("BNTang.txt");
        System.out.println(file.exists());
        System.out.println(file.createNewFile());
        System.out.println(file.exists());

        File fileTwo = new File("newDir");
        System.out.println(fileTwo.exists());
        System.out.println(fileTwo.mkdir());
        System.out.println(fileTwo.exists());

        File fileThree = new File("newDira\\newDirb");
        System.out.println(fileThree.mkdir());
        System.out.println(fileThree.mkdirs());

        System.out.println(file.delete());
        System.out.println(fileTwo.delete());
        System.out.println(fileThree.delete());
    }
}

目录遍历

方法名 作用
public String[] list() 返回一个 String数组,表示该 File 目录中的所有子文件或目录
public File[] listFiles() 返回一个 File 数组,表示该 File 目录中的所有的子文件或目录
public class Demo {
    public static void main(String[] args) throws Exception {
        File dir = new File("F:\\upload");
        String[] names = dir.list();
        for (String name : names) {
            System.out.println(name);
        }

        File[] files = dir.listFiles();
        for (File file : files) {
            System.out.println(file);
        }
    }
}

🐤注意事项

  • 调用 listFiles 方法的 File 对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历

递归

  • 指在当前方法内调用自己的这种现象
  • 调用时,要有一个退出的条件,否则会死循环,一直调用
  • 就是一种方法的调用,方法自己调用自己,如果没有出口的话,就变成了死循环了
public class Demo {
    static int num = 10;

    public static void main(String[] args) throws Exception {
        System.out.println("main");
        num--;
        if (num == 0) return;
        main(args);
    }
}

🐤计算1 - n的和

public class Demo {
    public static void main(String[] args) throws Exception {
        int sum = getSum(3);
        System.out.println(sum);
    }

    /**
     * 传入一个数返回1到这个数的和
     * @param num   n
     * @return      1 - n的结果
     */
    private static int getSum(int num) {
        if (num == 1){
            return 1;
        }
        return num + getSum(num-1); 
    }
}

🦄文件搜索

  • 搜索指定目录下指定扩展名的文件
  • 例如:D盘下 aaa目录中所有的 .txt文件
public class Demo {

    public static void main(String[] args) throws Exception {
        printDir(new File("F:\\IdeaProjectTwo\\IT6666-Web"));
    }

    public static void printDir(File dir) {
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                if (file.getName().endsWith(".txt")) {
                    System.out.println("文件名:" + file.getAbsolutePath());
                }
            } else {
                printDir(file);
            }
        }
    }
}

🐸多级目录树形结构显示

public class Demo {

    public static void main(String[] args) throws Exception {
        printDir(new File("F:\\upload"), 0);
    }

    public static void printDir(File dir, int level) {

        if (level != 0) {
            printSpace(level);
            for (int i = 0; i < level; i++) {
                if (i == 0) {
                    System.out.print("|-");
                } else {
                    System.out.print("-");
                }
            }
        }

        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                if (file.getName().endsWith(".txt")) {
                    System.out.println("文件名:" + file.getAbsolutePath());
                }
            } else {
                printDir(file, level + 1);
            }
        }
    }

    private static void printSpace(int level) {
        StringBuilder str = new StringBuilder();
        for (int i = 0; i < level; i++) {
            str.append("  ");
        }
        System.out.print(str);
    }
}

🐤递归求阶乘

public class Demo {

    public static void main(String[] args) throws Exception {
        int num = getJieCheng(4);
        System.out.println(num);
    }

    private static int getJieCheng(int num) {
        if (num == 1) {
            return 1;
        }
        return num * getJieCheng(num - 1);
    }
}

🐤斐波那契数列

  • 斐波那契数列:又称黄金分割数列、因数学家列昂纳多 • 斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为兔子数列
  • 指的是这样一个数列:1、1、2、3、5、8、13、21、34、…
  • 求数列的第6位的值是多少

递归分析

  • 当位数为1和2时,当前返回的值应该是1
  • 当位数为3时,返回值应该是2=1+1
  • 当位数为4时,返回值是3=2+1
  • 当位数为5时,返回值是5=3+2
  • 大于等于3的情况下,当前位数(n)的数值是 f(n - 1) + f(n - 2)

public class Demo {

    public static void main(String[] args) {
        int f = f(3);
        System.out.println(f);
        for (int i = 1; i <= 15; i++) {
            System.out.print(f(i) + "\t");
        }
    }

    public static int f(int n) {
        if (n == 1 || n == 2)
            return 1;
        else
            return f(n - 1) + f(n - 2);
    }
}

IO流

  • 与计算机之间数据的传输,可以看做是一种数据的流动
  • 以内存为基准,分为 输入input 和 输出 output ,流向内存是输入流,内存流出是的输出流
  • 可以理解把程序当中的数据保存到电脑磁盘,为输出流,把电脑磁盘当中的数据加载到程序当中为输入流

IO流的分类

  • 根据数据的流向分
    • 输入流:把数据从 其他设备 上读取到 内存 中
    • 输出流:把数据从 内存 中写出到 其他设备 上
  • 根据数据的类型分
    • 字节流:以字节为单位,读写数据
    • 字符流:以字符为单位,读写数据

顶级父类

  • 字节输入流:InputStream
  • 字节输出流:OutputStream
  • 字符输入流:Reader
  • 字符输出流:Writer

字节流

  • 一切文件数据(文本、图片、视频等)在存储时,都是以二进制的数字的形式保存的,都一个一个的字节
  • 在传输时也是使用字节进行传输,我们称之为字节流
  • 字节流可以传输任意文件数据
  • 无论使用什么样的流对象,底层传输的始终为二进制数据

字节输出流

  • OutputStream:字节输出流
    • java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地
方法名 作用
public void close() 关闭此输出流并释放与此流相关联的任何系统资源,close方法,当完成流的操作时,必须调用此方法,释放系统资源
public void flush() 刷新此输出流,并强制任何缓冲的输出字节被写出
public void write(byte[] b) 将 b.length 字节从指定的字节数组写入此输出流
public void write(byte[] b, int off, int len) 从指定的字节数组写入 len 字节,从偏移量 off 开始输出到此输出流
public abstract void write(int b) 将指定的字节输出流
  • OutputStream 有很多子类,以上方法子类都可以调用

  • FileOutputStream类

    • java.io.FileOutputStream 类是文件输出流,用于将数据写出到文件,继承自OutputStream

构造方法

方法名 作用
public FileOutputStream(File file) 创建文件输出流写入到指定的 File 对象表示的文件
public FileOutputStream(String name) 创建文件输出流以指定的名称写入文件
public class Demo {

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

        File file = new File("a.txt");
        FileOutputStream fos = new FileOutputStream(file);
        FileOutputStream fos2 = new FileOutputStream("b.txt");
    }
}

🐤注意事项

  • 当你创建一个流对象时,必须传入一个文件路径
  • 该路径下,如果没有这个文件,会创建该文件。如果有这个文 件,会清空这个文件的数据,写入新的信息

write(int b)

  • 写出字节
  • 每次只可以写出一个字节数据
public class Demo {

    public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.close();
    }
}

🐸注意事项

  1. 虽然参数为 int 类型四个字节,但是只会保留一个字节的信息写出
  2. 流操作完毕后,必须释放系统资源,调用 close 方法,千万记得

write(byte[] b)

  • 写出字节数组
  • 可以通过 getBytes 方法把汉字转成字节数组
public class Demo {

    public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileOutputStream fos = new FileOutputStream(file);
        byte[] b = "灰灰".getBytes();
        fos.write(b);
        fos.close();
    }
}

write(byte[] b, int off, int len)

  • 写出指定长度的字节数组
  • 每次写出从 off 索引开始,len个字节
public class Demo {

    public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileOutputStream fos = new FileOutputStream(file);
        byte[] b = "abcde".getBytes();
        fos.write(b, 2, 2);
        fos.close();
    }
}

数据追加续写

  • 每次程序运行,创建输出流对象,都会清空目标文件中的数据
方法名 作用
public FileOutputStream(File file, boolean append) 创建文件输出流写入到指定的 File对象表示的文件
public FileOutputStream(String name, boolean append) 创建文件输出流以指定的名称写入文件
  • 参数介绍
    • 参数中都需要传入一个 boolean类型 的值
    • true 表示追加数据
    • false 表示清空原有数据
public class Demo {

    public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileOutputStream fos = new FileOutputStream(file, true);
        byte[] b = "abcde".getBytes();
        fos.write(b, 2, 2);
        fos.close();
    }
}

写出换行

  • Windows系统里,换行符号是\r\n
public class Demo {

    public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileOutputStream fos = new FileOutputStream(file, true);
        byte[] b = "abcde".getBytes();
        fos.write(b, 2, 2);
        fos.write("\r\n".getBytes());
        fos.write(b, 2, 2);
        fos.close();
    }
}

字节输入流

  • java.io.InputStream
    • java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入 流的基本共性功能方法

基本方法

方法名 作用
public void close() 关闭此输入流并释放与此流相关联的任何系统资源
public abstract int read() 从输入流读取数据的下一个字节
public int read(byte[] b) 从输入流中读取一些字节数,并将它们存储到字节数组 b 中

FileInputStream

  • java.io.FileInputStream 类是文件输入流,从文件中读取字节

构造方法

方法名 作用
FileInputStream(File file) file 是需要读取的文件路径或者是文件对象
FileInputStream(String name) 可以传入一个字符串的路径创建字节输入流
public class Demo {

    public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileInputStream fileInputStream = new FileInputStream(file);
        FileInputStream fileInputStream1 = new FileInputStream("a.txt");
    }
}

🐤注意事项

  • 当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出 FileNotFoundException 异常

读取字节数据

  • read()方法:每次可以读取一个字节的数据,提升为 int 类型,读取到文件末尾,返回-1
public class Demo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("a.txt");
        int read = fis.read();
        System.out.println((char) read);
        int read2 = fis.read();
        System.out.println((char) read2);
        int read3 = fis.read();
        System.out.println((char) read3);
        int read4 = fis.read();
        System.out.println((char) read4);
        int read5 = fis.read();
        System.out.println(read5);
    }
}

循环的方式优化

public class Demo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("a.txt");
        int b;
        while ((b = fis.read()) != -1) {
            System.out.println((char) b);
        }
    }
}
  • read(byte[] b)方法:每次读取 b 个长度到字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1
public class Demo {
    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("a.txt");
        int len;
        byte[] b = new byte[2];
        while ((len = fis.read(b)) != -1) {
            System.out.println(new String(b));
        }
        fis.close();
    }
}
  • 复制图片
public class Demo {
    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("D:\\logo.jpg");
        FileOutputStream fos = new FileOutputStream("copyLogo.jpg");
        byte[] b = new byte[1024];
        int len;
        while ((len = fis.read(b)) != -1) {
            fos.write(b, 0, len);
        }
        fos.close();
        fis.close();
    }
}

字符流

  • 当使用字节流读取文本文件时,可能会有一个小问题
  • 就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储
  • 所以 Java 提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件

Reader类

  • java.io.Reader 抽象类是表示用于读取,字符流的所有类的超类,可以读取字符信息到内存中
  • 它定义了字符输入流的基本共性功能方法

基本方法

方法名 作用
public void close() 关闭此流并释放与此流相关联的任何系统资源
public int read() 从输入流读取一个字符
public int read(char[] cbuf) 从输入流中读取一些字符,并将它们存储到字符数组 cbuf 中

FileReader类

  • java.io.FileReader 类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区

构造方法

方法名 作用
FileReader(File file) 传入一个文件对象创建一个字符读取流
FileReader(String fileName) 传入一个字符串路径创建一个字符读取流

🐤注意事项

  • 当你创建一个流对象时,必须传入一个文件路径。类似于 FileInputStream

读取字符数据

  • read方法:每次可以读取一个字符的数据,提升为 int 类型,读取到文件末尾,返回-1
public class Demo {
    public static void main(String[] args) throws Exception {
        FileReader fr = new FileReader("a.txt");
        int b;
        while ((b = fr.read()) != -1) {
            System.out.println((char) b);
        }
        fr.close();
    }
}
  • read(char[] cbuf):每次读取 b 个长度字符到数组中,返回读取到的有效字符个数, 读取到末尾时,返回-1
public class Demo {
    public static void main(String[] args) throws Exception {
        FileReader fr = new FileReader("a.txt");
        int len;
        char[] chars = new char[2];
        while ((len = fr.read(chars)) != -1) {
            System.out.println(new String(chars));
        }
        fr.close();
    }
}
  • 使用上面这种方法会发现,如果是5个字符的时候会多读取一个,是因为 chars数组中内容没有被清空
  • 指定有效个数
public class Demo {
    public static void main(String[] args) throws Exception {
        FileReader fr = new FileReader("a.txt");
        int len;
        char[] chars = new char[2];
        while ((len = fr.read(chars)) != -1) {
            System.out.println(new String(chars, 0, len));
        }
        fr.close();
    }
}

FileWriter类

  • java.io.FileWriter 类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区

构造方法

方法名 作用
FileWriter(File file) 传入一个文件对象创建一个字符输出流
FileWriter(String fileName) 传入一个字符串路径创建一个字符输出流
  • 当你创建一个流对象时,必须传入一个文件路径,类似于 FileOutputStream
  • write(int b):每次可以写出一个字符数,如果不关闭也就是释放资源,数据只是保存到缓冲区,并未保存到文件
public class Demo {
    public static void main(String[] args) throws Exception {
        FileWriter fw = new FileWriter("a.txt", true);
        fw.write(97);
        fw.write('b');
        fw.write(30000);
        fw.close();
    }
}
  • 关闭和刷新
    • 刷新:因为内置缓冲区的原因,如果不关闭输出流,无法将字符写到文件中。但是关闭了流对象,还想在写入就无法继续写出数据了,如果我们既想写出数据,又想继续使用流,就需要 flush 方法了
    • flush:刷新缓冲区,流对象可以继续使用
    • close:关闭流,释放系统资源。关闭前会刷新缓冲区
public class Demo {
    public static void main(String[] args) throws Exception {
        FileWriter fw = new FileWriter("a.txt", true);
        fw.write(97);
        fw.write('b');
        fw.write(30000);
        fw.flush();
        fw.write('d');
        fw.close();
    }
}
  • write(char[] cbuf):每次可以写出字符数组中的数据
public class Demo {
    public static void main(String[] args) throws Exception {
        FileWriter fw = new FileWriter("a.txt");
        String msg = "IT6666灰灰";
        char[] chars = msg.toCharArray();
        fw.write(chars);
        fw.close();
    }
}
  • write(String str, int off, int len):每次可以写出字符数组中的数据
public class Demo {
    public static void main(String[] args) throws Exception {
        FileWriter fw = new FileWriter("a.txt");
        String msg = "灰灰";
        char[] chars = msg.toCharArray();
        fw.write(chars, 2, 2);
        fw.close();
    }
}

异常处理

JDK7之前异常处理中释放资源的是需要自己手动来释放的

public class Demo {
    public static void main(String[] args) throws Exception {
        FileWriter fw = null;
        try {
            fw = new FileWriter("a.txt");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

JDK7之后就不用自己来手动释放了,JDK7之后的异常处理会自动帮我们释放只需要把需要释放的资源写在try()的括号中即可

格式

try(创建流对象语句,如果多个使用 ; 隔开){
	代码
} catch(IOException e){
	e.printStackTrace();
}
  • 该语句确保了每个资源在语句结束时自动关闭释放资源
public class Demo {
    public static void main(String[] args) throws Exception {
        try (FileWriter fw = new FileWriter("a.txt"); FileReader fr = new FileReader("a.txt")) {
            fw.write("it6666.top");
            int read = fr.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

缓冲流

  • 缓冲流,也叫高效流,是对4个基本的 File*** 流的增强
  • 所以也是4个流,按照数据类型分类
    • 字节缓冲流: BufferedInputStream , BufferedOutputStream
    • 字符缓冲流: BufferedReader,BufferedWriter

基本原理

  • 缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组
  • 通过缓冲区读写,减少系统 IO 次数,从而提高读写的效率

字节缓冲流

构造方法

方法名 作用
public BufferedInputStream(InputStream in) 创建一个 新的缓冲输入流
public BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流
public class Demo {
    public static void main(String[] args) throws Exception {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));
    }
}

效率测试

直接使用 FileInputStream 与 FileOutStream 复制文件

public class Demo {
    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        FileInputStream fis = new FileInputStream("D:\\view.mp4");
        FileOutputStream fos = new FileOutputStream("newView.mp4");
        int len;
        byte[] b = new byte[1024];
        while ((len = fis.read(b)) != -1) {
            fos.write(b);
        }
        fis.close();
        fos.close();
        long end = System.currentTimeMillis();
        System.out.println("时间:" + (end - start));
    }
}

使用缓冲流复制文件

public class Demo {
    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\view.mp4"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("newView.mp4"));
        int len;
        byte[] b = new byte[1024];
        while ((len = bis.read(b)) != -1) {
            bos.write(b);
        }
        bis.close();
        bos.close();
        long end = System.currentTimeMillis();
        System.out.println("时间:" + (end - start));
    }
}

字符缓冲流

构造方法

方法名 作用
public BufferedReader(Reader in) 创建一个 新的缓冲字符输入流
public BufferedWriter(Writer out) 创建一个新的缓冲字符输出流
public class Demo {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new FileReader("a.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
    }
}

特有方法

方法名 作用
public String readLine() 读一行文字
public void newLine() 写一行分隔符,由系统属性定义符号
public class Demo {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new FileReader("a.txt"));
        String line = null;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();
    }
}
public class Demo {
    public static void main(String[] args) throws Exception {
        BufferedWriter br = new BufferedWriter(new FileWriter("a.txt"));
        br.write("灰灰");
        br.newLine();
        br.write("IT6666.top");
        br.newLine();
        br.close();
    }
}

转换流

字符编码

  • 计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制 数转换之后的结果
  • 按照某种规则,将字符存储到计算机中,称为编码
  • 反之,将存储在计算机中的二进制数按照以某种规则解析显示出来,称为解码
  • 按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象

字符集

  • 字符集 Charset:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
  • 计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码
  • 常见字符集有ASCII字符集、GBK字符集、Unicode字符集等

🐤常见字符集

  • ASCII字符集:ASCII编码
  • GBK字符集:GBK编码
  • Unicode字符集:UTF8编码、UTF16编码、UTF32编码
  • 当指定了编码,它所对应的字符集自然就指定了,所以编码才是我们最终要关心的

🐸字符集介绍

ASCII字符集

  • ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)
  • 是基于拉丁字母的一套电脑编码系统,用于显示现代英语
  • 主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
  • 基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符
  • ASCII的扩展字符集使用8位(bits) 表示一个字符,共256字符,方便支持欧洲常用字符

ISO-8859-1字符集

  • 拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等
  • ISO-5559-1使用单字节编码,兼容ASCII编码

GBxxx字符集

  • GB就是国标的意思,是为了显示中文而设计的一套字符集
  • GB2312
    • 简体中文码表。一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字
    • 这样大约可以组合了包含7000多个简体汉字
    • 此外数学符号、罗马希腊的字母、日文的假名们都编进去了
    • 在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码
    • 这就是常说的全角字符,而原来在127号以下的那些就叫半角字符了
  • GBK
    • 最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案
    • 共收录了 21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
  • GB18030
    • 新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成
    • 支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等

Unicode字符集

  • Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码
  • 它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案
  • UTF-8、UTF-16和UTF32,最为常用的UTF-8编码
  • UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码

UTF8编码规则

  • 128个US-ASCII字符,只需一个字节编码
  • 拉丁文等字符,需要二个字节编码
  • 大部分常用字(含中文),使用三个字节编码
  • 其他极少使用的Unicode辅助字符,使用四字节编码

编码引出的问题

  • 在IDEA中,使用 FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的 UTF-8 编码,所以没有任何问题
  • 但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码
public class Demo {
    public static void main(String[] args) throws Exception {
        FileReader fileReader = new FileReader("d:/demo.txt");
        int read;
        while ((read = fileReader.read()) != -1) {
            System.out.println((char) read);
        }
        fileReader.close();
    }
}

🐤解决乱码

InputStreamReader

  • 转换流 java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁
  • 它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集

构造方法

方法名 作用
InputStreamReader(InputStream in) 创建一个使用默认字符集的字符流
InputStreamReader(InputStream in, String charsetName) 创建一个指定字符集的字符流
public class Demo {
    public static void main(String[] args) throws Exception {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("d://demo.txt"), "gbk");
        int read;
        while ((read = isr.read()) != -1) {
            System.out.println((char) read);
        }
        isr.close();
    }
}

OutputStreamWriter

  • 转换流 java.io.OutputStreamWriter,是Writer的子类,是从字符流到字节流的桥梁
  • 使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集

构造方法

方法名 作用
OutputStreamWriter(OutputStream in) 创建一个使用默认字符集的字符流
OutputStreamWriter(OutputStream in, String charsetName) 创建一个指定字符集的字符流
public class Demo {
    public static void main(String[] args) throws Exception {
        String fileName1 = "d://demo.txt";
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(fileName1));
        osw.write("灰灰");
        osw.close();

        String fileName2 = "d://demoTwo.txt";
        OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(fileName2), "gbk");
        osw2.write("灰灰");
        osw2.close();
    }
}

序列化

  • 用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息
  • 字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息
  • 字节序列还可以从文件中读取回来,重构对象,对它进行反序列化

序列化必须满足两个条件

  • 该类必须实现 java.io.Serializable 接口
  • Serializable 是一个标记接口,不实现此接口的类将不会被序列化或反序列化,会抛出 NotSerializableException
  • 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用 transient 关键字修饰

ObjectOutputStream类

  • 将Java对象的原始数据类型写出到文件,实现对象的持久存储

构造方法

方法名 作用
public ObjectOutputStream(OutputStream out) 创建一个指定 OutputStream 的 ObjectOutputStream

写出对象方法

  • public final void writeObject (Object obj)
  • 创建Person类
public class Person implements java.io.Serializable {
    public String name;
    public String age;
    public transient String address;

    public void show() {
        System.out.println("myName is " + name);
    }
}
  • 写到文件当中
public class Demo {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        person.name = "IT6666";
        person.age = "23";
        person.address = "上海";
        FileOutputStream fos = new FileOutputStream("person.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(person);
        oos.close();
        fos.close();
    }
}

ObjectInputStream类

  • ObjectInputStream 反序列化流,将之前使用 ObjectOutputStream 序列化的原始数据恢复为对象

构造方法

方法名 作用
public ObjectInputStream(InputStream in) 创建一个指定 InputStream 的 ObjectInputStream

读取对象方法

  • readObject()
public class Demo {
    public static void main(String[] args) throws Exception {
        FileInputStream fileIn = new FileInputStream("person.txt");
        ObjectInputStream in = new ObjectInputStream(fileIn);
        Person p = (Person) in.readObject();
        System.out.println(p.name);
        System.out.println(p.age);
        System.out.println(p.address);
        p.show();
        fileIn.close();
        in.close();
    }
}

注意事项

  • 对于 JVM 可以反序列化对象,它必须是能够找到 class 文件的类
  • 如果找不到该类的 class 文件,则抛出一个 ClassNotFoundException 异常

打印流

  • 我们在控制台打印输出,是调用 print 方法和 println 方法完成的
  • 这两个方法都来自于 java.io.PrintStream 类
  • 该类能够方便地打印各种数据类型的值,是一种便捷的输出方式

使用指定的文件名创建一个新的打印流

  • public PrintStream(String fileName)
  • System.out 就是 PrintStream 类型的,只不过它的流向是系统规定的,打印在控制台上
public class Demo {
    public static void main(String[] args) throws Exception {
        System.out.println("it6666.top");
        PrintStream os = new PrintStream("demo.txt");
        System.setOut(os);
        System.out.println("it6666.top");
    }
}
posted @ 2020-08-29 09:11  BNTang  阅读(181)  评论(0编辑  收藏  举报