自学内容网 自学内容网

Java:File、字符集、IO流、缓冲流、转换流、打印流、数据流、序列化流

1. File 类

File 是Java.io包下的类,File类的对象,用于代表当前操作系统的文件(可以是文件或文件夹)。
File类只能对文件本身进行操作(比如获取文件大小、文件名、修改时间,或者创建文件/文件夹,删除文件/文件夹),不能读写文件里面存储的数据。如果要读写数据,需要使用到Java IO流。

请添加图片描述

2. 字符集

  • ascii编码中字符a的ascii编码为97,标准的ASCII使用1个字节存储一个字符;
  • gbk编码(汉字编码字符集,gbk中一个中文字符编码成两个字节的形式存储,GBK兼容ASCII字符集);
  • utf-8编码(unicode字符集的一种编码方式,采取可变长编码方案,英文、数字字符只占用一个字节,汉字字符占用3个字节);

在这里插入图片描述在这里插入图片描述
使用gbk编码方式,只占用7个字节。

package File_study;

import java.util.Arrays;

public class File_study {

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

        // 编码
        String _str = "我a你";
        byte[] bytes = _str.getBytes();
        byte[] bytes1 = _str.getBytes("gbk");
        System.out.println(Arrays.toString(bytes));
        // utf-8 编码中上述字符串占用7个字节
        System.out.println(Arrays.toString(bytes1));
        // gbk 编码中上述字符串占用5个字节

        // 解码
        String string = new String(bytes);
        System.out.println(string);

        String s = new String(bytes1);
        System.out.println(s);
        // 编码使用的是utf-8,而解码使用的是gbk,因此出现了乱码
    }
}

运行结果:
在这里插入图片描述

3. IO流

  • 按流的方向分为输入流、输出流;
  • 按流中数据的最小单位,分为字节流、字符流,其中字节流适合操作所有类型的文件,而字符流只适合操作纯文本文件;

因此常用的有字符输入流(Reader)、字符输出流(Writer)、字节输入流(InputStream)、字节输出流(OutputStream),但上述指定的都是抽象类,它们的具体实现类分别为FileReader、FileWriter、FileInputStream、FileOutputStream

3-1. FileInputStream(文件字节输入流)

用于从文件中读取字节,文件字节输入流常用的构造方法有如下图中的前两种,可以是文件路径或者File对象都可以。
在这里插入图片描述
通过文件字节输入流的read方法读取文件数据。

  • read 无参数表示每次读取一个字节,返回值类型为int,读取到最后返回值为-1
  • read 一个参数时表示把读取的字节数组传给参数,它的返回值表示此次读取的字节长度,读取到最后返回值为-1

在这里插入图片描述

package File_study;

import java.io.*;

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

        File file = new File("1/1.txt");
        // 文件里边的数据为:我a你,使用的编码方式为utf-8
        InputStream inputStream = new FileInputStream(file);
        int a;
        while((a = inputStream.read())!=-1){
            System.out.println(a);
        }
        inputStream.close();
    }
}

运行结果:
在这里插入图片描述

package File_study;

import java.io.*;

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

        File file = new File("1/1.txt");
        // 文件里边的数据为:我a你,使用的编码方式为utf-8
        InputStream inputStream = new FileInputStream(file);
        byte[] bytes1 = new byte[3];
        int len;
        while((len = inputStream.read(bytes1))!=-1){
            System.out.println(new String(bytes1,0,len));
        }

        inputStream.close();
    }
}

在这里插入图片描述
为了避免读取的汉字不乱码,可以定义一个长度和文件大小一致的字节数组,这样就可以读取所有的字节了。

package File_study;

import java.io.*;

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

        File file = new File("1/1.txt");
        long len = file.length();
        // 文件里边的数据为:我a你,使用的编码方式为utf-8
        InputStream inputStream = new FileInputStream(file);
        byte[] bytes1 = new byte[(int) len];
        int read = inputStream.read(bytes1);
        System.out.println(read+" "+new String(bytes1));
    }
}

在这里插入图片描述

3-2. FileOutputStream(文件字节输出流)

用于把字节数据写入到文件中去。常用的构造方法也有两种,一种是直接写文件名,另外一种则是写File对象。

package File_study;

import java.io.*;

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

        FileOutputStream os = new FileOutputStream("1.txt");
        os.write(97);
        os.write("我a你".getBytes());
        os.close();
    }
}

在这里插入图片描述
写入方式是会把原来的数据覆盖掉,如果想在文件后面追加数据,可以直接在文件字节输出流后面加上参数true即可,如下:

FileOutputStream os = new FileOutputStream("1.txt",true);

3-3. 通过FileInputoutStream、FileOutputStream实现文件的复制

package File_study;

import java.io.*;

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

        // 实现文件的复制
        InputStream is = new FileInputStream("C:\\Users\\Administrator\\Pictures\\5.jpg");
        OutputStream os = new FileOutputStream("1.jpg",true);
        byte[] bytes = new byte[1024*1024];
        int len;
        while((len=is.read(bytes))!=-1){
            os.write(bytes,0,len);
        }

        os.close();
        is.close();
    }
}

在这里插入图片描述

3-3-1. 通过try-catch-finally来释放资源

package File_study;

import java.io.*;

public class File_study2 {
    public static void main(String[] args) {

        InputStream is = null;
        OutputStream os = null;
        // 实现文件的复制
        try{
            is = new FileInputStream("C:\\Users\\Administrator\\Pictures\\5.jpg");
            os = new FileOutputStream("2.jpg",true);
            byte[] bytes = new byte[1024*1024];
            int len;
            while((len=is.read(bytes))!=-1){
                os.write(bytes,0,len);
            }
        }catch (IOException e){

            e.printStackTrace();

        }finally {

            try {
                if(os != null)
                    os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if(is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3-3-2. 通过try-catch-resource来释放资源

通过这种方式,把需要释放的资源放到try()小括号里边,这样代码运行完之后就会自动释放。

package File_study;

import java.io.*;

public class File_study2 {
    public static void main(String[] args) {
        // 实现文件的复制
        try(
                InputStream is = new FileInputStream("C:\\Users\\Administrator\\Pictures\\5.jpg");
                OutputStream os = new FileOutputStream("3.jpg",true);
                ){
            byte[] bytes = new byte[1024*1024];
            int len;
            while((len=is.read(bytes))!=-1){
                os.write(bytes,0,len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

这里根本看不出它是否释放了资源,通过查询FileInputStream继承关系看看,发现最终它的close方法最终来自于接口AutoCloseable下的close方法。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
为此我们可以定义一个类,让其实现AutoCloseable接口下的close方法来进行演示,看在小括号中这个自定义的类对象是否执行了close方法,如下:

package File_study;

public class CloseTest implements AutoCloseable{
    @Override
    public void close() throws Exception {
        System.out.println("在这里释放资源");
    }
}
package File_study;

import java.io.*;

public class File_study2 {
    public static void main(String[] args) {
        // 实现文件的复制
        try(
                InputStream is = new FileInputStream("C:\\Users\\Administrator\\Pictures\\5.jpg");
                OutputStream os = new FileOutputStream("3.jpg",true);
                CloseTest closeTest = new CloseTest();
        ){
            byte[] bytes = new byte[1024*1024];
            int len;
            while((len=is.read(bytes))!=-1){
                os.write(bytes,0,len);
            }
            System.out.println(closeTest);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

运行结果:
在这里插入图片描述

4. FileReader(文件字符输入流)

从文件中读取字符出来,常用的构造方法两种,一种写文件存储路径,第二种参数为File对象。
在这里插入图片描述

package File_study;

import java.io.*;

public class File_study3 {

    public static void main(String[] args) {
        try(
            Reader r = new FileReader("src/File_study/File_study2.java");
        ){
            int c;
            while((c= r.read())!=-1){
                System.out.print((char) c);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
关于读取方法read,常用的有如下两种:
在这里插入图片描述
上述读取效率较低,为此,可以使用字符数组来存储读取到的字符。

package File_study;

import java.io.*;

public class File_study3 {

    public static void main(String[] args) {
        try(
            Reader r = new FileReader("src/File_study/File_study2.java");
        ){
            int len;
            char[] chars = new char[10];
            while((len= r.read(chars))!=-1){
                System.out.print(new String(chars,0,len));
                // 读取多少,输出多少
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

5. FileWriter(文件字符输出流)

字符写入到文件中去。

常用的写入字符到文件中去的方法writer有如下几种:
在这里插入图片描述

package File_study;


import java.io.*;

public class File_study3 {

    public static void main(String[] args) {
        try(
            Writer w = new FileWriter("src/File_study/1.txt");
        ){
            w.write('我');
            // 写入单个字符
            w.write("\r\n");
            w.write("我a你");
            // 写入字符串
            w.write("\r\n");
            char[] chars = {'我','a','你'};
            w.write(chars);
            // 写入字符数组
            w.write("\r\n");
            w.write("我a你",1,1);
            // 写入字符串 “a”
            w.write("\r\n");
            w.write(chars,1,1);
            // 写入字符数组 'a'
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
需要注意的是:字符输出流写出数据后,必须刷新流,或者关闭流,否则不能生效。 这是因为文件字符输入流它执行writer方法后,会先把数据先写入到缓冲区中去,然后再经过系统调用写入到文件中。所以在没有执行close方法或flush方法时,数据是没有写入到文件中去的,在执行close方法时会调用flush方法。

6. 缓冲流

对上述中的一些的原始流(文件字节输入流、文件字节输出流、文件字符输入流、文件字符输出流)进行了包装,以提高原始流的读写数据的性能。

6-1. 字节缓冲流

提高字节流读写的性能。原理:字节缓冲输入流自带8kb缓冲池;字节缓冲输出流也自带了8kb的缓冲池。把上述那个复制文件的代码修改为使用字节缓冲流的形式,如下:

package File_study;

import java.io.*;

public class File_study4 {
    public static void main(String[] args) {
        // 实现文件的复制
        try(
                InputStream is = new FileInputStream("C:\\Users\\Administrator\\Pictures\\5.jpg");
                InputStream bis = new BufferedInputStream(is);
                OutputStream os = new FileOutputStream("5.jpg",true);
                OutputStream bos = new BufferedOutputStream(os);
        ){
            byte[] bytes = new byte[1024];
            int len;
            while((len=bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

查看字节缓冲流的源码可以看到的确有8kb的缓冲池,如下:
在这里插入图片描述
在这里插入图片描述
如果想设置缓冲池的大小,直接在字符缓冲流后加上参数即可。

InputStream bis = new BufferedInputStream(is,8192*2);
OutputStream bos = new BufferedOutputStream(os,8192*2);

6-2. 字符缓冲输入流

自带8kb(8192)的字符缓冲池,可以提高字符输入流读取字符数据的性能。

在这里插入图片描述

package File_study;

import java.io.*;

public class File_study5 {

    public static void main(String[] args) {

        try(
            Reader r = new FileReader("src/File_study/File_study3.java");
            BufferedReader br = new BufferedReader(r)
        ){
            int len;
            char[] chars = new char[100];
            while((len=br.read(chars))!=-1){
                System.out.println(new String(chars,0,len));
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

按照行来读取数据,使用方法readLine,如下:

package File_study;

import java.io.*;

public class File_study5 {

    public static void main(String[] args) {
        try(
            Reader r = new FileReader("src/File_study/File_study3.java");
            BufferedReader br = new BufferedReader(r)
        ){
            String outcome;
            while((outcome=br.readLine())!=null){
                System.out.println(outcome);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

6-3. 字符缓冲输出流

自带8kb(8192)的字符缓冲池,可以提高字符输出流写字符数据的性能。
在这里插入图片描述

package File_study;

import java.io.*;

public class File_study6 {

    public static void main(String[] args) {

        try(
                Writer os = new FileWriter("3.txt");
                BufferedWriter bos = new BufferedWriter(os);
        ){
            bos.write("爱我中华。。");
            bos.newLine();
            // 换行
            bos.write('爱');
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

7. 测试复制文件代码的性能

这里通过四种方式来测试,分别为使用一个一个字节来实现文件的复制、使用字节数组来实现文件的复制、使用缓冲流并一个一个字节来实现文件的复制、使用缓冲流并字节数组来实现文件的复制,参考代码如下:

package File_study;

import java.io.*;

public class File_study7 {

    private static final String FILE_PATH = "E:/Download/2.png";
    private static final String DIR = "E:/Download/";

    public static void main(String[] args) {
        copy1(FILE_PATH,DIR);
        copy2(FILE_PATH,DIR);
        copy3(FILE_PATH,DIR);
        copy4(FILE_PATH,DIR);
    }


    public static void copy1(String file_path,String DIR){
        long start = System.currentTimeMillis();
        try(
                InputStream is = new FileInputStream(file_path);
                OutputStream os = new FileOutputStream(DIR+"3.png");
                ){
            int c;
            while((c=is.read())!=-1){
                os.write(c);
            }
        }catch (IOException e){
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("通过一个一个字节来复制文件花费的时间为:"+(end-start)/1000.0+"s");
    }


    public static void copy2(String file_path,String DIR){
        long start = System.currentTimeMillis();
        try(
                InputStream is = new FileInputStream(file_path);
                OutputStream os = new FileOutputStream(DIR+"4.png");
        ){
            byte[] bytes = new byte[1024];
            int len;
            while((len=is.read(bytes))!=-1){
                os.write(bytes,0,len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("通过字节数组来复制文件花费的时间为:"+(end-start)/1000.0+"s");
    }


    public static void copy3(String file_path,String DIR){
        long start = System.currentTimeMillis();
        try(
                InputStream is = new FileInputStream(file_path);
                BufferedInputStream bis = new BufferedInputStream(is);
                OutputStream os = new FileOutputStream(DIR+"5.png");
                BufferedOutputStream bos = new BufferedOutputStream(os);
        ){
            int c;
            while((c=bis.read())!=-1){
                bos.write(c);
            }
        }catch (IOException e){
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("通过缓冲字符流、一个一个字节来复制文件花费的时间为:"+(end-start)/1000.0+"s");
    }

    public static void copy4(String file_path,String DIR){
        long start = System.currentTimeMillis();
        try(
                InputStream is = new FileInputStream(file_path);
                BufferedInputStream bis = new BufferedInputStream(is);
                OutputStream os = new FileOutputStream(DIR+"6.png");
                BufferedOutputStream bos = new BufferedOutputStream(os);
        ){
            byte[] bytes = new byte[1024];
            int len;
            while((len=bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("通过缓冲流和字节数组来复制文件花费的时间为:"+(end-start)/1000.0+"s");
    }
}

运行结果如下:
在这里插入图片描述

这里没有运行copy1,效率太低了。如果把copy2中字节数组大小修改为1024*8(或者更大吧!),其他的不变,只运行copy2和copy4,可以发现它们两者的运行效率基本上差不了多少。

8. 转换流

用于解决不同编码读写时的乱码情况,这里有一段代码如下:

package File_study;

import java.io.* ;

public class File_study8 {
    public static void main(String[] args) {
        try(
            Reader r = new FileReader("3.txt");
            BufferedReader br = new BufferedReader(r)
        ){
            String line;
            while((line=br.readLine())!=null){
                System.out.println(line);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
此时出现了乱码,因为这个文件的编码为gbk,而代码运行文件编码为utf-8。
在这里插入图片描述
在这里插入图片描述

8-1. 字符输入转换流(InputStreamReader)

解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转换成字符输入流,这样字符输入流中的字符就不乱码了

package File_study;

import java.io.* ;

public class File_study8 {
    public static void main(String[] args) {
        try(
            InputStream fis = new FileInputStream("3.txt");
            Reader r = new InputStreamReader(fis,"gbk");
            BufferedReader bfr = new BufferedReader(r);
            ){
            String line;
            while((line= bfr.readLine())!=null){
                System.out.println(line);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

8-2. 字符输出转换流(OutputStreamWriter)

控制写出去的字符使用特定的字符集编码。
解决思路:先获取字节输出流,再将其按指定的字符集编码转换成字符输出流,之后写出去的字符就会使用该字符集编码了

package File_study;


import java.io.*;

public class File_study9 {

    public static void main(String[] args) {

        try (
                OutputStream fos = new FileOutputStream("4.txt");
                Writer osw = new OutputStreamWriter(fos,"gbk");
                BufferedWriter bw = new BufferedWriter(osw);
        ){
            bw.write("爱我中华");
            bw.write("我爱中国。。");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

9. 打印流(PrintStream/PrintWriter)

作用:更方便、更高效的把数据打印出去,能够实现打印啥出去就是啥出去

9-1.PrintStream

在这里插入图片描述

package File_study;

import java.io.*;

public class File_study10 {

    public static void main(String[] args) {


        try(
                PrintStream ps = new PrintStream("printStream.txt", "gbk");
                ){
            ps.println("爱我中华");
            ps.print("1");
            ps.println();
            ps.print("我爱中国");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

9-2. PrintWriter

在这里插入图片描述

package File_study;

import java.io.*;

public class File_study10 {
    public static void main(String[] args) {
        try(
                PrintWriter pw = new PrintWriter("printWriter.txt");
        ){
            pw.println("爱我中华");
            pw.println("1");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

9-3. 关于打印流的高效

直接查看源码,可以发现在它们的下面使用了缓冲流。
PrintStream
在这里插入图片描述
在这里插入图片描述

PrintWriter
在这里插入图片描述

9-4. 把系统默认的打印流修改为自定义的打印流

系统运行结果都会打印到控制台上,如果想把打印的数据写入的文件中去,可以使用打印流,如下:

package File_study;

import java.io.*;

public class File_study10 {

    public static void main(String[] args) {

        System.out.println("我爱中国!");

        try(
                PrintStream ps = new PrintStream("printstream1.txt");
        ){
            System.setOut(ps);
            System.out.println("爱我中华");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

10. 数据流

允许把数据和其类型一并写出去。

10-1. 数据输出流(DataOutputStream)

package File_study;

import java.io.*;

public class File_study11 {

    public static void main(String[] args) {

        try(
                OutputStream os = new FileOutputStream("dataoutputstream.txt");
                DataOutputStream dos = new DataOutputStream(os);
        ){
            dos.write(1);
            dos.writeFloat(0.1f);
            dos.writeBoolean(false);
            dos.writeUTF("爱我中华2");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

10-2. 数据输入流(DataInputStream)

package File_study;

import java.io.*;

public class File_study11 {
    public static void main(String[] args) {

        try(
                InputStream is = new FileInputStream("dataoutputstream.txt");
                DataInputStream dis = new DataInputStream(is);
        ){
            int i = dis.read();
            float v = dis.readFloat();
            boolean b = dis.readBoolean();
            String s = dis.readUTF();
            System.out.println(i+" "+v+" "+b+" "+s);
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

数据是怎样写入的,就怎么读取出来。
在这里插入图片描述

11. 序列化流

11-1. 对象字节输出流 (ObjectOutputStream)

Java对象进行序列化:把Java对象存入到文件中去。
把对象序列化,需要把对象对应的类实现Serializable这个接口。

package File_study.enity;

import java.io.Serializable;

public class User implements Serializable {
    private String name;
    private Integer age;
    private char sex;

    public User(String name, Integer age, char sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

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

package File_study;

import File_study.enity.User;

import java.io.*;

public class File_study12 {

    public static void main(String[] args) {

        try(
                OutputStream fos = new FileOutputStream("object.txt");
                ObjectOutputStream oos = new ObjectOutputStream(fos);
                ){
            User user = new User("张三", 20, 'm');
            oos.writeObject(user);
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

11-2. 对象字节输入流 (ObjectInputStream)

Java对象反序列化:从文件中读取Java对象。

package File_study;

import File_study.enity.User;
import java.io.*;

public class File_study12 {

    public static void main(String[] args) {
        try(
                InputStream fis = new FileInputStream("object.txt");
                ObjectInputStream ois = new ObjectInputStream(fis);
        ){
            User o = (User) ois.readObject();
            System.out.println(o);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述


原文地址:https://blog.csdn.net/qq_45404396/article/details/144006098

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!