适合小小白入门的JavaIO文章,学完即可上手
IO概述
基本概念
首先我们需要理解的是什么是IO,从字面意思上来看,IO取的是Input和Output的首字母,也就是输入和输出的意思了,即数据的传输。这里的输入和输出是相对于内存等存储设备来说的,流向内存等存储设备是输入,流出内存等存储设备是输出!(IO又称IO流)
关于IO对进程的影响以及IO的同步和异步等本文不做介绍
IO的分类
知道了IO的基本概念后,对IO做一个分类,方便理解和使用。
根据数据的流向分:输入流和输出流
- 输出流:数据从内存等存储设备写到其他设备上
- 输入流:数据从其他设备上读取到内存等存储设备上
- 字符流:数据流以字符为单位进行传输
- 字节流:数据流以字节为单位进行传输
根据数据流的功能分:节点流和处理流
- 节点流:在某一个特定节点进行数据读写,直接连接数据源
- 处理流:对一个已存在的流进行连接和封装,通过所封装的流的功能调用实现数据读写,不直接连接数据源
基本介绍
字节流
我们都知道在计算机中所有的内容都是以二进制数字的形式存储的,也就是可以看作字节(计算机信息技术用于计量存储容量的一种计量单位,一个字节存储8位无符号数,储存的数值范围为0-255)。那么,从这里来看,我们传输任何数据都是可以以字节流进行的。
字节输出流
字节输出流是OutputStream,它是java.io.OutputStream抽象类,它定义了字节输出流中的有些基本的方法,其子类会有更加详细的具体功能的实现。下面介绍它的接种常见方法:
- public void 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) :将指定的字节写入该输出流中。
close()方法是必须要调用的,因为IO流不能自动关闭,需要手动调用该方法以释放占用的资源
该抽象类有很多子类,下面介绍一个入门级且很常用的子类:FileOutputStream
FilterOutputStream
文件输出流是File或FileDescriptor数据写入输出流。其目的是将数据写到文件中。
构造方法
- FileOutputStream(File file) :创建一个文件输出流写入指定的 File对象表示的文件。
- FileOutputStream(File file, boolean append) :创建一个文件输出流写入指定的 File对象表示的文件。
- FileOutputStream(String name): 创建一个文件输出流,用指定的名称写入文件。
- FileOutputStream(String name, boolean append) :创建一个文件输出流,用指定的名称写入文件。
当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据。
常用方法
- void close() :关闭此文件输出流并释放与此流关联的任何系统资源。
- void write(byte[] b) :写 b.length字节从指定的字节数组来此文件输出流。
- void write(byte[] b, int off, int len) :写 len字节指定字节数组中的起始偏移 off此文件输出流。
- void write(int b) :将指定的字节写入该文件输出流中。
- public FileOutputStream(File file, boolean append): 创建文件输出流以写入由指定的 File对象表示的文件。
- public FileOutputStream(String name, boolean append): 创建文件输出流以指定的名称写入文件。
代码实例
import org.junit.Test;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;public class OutPutStreamDemo1 { public static void main(String[] args) throws IOException { //创建操作文件输出流对象 OutputStream outputStream = new FileOutputStream("(你自己的文件位置)\\test.txt"); //向文件写入内容 outputStream.write(97); outputStream.write(98); outputStream.write(99); //关闭输出流 outputStream.close(); } @Test public void outFile01() throws Exception { //创建操作文件输出流对象 OutputStream out = new FileOutputStream("(你自己的文件位置)\\test.txt"); //写内容 byte[] b = "test".getBytes(); out.write(b); //关闭 out.close(); } @Test public void outFile02() throws Exception { //创建操作文件输出流对象 OutputStream out = new FileOutputStream("(你自己的文件位置)\\test.txt"); //写内容 byte[] b = "abcde".getBytes(); //write 第一个参数开始位置 索引 // 第二个参数 从开始位置几个字符 out.write(b,2,2); //关闭 out.close(); } //追加操作 @Test public void outFile03() throws Exception { //创建操作文件输出流对象 //可以实现追加 OutputStream out = new FileOutputStream("(你自己的文件位置)\\test.txt",true); //写内容 byte[] b = "append".getBytes(); //write 第一个参数开始位置 索引 // 第二个参数 从开始位置几个字符 //out.write(b,0,6); out.write(b,2,2); //关闭 out.close(); }}
字节输入流
字节输入流是InputStream,它是java.io.InputStream抽象类,它定义了字节输入流中的有些基本的方法,其子类会有更加详细的具体功能的实现。下面介绍它的接种常见方法:
- void close() :关闭此输入流并释放与流关联的任何系统资源。
- abstract int read() :从输入流读取下一个数据字节。
- int read(byte[] b) :读取一定数量的字节从输入流并存入缓冲区阵列 b。
- int read(byte[] b, int off, int len) :读到 len字节从输入流读入字节数组数据。
close()方法是必须要调用的,因为IO流不能自动关闭,需要手动调用该方法以释放占用的资源
该抽象类有很多子类,下面介绍一个入门级且很常用的子类:FileInputStream
FileInputStream
FileInputStream从文件系统中的文件获得输入的字节
构造方法
- FileInputStream(File file) : 连接到实际的文件创建一个FileInputStream,文件在文件系统的 File对象 file命名。
- FileInputStream(String name) :连接到实际的文件创建一个FileInputStream,文件由文件系统中的路径名 name命名。
常用方法
- void close() :关闭此文件输入流并释放与流关联的任何系统资源。
- int read() :从这个输入流读取一个字节的数据。
- int read(byte[] b) :读到 b.length从输入流到字节数组数据字节。
- int read(byte[] b, int off, int len) :读到 len从输入流到字节数组数据字节。
代码实例
import org.junit.Test;import java.io.*;public class InPutStreamDemo1 { public static void main(String[] args) throws Exception { //创建操作文件输入流对象 InputStream inputStream = new FileInputStream("F:\\study\\程序员学习\\尚硅谷\\尚硅谷-大数据大神班2021(JD)\\阶段一\\1.javase&mysql\\02Javase-王泽\\05-JavaSE-Map和文件与IO\\test.txt"); //读取文件内容 int read = inputStream.read(); System.out.println((char) read); //关闭 inputStream.close(); } @Test public void readFile01() throws Exception { //创建操作文件输入流对象 InputStream inputStream = new FileInputStream("F:\\study\\程序员学习\\尚硅谷\\尚硅谷-大数据大神班2021(JD)\\阶段一\\1.javase&mysql\\02Javase-王泽\\05-JavaSE-Map和文件与IO\\test.txt"); //定义变量 int b; //循环判断读取 while((b = inputStream.read())!=-1) { System.out.println((char)b); } //关闭 inputStream.close(); } @Test public void readFile02() throws Exception { //创建操作文件输入流对象 InputStream inputStream = new FileInputStream("F:\\study\\程序员学习\\尚硅谷\\尚硅谷-大数据大神班2021(JD)\\阶段一\\1.javase&mysql\\02Javase-王泽\\05-JavaSE-Map和文件与IO\\test.txt"); //定义变量,保存数据 int len; //字节数组 byte[] b = new byte[1024]; //循环读取 while((len = inputStream.read(b))!=-1) { System.out.println(new String(b)); } //关闭 inputStream.close(); }}
字符流
前面介绍的字节流可以实现所有形式的文件的读写,不过对于中文字符,当我们使用字节流的时候,因为一个中文字符占用多个字节存储,所以它可能会显示不完整的字符。为了解决这样一种问题,Java中使用专门的字符流来读取中文字符,处理文本文件。
字符流是以字符为单位进行数据的读写
字符输入流
字符输入流是Reader,它是所有的输入字符流的父类,它是一个抽象类,它定义了字节输入流中的有些基本的方法,其子类会有更加详细的具体功能的实现。下面介绍它的接种常见方法:
- public void close():关闭此流并释放与此流相关联的任何系统资源
- public int read(): 从输入流读取一个字符
- public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组中
该抽象类有很多子类,下面介绍一个入门级且很常用的子类:FileReader
FileReader类
FileReader 类是用来读取字符文件。构造时使用系统默认的字符编码和默认字节缓冲区。
字符编码:IDEA默认的是UTF-8,Windows系统的中文编码默认是GBK
字节缓冲区:指的是用来临时存储字节数据的一个字节数组
构造方法
- FileReader(File file): 创建一个新的 FileReader ,创建要读取的File对象
- FileReader(String fileName): 创建一个新的 FileReader ,指定读取文件的名称
常用方法
- public int read(): 从输入流读取一个字符
- public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组中
代码实例
import org.junit.Test;import java.io.*;public class ReaderDemo { @Test public void demo1() throws Exception { Reader reader = new FileReader("你自己的文件位置\\test.txt"); //字符数组读取 char[] cbuf = new char[1024]; int len; while((len=reader.read(cbuf))!=-1) { System.out.println(new String(cbuf,0,len)); } reader.close(); } @Test public void demo2() throws Exception { // 使用文件名称创建流对象 Writer fw = new FileWriter("你自己的文件位置\\test.txt"); // 字符串转换为字节数组 char[] chars = "test".toCharArray(); // 写出字符数组 fw.write(chars); // test // 关闭资源 fw.close(); }}
字符输出流
字符输入流是Writer,它是所有的输出字符流的父类,它是一个抽象类,它定义了字节输出流中的有些基本的方法,其子类会有更加详细的具体功能的实现。下面介绍它的接种常见方法:
- void write(int c):写入单个字符
- void write(char[] cbuf) :写入字符数组
- abstract void write(char[] cbuf, int off, int len) :写入字符数组的某一部分,off数组的开始索引,len写的字符个数
- void write(String str) :写入字符串
- void write(String str, int off, int len) :写入字符串的某一部分,off字符串的开始索引,len写的字符个数
- void flush() :刷新该流的缓冲
- void close() : 关闭此流,但要先刷新它
该抽象类有很多子类,下面介绍一个入门级且很常用的子类:FileWriter
FileWriter类
FileWriter类是用来写出字符到文件的类。构造时使用系统默认的字符编码和默认字节缓冲区。
字符编码:IDEA默认的是UTF-8,Windows系统的中文编码默认是GBK
字节缓冲区:指的是用来临时存储字节数据的一个字节数组
构造方法
- FileWriter(File file): 创建一个新的 FileWriter,确定读取的File对象。
- FileWriter(String fileName): 创建一个新的 FileWriter,确定读取的文件名称。
当你创建一个流对象时,必须传入一个文件路径,类似于FileOutputStream
常用方法
- void write(int c):写入单个字符
- void write(char[] cbuf) :写入字符数组
- abstract void write(char[] cbuf, int off, int len) :写入字符数组的某一部分,off数组的开始索引,len写的字符个数
- void write(String str) :写入字符串
- void write(String str, int off, int len) :写入字符串的某一部分,off字符串的开始索引,len写的字符个数
- void flush() :刷新该流的缓冲,刷新后,写入才生效
- void close() : 关闭流,如果不关闭则数据只是被保存到缓冲区,并没有保存到文件,也可以用使用刷新的方法
代码示例
import org.junit.Test;import java.io.File;import java.io.FileWriter;import java.io.IOException;public class WriterDemo { @Test public void test1() throws IOException { // 使用File对象创建流对象 File file = new File("a.txt"); FileWriter fw1 = new FileWriter(file); // 使用文件名称创建流对象 FileWriter fw2 = new FileWriter("b.txt"); System.out.println(fw1); System.out.println(fw2); } @Test public void test2() throws IOException { // 使用文件名称创建流对象 FileWriter fw = new FileWriter("test1.txt"); fw.write(65); // 写出第1个字符 fw.write('b'); // 写出第2个字符 fw.write(30000); // 写出第3个字符,中文编码表中30000对应一个汉字 //fw.close(); //如果不关闭,则数据只是被保存到缓冲区,并没有保存到文件(也可以用flush) fw.flush();//用flush } @Test public void test3() throws IOException { // 使用文件名称创建流对象 FileWriter fw = new FileWriter("test2.txt"); FileWriter fw1 = new FileWriter("test3.txt"); // 字符串转换为字节数组 char[] chars = "test测试".toCharArray(); // 写出字符数组 fw.write(chars); // 写出从索引1开始,2个字节 fw1.write(chars,1,2); fw.close(); //如果不关闭,则数据只是被保存到缓冲区,并没有保存到文件(也可以用flush) fw1.close(); //如果不关闭,则数据只是被保存到缓冲区,并没有保存到文件(也可以用flush) } @Test public void test4() throws IOException { // 使用文件名称创建流对象 FileWriter fw = new FileWriter("test4.txt"); // 字符串 String str = "test字符串"; // 写出字符数组 fw.write(str); fw.close(); //如果不关闭,则数据只是被保存到缓冲区,并没有保存到文件(也可以用flush) } }
节点流
前面所提到的字符流和字节流都是节点流,他们都是直接作用于文件的流,除此之外,节点流一些,介绍如下:
- 文件进行处理的节点流:FileInputStream FileOutputStrean FileReader FileWriter
- 对字符串进行处理的节点流: StringReader StringWriter
- 对数组进行处理的节点流:ByteArrayInputStream ByteArrayOutputStreamCharArrayReader CharArrayWriter
- 对管道进行处理的节点流:PipedInputStream PipedOutputStream PipedReaderPipedWriter
处理流
处理流是在节点流的基础上又包了一层,然后对其进行操作。其主要目的是基于节点流进行操作,增强功能和性能。下面介绍三种常用处理流:
- 缓冲流:增加缓冲功能,避免频繁读写硬盘。
- 转换流:实现字节流和字符流之间的转换。
- 数据流:提供将基础数据类型写入到文件中,或者读取出来.
缓冲流
缓冲流,也叫高效流,它是通过对I/O进行缓冲,从而提升了性能,使其更加高效。所谓缓冲,是给I/O增加了缓冲区,通过缓冲区可以允许Java的I/O一次不只操作一个字符,提高了读写的效率 。
按照数据类型分类:
- 字节缓冲流:BufferedInputStream,BufferedOutputStream
- 字符缓冲流:BufferedReader,BufferedWriter
字节缓冲流
构造方法
- public BufferedInputStream(InputStream in) :创建一个缓冲输入流
- public BufferedOutputStream(OutputStream out): 创建一个缓冲输出流
字节缓冲流的使用和字节流是基本一致的(如下图),只不过效率完全不一样。缓冲流相对于普通流来说,效率大大提高了。(文章过长,这里不做代码证明了)
字符缓冲流
构造方法
- public BufferedReader(Reader in) :创建一个缓冲输入流
- public BufferedWriter(Writer out): 创建一个缓冲输出流
当对于前面的字节缓冲流,字符缓冲流新增了两个特有的方法(其他的基本方法与普通流也是一致的)
- BufferedReader:public String readLine(): 读一行文字
- BufferedWriter:public void newLine(): 写一行行分隔符,由系统属性定义符号
代码示例
import org.junit.Test;import java.io.*;public class Buffered { @Test public void test1() throws IOException { // 创建流对象 BufferedReader br = new BufferedReader(new FileReader("out.txt")); // 定义字符串,保存读取的一行文字 String line = null; // 循环读取,读取到最后返回null while ((line = br.readLine())!=null) { System.out.print(line); } // 释放资源 br.close(); } @Test public void test2() throws IOException { // 创建流对象 BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt")); // 写出数据 bw.write("test"); // 写出换行 bw.newLine(); bw.write("缓冲流"); bw.newLine(); // 释放资源 bw.close(); }}
转换流
众所周知,计算机是以二进制数存储信息的,但是我们所看到的都是二进制数转换后的文字信息,这其中就涉及了字节到字符的转换操作,这就是我们要讨论的转换流。
按照数据的流向分类:
- OutputStreamWriter类:将字符转为对应的字节
- InputStreamReader类:读取字节,将其转为对应的字符
InputStreamReader类
它是Reader的子类,实现了字节流转为字符流的转换操作。
字符集可以指定,不指定使用默认的
构造方法
- InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。
- InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。
代码实例
import java.io.FileInputStream;import java.io.InputStreamReader;public class TestDemo { public static void main(String[] args) throws Exception { // 定义文件路径,文件为gbk编码 String FileName = "你自己文件的位置\\test.txt"; // 创建流对象,默认UTF8编码 InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName)); // 创建流对象,指定GBK编码 InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName) , "GBK"); // 定义变量,保存字符 int read; // 使用默认编码字符流读取,乱码 while ((read = isr.read()) != -1) { System.out.print((char)read); } isr.close(); // 使用指定编码字符流读取,正常解析 while ((read = isr2.read()) != -1) { System.out.print((char)read);// 大家好 } isr2.close(); }}
OutputStreamWriter类
它是Reader的子类,实现了字符流转为字节流的转换操作。
字符集可以指定,不指定使用默认的
构造方法
- OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。
- OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。
代码实例
import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStreamWriter;public class TestDemo2 { public static void main(String[] args) throws IOException { // 定义文件路径 String FileName = "你自己的文件\\out.txt"; // 创建流对象,默认UTF8编码 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName)); // 写出数据 osw.write("DSyyds"); // 保存为6个字节 osw.close(); // 定义文件路径 String FileName2 = "你自己的文件\\out2.txt"; // 创建流对象,指定GBK编码 OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK"); // 写出数据 osw2.write("大数据"); osw2.close(); }}
数据流
前面的内容所设计的都是字符和字节,那针对于Java语言的基本数据类型和String的数据,上面两种流显然是不适用的,因此引入了数据流来解决这个问题。
按照数据流的方向分类:
- DataInputStream类:数据输入流
- DataOutputStream类:数据输出流
DataInputStream类
数据输入流,它是让应用程序读取原始java数据类型从底层输入流中的一个独立于机器的方式。
构造方法
- DataInputStream(InputStream in) :创建一个输入流InputStream使用指定的标。
代码实例
import org.junit.Test;import java.io.*;public class IoStreamDemo1 { //读操作 @Test public void readDataStream() throws Exception { //创建读数据流,把普通流包起来 DataInputStream dataInputStream = new DataInputStream(new FileInputStream("game.dat")); //读内容 String name = dataInputStream.readUTF(); char gender = dataInputStream.readChar(); //打印 System.out.println(name+","+gender); //数据流关闭 dataInputStream.close(); }}
DataOutputStream类
数据输出流,它可以让一个应用java写的原始数据类型在一个便携式的方式输出
构造方法
- DataOutputStream(OutputStream out) :创建一个新的数据输出流,将数据写入到指定的基本输出流中。
代码实例
import org.junit.Test;import java.io.*;public class IoStreamDemo1 { //写操作 @Test public void writeDataStream() throws Exception { //定义写入不同类型值 String name = "jack"; char gender = '男'; //创建写数据流,把普通流包起来 DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("game.dat")); //写入内容 dataOutputStream.writeUTF(name); dataOutputStream.writeChar(gender); //数据流关闭 dataOutputStream.close(); }}
开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系儿童百科