Java I/O流入门

前言

Java IO流入门,了解IO简介、IO流入门案例、File类的使用、常用流对象、Apache IO包。

一、IO简介

1、什么是IO流?

1)与外部设备进行通信,进行数据交换,即Input/Output data。
2)Java IO API 屏蔽外部设备的差异性。

2、数据源(Data Source)

以程序为参考对象。
1)源设备:向程序传输所需数据的设备。
2)目的设备:程序将数据存储到外部的设备。

3、流的概念

流是一个抽象、动态的概念,这里指的数据流,数据以一定容量为单位不断流入程序或外部设备。
数据流即一连串连续动态的数据集合。
在这里插入图片描述

4、Java四大IO抽象类

这四个抽象类奠定了IO的基础,分别为:
1)字节流,以一字节(8bit)作为基本单位。
A)InputStream
int read(),返回一个0-255的十进制 或 -1,分别表示读取的字符和已读完。
void close(),关闭字节流输入对象,释放相关系统资源。
B)OutputStream
void write(int n),向目的设备写一个字节的二进制。
void close(),关闭字节流输出对象,释放相关系统资源。
2)字符流,以一个字符为基本单位。
A)Reader
int read(),读取字符数据,返回一个0-65535 的十进制,即Unicode字符,或者返回-1。分别表示读出的字符和已读完。
void close(),关闭字节流输出对象,释放相关系统资源。
B)Writer
void write(int n),向目的设备写入一个字符的二进制。
void close(),关闭字节流输出对象,释放相关系统资源。

5、IO流分类

1)按流方向
A)输入流:Data Source -> Program
B)输出流:Program -> Destination
2)按处理单元
A)字节流,以字节为基本单位。
B)字符流,以字符为基本单位,即Unicode字符。
3)按处理对象
A)节点流,直接链接到数据源。
B)处理流,对节点流的包装,让流有更加强大的功能,处理流的流对象。如BufferedInputStream、BufferedOutputStream。
在这里插入图片描述

6、Java IO流体系

在这里插入图片描述

重点类介绍
1)File,处理目录或文件,包装成类,就能够更好的操作目录和文件。
2)InputStream、OutputStream、Reader、Writer,四大基本抽象类,Java 中IO的规范。
3)FileInputStream / FileOutputStream
节点流,以字节为单位,直接操作文件。
4)ByteArrayInputStream / ByteArrayOutputStream
节点流,以字节为单位,直接处理“字节数组对象”。
5)ObjectInputStream / ObjectOutputStream
处理流,以字节为单位,操作字节流中的对象。
6)DataInputStream / DataOutputStream
处理流,以字节为单位,操作字节流中的基本数据类型与字符串类型。
7)FileReader / FileWriter
节点流,以字符为基本单位,直接操作文本文件。
8)BufferedReader / BufferedWriter
处理流,包装了Reader、Writer,增加了缓存功能,通过缓存减少等待时间来提高读写的效率。
9)BufferedInputStream / BufferedOutputStream
处理流,包装InputStream、OutputStream,增加缓存功能,提高读写效率。
10)InputStreamReader / OutputStreamWriter
处理流,将字节流对象包装成字符流对象。
11)PrintStream
处理流,包装OutputStream,方便输出字符。

二、IO流入门案例

1)只能展示0-255的字符

package com.xhu.java;

import java.io.*;

public class TestIO {
    public static void main(String[] args) {
        //1.创建字节输入流
        try (FileInputStream fis = new FileInputStream("d:/IOCase.txt")) {
            int n = 0;
            while ((n = fis.read()) != -1)
                System.out.print((char) (n));
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }

    }
}

Java 异常进阶
2)展示0-65535,即Unicode字符

package com.xhu.java;

import java.io.*;
import java.util.Arrays;

public class TestIO {
    public static void main(String[] args) {
        try (FileReader fr = new FileReader("d:/IOCase.txt")) {
            StringBuilder sb = new StringBuilder();
            int n = 0;
            while ((n = fr.read()) != -1) {
                sb.append((char) n);
            }
            System.out.println(sb.toString());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

三、File类的使用

1、File的常见方法

File 常见方法

四、常用流对象

1、文件字节流

1)FileInputStream / FileOutputStream
以字节的方式读取文件,所有文件底层都为二进制,所以这个能读取所有类型的文件和写任意类型的文件。(图像、视频、文本文件)

package com.xhu.java;
import java.io.*;
import java.util.Arrays;

public class TestIO {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("d:/生物钟.jpg");
             FileOutputStream fos = new FileOutputStream("d:生物钟副本.png")) {
            int n = 0;
            while((n = fis.read()) != -1){
                fos.write(n);
            }
            //把内存缓存的数据写入磁盘中
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2)通过缓存区提高读写效率

上面的操作是一个一个字节去读的,一个一个去写,IO的调用次数大多,当图片太大就会很慢。
A)指定长度的字节数组作为缓存区,该长度应为2的整数幂。

	public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("d:/生物钟.jpg");
             FileOutputStream fos = new FileOutputStream("d:生物钟副本.png")) {
            //1024位bit,缓存区
            byte[] buffer = new byte[1024];
            //每次读到buffer中的长度
            int n = 0;
            //每次读写1024位
            while((n = fis.read(buffer)) != -1){
                fos.write(buffer,0,n);
            }
            //把内存缓存的数据写入磁盘中
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

B)根据文件大小来确定buffer长度,相当于一次性读写文件,文件太大,占用内存也会很大,所以推荐小文件。

	public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("d:/生物钟.jpg");
             FileOutputStream fos = new FileOutputStream("d:/生物钟副本.png")) {
            //1024位bit,缓存区,文件太大,内存空间占用也大
            byte[] buffer = new byte[fis.available()];
            int n = fis.read(buffer);
            fos.write(buffer, 0, n);
            //把内存缓存的数据写入磁盘中
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

C)包装流BufferedInputStream / BufferedOutputStream

缓存区慢或手动提交时,才会把处理数据。底层缓冲数组。

	public static void main(String[] args) {
        //关闭流顺序,后开先关闭
        try (FileInputStream fis = new FileInputStream("d:/生物钟.jpg");
             FileOutputStream fos = new FileOutputStream("d:/生物钟副本.png");
             BufferedInputStream bis = new BufferedInputStream(fis);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {
            int n = 0;
            //buffer的默认长度为2的13次方8192
            //private static int DEFAULT_BUFFER_SIZE = 8192;
            while ((n = bis.read()) != -1) {
                //去写缓冲区的内容,字节转十进制为n
                bos.write(n);
            }
            //把内存缓存的数据写入磁盘中
            bos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2、定义文件拷贝工具类

package com.xhu.java;

import java.io.*;

/**
 * 用于复制文件
 */
public class CopyFileTools {

    /**
     * 复制文件
     *
     * @param source
     * @param dest
     * @throws IOException
     */
    public static void copy(String source, String dest) throws IOException {
        try (FileInputStream fis = new FileInputStream(source);
             FileOutputStream fos = new FileOutputStream(dest)) {
            copyFile(fis, fos);
        } catch (IOException e) {
            throw e;
        }
    }

    /**
     * 通过缓冲区提高复制文件的效率
     *
     * @param fis
     * @param fos
     * @throws IOException
     */
    private static void copyFile(FileInputStream fis, FileOutputStream fos) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        int n = 0;
        while ((n = bis.read()) != -1) {
            bos.write(n);
        }
        bos.flush();
    }

}

3、文件字符流

1)FileReader / FileWriter

	public static void main(String[] args) {
        try (FileReader fr = new FileReader("d:/IOCase.txt");
             FileWriter fw = new FileWriter("d:/IOCase_copy.txt")) {
            int n = 0;
            while ((n = fr.read()) != -1) {
                fw.write(n);
            }
            fw.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2)用buffer来提高效率

	public static void main(String[] args) throws IOException {
        try (FileReader fr = new FileReader("d:/IOCase.txt");
             FileWriter fw = new FileWriter("d:/IOCase_copy.txt");
             BufferedReader br = new BufferedReader(fr);
             BufferedWriter bw = new BufferedWriter(fw)) {
            int n = 0;
            while ((n = br.read()) != -1) {
                bw.write(n);
            }
            //换行
            bw.newLine()
            bw.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
	String str = null;
    while ((str = br.readLine()) != null) {
          bw.write(str);
    }

4、为每行添加行号

	public static void main(String[] args) throws IOException {
        try (FileReader fr = new FileReader("d:/IOCase.txt");
             FileWriter fw = new FileWriter("d:/IOCase_copy.txt");
             BufferedReader br = new BufferedReader(fr);
             BufferedWriter bw = new BufferedWriter(fw)) {
            int n = 0;
            String str = null;
            StringBuilder sb = new StringBuilder();
            while ((str = br.readLine()) != null) {
                bw.write(sb.append(++n).append(":").append(str).toString());
                //读完一行就换还
                bw.newLine();
                sb.delete(0, sb.length());
            }
            bw.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

5、转换流

InputStreamReader / OutputStreamWriter ,将字节流转换为字符流。
如键盘输入一行System.in,用BufferedReader 读一行,键盘输入的是字节流,而BufferedReader是字符流;显示在屏幕的System.out也是字节流,但是我们需要把它变成字符显示在屏幕上。所以需要用到转换流,即一种包装流。

package com.xhu.java;

import java.io.*;

public class TestInputStreamReader {
    public static void main(String[] args) {
        //把键盘作为数据源
        InputStream is = System.in;
        //把显示屏作为目的设备
        OutputStream os = System.out;
        try (InputStreamReader ism = new InputStreamReader(is);
             OutputStreamWriter osw = new OutputStreamWriter(os);
             BufferedReader br = new BufferedReader(ism);
             BufferedWriter bw = new BufferedWriter(osw)) {
            //输入exit为出口
            while (true) {
                //将请输入flush到屏幕上
                bw.write("请输入:");
                bw.flush();

                String str = br.readLine();
                if ("exit".equals(str)) {
                    break;
                }
                //将输入的一行flush到屏幕上
                bw.write("你输入的是:" + str);
                bw.flush();
                //手动换行
                bw.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

6、字符输出流

PrintWriter自带换行(print)和flush。

public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("d:/IOCase.txt");
             InputStreamReader isr = new InputStreamReader(fis);
             BufferedReader br = new BufferedReader(isr);
             PrintWriter pw = new PrintWriter("d:/IOCase_copy.txt");
        ) {
            int n = 0;
            String str = null;
            StringBuilder sb = new StringBuilder();
            while ((str = br.readLine()) != null) {
                pw.println(sb.append((++n)).append(',').append(str));
                sb.delete(0, sb.length());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

7、字节数组流

ByteArrayInputStream / ByteArrayOutStream
以字节数组为处理对象,进行读取和写入。

package com.xhu.java;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class TestByteArrayInputStream {
    public static void main(String[] args) {
        byte[] bytes = "abc".getBytes();
        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
             ByteArrayOutputStream baos = new ByteArrayOutputStream();) {
            int n = 0;
            while ((n = bais.read()) != -1) {
                //写回字符数组
                baos.write(n);
            }
            //得到字节数组
            byte[] res = baos.toByteArray();
            for (byte b : res) {
                System.out.print((char) b);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

8、数据流

DataInputStream / DataOutputStream
字节和字符流便于存储和读取Java中的基本数据类型。

package com.xhu.java;

import java.io.*;

public class TestDataInputStream {
    public static void main(String[] args) {
        try (DataOutputStream dps = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("d:/data.txt")));
             DataInputStream dis = new DataInputStream(new FileInputStream("d:/data.txt"))) {
            int[] data = new int[]{1122211111, 2, 3};
            for (int n : data) {
                dps.writeInt(n);
            }
            dps.flush();
            int n = 3;
            while (n-- != 0) {
                System.out.println(dis.readInt());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

9、对象流

将对象以二进制的形式进行输入和写出。
1)序列化和反序列化
含义)将Java对象转化为字节序列,为序列化;将二进制序列转化为Java对象,为反序列化。
作用)将对象持久化;网络通信。
序列化类)ObjectInputStream / ObjectOutputStream
writeObject(Object obj),将obj序列化,然后再写到目标输出流中。
Object readObject(),从数据流中读出序列数据,然后将字节序列反序列化为Object对象。
Serializable)一个空接口,起标记作用,只有实现了这个接口的类,其对象才能被序列化。

package com.xhu.java;

import java.io.*;

public class TestObjectInputStream {
    public static void main(String[] args) {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/data.txt"));
             ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/data.txt"));
        ) {
            Person[] ps = new Person[]{new Person("林森"), new Person("李")};
            oos.writeInt(ps.length);
            for (Person p : ps) {
                oos.writeObject(p);
            }
            //oos.writeObject(null);
            //oos.flush();
            int len = ois.readInt();
            Object obj = null;
            while (len-- > 0) {
                System.out.println(((Person) ois.readObject()).name);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

10、随机访问流

1)RandomAccessFile
作用1)既可以读入文件,也可以写出文件。
作用2)可以访问文件的任意位置,不像其它流只能顺序读取。
核心函数)
A)RandomAccessFile(String name,String mode),name为文件名,mode为流的访问权限,如r(读)、rw(可读写)。
定位函数)seek(long a),定位流对象读写的位置,a是离文件头的字节数。
getFilePointer(),获取当前文件指针位置。

package com.xhu.java;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class TestRandomAccessFile {
    public static void main(String[] args) {
        try (RandomAccessFile raf = new RandomAccessFile("d:data.txt", "rw")) {
            int[] data = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
            for (int n : data) {
                raf.writeInt(n);
            }
            raf.writeInt(Integer.MAX_VALUE);
            //把指针移回来
            raf.seek(0);
            int n = 0;
            while ((n = raf.readInt()) != Integer.MAX_VALUE) {
                System.out.println(n);
                //打印偶数,int 4个字节,当前位置加4个字节就跳过了一位整数。
                raf.seek(raf.getFilePointer() + 4);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注:当文件作为数据源或目标时,可以使用File类来表示。File file = new File("d:a.txt"); FileReader fr = new FileReader(file);

五、Apache IO包

为了简化实际开发中复杂的IO操作代码,第三方Apache提供了IO包来简化许多复杂繁琐的IO操作。
Apache-commons工具包中提供了IOUtils / FileUtils类。

1、下载Apache IO包

下载地址:commons.apache.org
在这里插入图片描述

2、添加jar包

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、FileUtils

进入docs查看API参考文档,该类提供了很多方法,功能强大。
在这里插入图片描述

package com.xhu.java;

import org.apache.commons.io.FileUtils;

import java.io.*;

public class TestFileUtils {
    public static void main(String[] args) throws IOException {
        File file = new File("d:data.txt");
        //读取所有内容
        String allContent = FileUtils.readFileToString(file, "UTF-8");
        System.out.println(allContent);
        //复制文件
        FileUtils.copyToFile(new FileInputStream(file), new File("d:data_copy.txt"));
        //拷贝文件夹
        FileUtils.copyDirectory(new File("d:/file"), new File("d:/file_copy"), new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isDirectory() || pathname.getName().endsWith(".txt") ? true : false;
            }
        });
    }
}

4、IOUtils

toString:将输入流或数组中的内容转化为字符串。其它查API参考文档。

package com.xhu.java;

import org.apache.commons.io.IOUtils;

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

public class TestIOUtils {
    public static void main(String[] args) throws IOException {
        //字节转字符串
        String allContent = IOUtils.toString(new FileInputStream("d:data.txt"), "utf-8");
        System.out.println(allContent);
    }
}

总结

1)输入流、输出流、节点流、处理流
2)序列化、反序列化
3)常用流对象、FileUtils、IOUtils

参考文献

[1] [JDK 1.12]
[2] Java SE oldLu
[3] Apache IO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值