Java的IO流是实现输入/输出的基础,它可以方便地实现数据的输入/输出操作,在Java中把不同的输入/输出源(键盘、文件、网络连接等)抽象表述为“流”(stream),通过流的方式允许Java程序使用相同的方式来访问不同的输入输出源。
stream是从起源(source)到接收(sink)的有序数据。Java把所有传统的流类型(类或抽象类)都放在java.io包中,用以实现输入输出功能。
一、流的分类:
1、节点流与非节点流
1.1 节点流
节点流:直接与数据源相连,读入或读出。
直接使用节点流,读写不方便,为了更快的读写文件,才有了处理流。
这里写图片描述
常用的节点流
父 类 :InputStream
、OutputStream
、 Reader
、 Writer
文 件 :FileInputStream
、 FileOutputStrean
、FileReader
、FileWriter
文件进行处理的节点流
数 组 :ByteArrayInputStream
、 ByteArrayOutputStream
、 CharArrayReader
、CharArrayWriter
对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)
字符串 :StringReader
、 StringWriter
对字符串进行处理的节点流
管 道 :PipedInputStream
、PipedOutputStream
、PipedReader
、PipedWriter
对管道进行处理的节点流
1.2 处理流
处理流和节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。
这里写图片描述
常用的处理流
缓冲流:BufferedInputStrean
、BufferedOutputStream
、 BufferedReader
、 BufferedWriter
增加缓冲功能,避免频繁读写硬盘。
转换流:InputStreamReader
、OutputStreamReader
实现字节流和字符流之间的转换。
数据流: DataInputStream
、DataOutputStream
等-提供将基础数据类型写入到文件中,或者读取出来。
1.3 转换流
InputStreamReader
、OutputStreamWriter
要InputStream
或OutputStream
作为参数,实现从字节流到字符流的转换。
Java的IO流共涉及40多个类,这些类看上去芜杂而凌乱,但实际上非常规则,而且彼此之间存在非常紧密的联系Java的IO流的40多个类都是从如下4个抽象基类派生的。
1、输入流和输出流
按照流的流向来分,可以分为输入流和输出流。输入、输出都是从程序运行所在内存的角度来划分的。
输入流:只能从中读取数据,而不能向其写入数据。由InputStream和Reader作为基类
输出流:只能向其写入数据,而不能从中读取数据。由OutputStream和Writer作为基类
2、字节流和字符流
字节流和字符流的用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不同。字节流操作的数据单元是字节,字符流操作的数据单元是字符。
**字节流:**操作的数据单元是8位的字节,由InputStream和OutputStream作为基类。
**字符流:**操作的数据单元是16位的字符,由 Reader和 Writer作为基类。
3、节点流和处理流
按照流的角色来分,可以分为节点流和处理流。
节点流:可以从向一个特定的IO设备(如磁盘、网络)读/写数据的流。也被称为低级流。
处理流:用于对一个已存在的流进行连接或封装,通过封装后的流来实现数据读/写功能。也称为高级流。
4、Stream流:
根据Collection获取流:
Set<String> set = new HashSet<>(); //通过 stream 默认方法获取流 Stream<String> stream2 = set.stream();
方式2: 根据数组获取流
//通过Stream 接口中提供了静态方法of Stream<String> stream = Stream.of(array);
——常用方法:
终结方法:返回值类型不再是 Stream 接口自身类型的方法
count:统计个数 forEach 方法:并不保证元素的在流中是被有序执行的。
非终结方法:返回值类型仍然是 Stream 接口自身类型的方法;
filter:过滤 limit:取用前几个; skip:跳过前几个; Stream<String> result = original.skip(2); concat:组合,把两个流合并成一个; Stream<String> result = Stream.concat(streamA, streamB);
与Lambda表达式联合使用:
list.stream() .filter(s -> s.startsWith("张")) //过滤开头为张的 .filter(s -> s.length() == 3) //过滤长度为3的 .forEach(s -> System.out.println(s)); //打印 }
5、函数拼接与终结方法
凡是返回值仍然为 Stream 接口的为函数拼接方法,它们支持链式调用;而返回值不再
为 Stream 接口的为终结方法,不再支持链式调用
二、File类
1、File类
类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。
2、构造方法:
public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。 public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的 File实例。 public File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。
3、常用方法
public String getAbsolutePath() :绝对路径名(字符串) public String getPath() : 构造路径名(字符串) public String getName() : 文件或目录的名称。 public long length() : 文件的长度。
File f = new File("d:/aaa/bbb.java"); 输出结果: 文件绝对路径:d:\aaa\bbb.java 文件构造路径:d:\aaa\bbb.java 文件名称:bbb.java 文件长度:636字节
**绝对路径:**从盘符开始的路径,这是一个完整的路径。
**相对路径:**相对于项目目录的路径,这是一个便捷的路径,开发中经常使用。
4、判断功能的方法
public boolean exists() : 此File表示的文件或目录是否实际存在。 public boolean isDirectory() :此File表示的是否为目录。 public boolean isFile() : 此File表示的是否为文件。
5、创建删除功能的方法
public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。 public boolean mkdir() : 创建由此File表示的目录。 public boolean mkdirs() : 创建由此File表示的目录,包括任何必需但不存在的父目录。 public boolean delete() : 删除由此File表示的文件或目录,java中删除动作不走回收站。
6、目录的遍历
public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。 public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录
目录遍历的代码:
//获取当前目录下的文件以及文件夹的名称。 String[] names = dir.list(); for(String name : names){ System.out.println(name); }
7、递归搜索文件
——文件搜索:
public class DiGuiDemo3 { public static void main(String[] args) { // 创建File对象 File dir = new File("D:\\aaa"); // 调用打印目录方法 printDir(dir); } public static void printDir(File dir) { // 获取子文件和目录 File[] files = dir.listFiles(); // 循环打印 for (File file : files) { if (file.isFile()) { // 是文件,判断文件名并输出文件绝对路径 if (file.getName().endsWith(".java")) { System.out.println("文件名:" + file.getAbsolutePath()); } else { // 是目录,继续遍历,形成递归 printDir(file); }
三、基本流(字节流、字符流)
1、分类:
2、字节流:
2.1 字节输出流【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) :将指定的字节输出流。
2.2 子类【FileOutputStream】
构造方法:
public FileOutputStream(File file) :创建文件输出流以写入由指定的 File对象表示的文件。 public FileOutputStream(String name) : 创建文件输出流以指定的名称写入文件。
public class FOSWrite { public static void main(String[] args) throws IOException { // 使用文件名称创建流对象 FileOutputStream fos = new FileOutputStream("fos.txt"); // 字符串转换为字节数组 byte[] b = "abcde".getBytes(); // 写出从索引2开始,2个字节。也就是cd。 fos.write(b,2,2); // 关闭资源 fos.close(); } 输出结果: cd
数据的追加
public FileOutputStream(File file, boolean append) : 创建文件输出流以写入由指定的 File对象表示的文件。 public FileOutputStream(String name, boolean append) : 创建文件输出流以指定的名称写入文件。 true 表示追加数据, false 表示清空原有数据。 为false:cd 为true:cdabcde
Windows系统里,换行符号是 \r\n
2.3 字节输入流【InputStream】
共性的的方法:
public void close() : 关闭此输入流并释放与此流相关联的任何系统资源。 public abstract int read() : 从输入流读取数据的下一个字节。 public int read(byte[] b) : 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
2.4 子类【FileInputStream】
——构造方法:
FileInputStream(File file) : 通过打开与实际文件的连接来创建一个 FileInputStream , 该文件由文件系统中的 File对象 file命名。 FileInputStream(String name) : 通过打开与实际文件的连接来创建一个 FileInputStream , 该文件由文件系统中的路径名 name命名
流操作完毕后,必须释放系统资源,调用close方法,千万记得。
重要代码:
public class Copy { public static void main(String[] args) throws IOException { // 1.创建流对象 FileInputStream fis = new FileInputStream("D:\\test.jpg"); FileOutputStream fos = new FileOutputStream("test_copy.jpg"); // 2.读写数据 byte[] b = new byte[1024]; int len; while ((len = fis.read(b))!=-1) { fos.write(b, 0 , len); } // 3.关闭资源 fos.close(); fis.close(); }
3、字符流
3.1 字符输入流【Reader]
共性方法:
public void close() : 关闭此流并释放与此流相关联的任何系统资源。 public int read() : 从输入流读取一个字符。 public int read(char[] cbuf) : 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中
3.2 子类:【FileReader类]
构造方式:
FileReader(File file) : 创建一个新的 FileReader ,给定要读取的File对象。 FileReader(String fileName) : 创建一个新的 FileReader ,给定要读取的文件的名称。
3.3 字符输出流【Writer】
共性方法:
public abstract void close() : 关闭流,释放系统资源。关闭前会刷新缓冲区 public abstract void flush() : 刷新缓冲区,流对象可以继续使用。 public void write(int c) : 写出一个字符。 public void write(char[] cbuf) :将 b.length字符从指定的字符数组写出此输出流。 public abstract void write(char[] b, int off, int len) : 从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。 public void write(String str) : 写出一个字符串。
3.4 子类【FileWriter】
构造方法:
FileWriter(File file) : 创建一个新的 FileWriter,给定要读取的File对象。 FileWriter(String fileName) : 创建一个新的 FileWriter,给定要读取的文件的名称
flush : 刷新缓冲区,流对象可以继续使用。
close : 关闭流,释放系统资源。关闭前会刷新缓冲区
即便是flush方法写出了数据,操作的最后还是要调用close方法,释放系统资源。
字符流,只能操作文本文件,不能操作图片,视频等非文本文件。
当我们单纯读或者写文本文件时 使用字符流 其他情况使用字节流
IO异常的处理
利用try…catch进行处理
try { //可能产生异常的位置 fw = new FileWriter("fw.txt"); } catch (IOException e) { e.printStackTrace();//异常的处理方式 } finally { //无论怎样都会执行的代码 }
4、属性集Properties类
构造方式:
public Properties() : 创建一个空的属性列表
基本方法:
public Object setProperty(String key, String value) : 保存一对属性。 public String getProperty(String key) : 使用此属性列表中指定的键搜索属性值。 public Set<String> stringPropertyNames() : 所有键的名称的集合
基本储存属性的方式(存储在properties对象中):
// 创建属性集对象 Properties properties = new Properties(); // 添加键值对元素 properties.setProperty("filename", "a.txt"); // 打印属性集对象 System.out.println(properties); // 通过键,获取属性值 System.out.println(properties.getProperty("filename"));
利用流的方式从文件中获取属性:
public void load(InputStream inStream) : 从字节输入流中读取键值对。
public static void main(String[] args) throws FileNotFoundException { // 创建属性集对象 Properties pro = new Properties(); // 加载文本中信息到属性集 pro.load(new FileInputStream("read.txt")); // 遍历集合并打印 Set<String> strings = pro.stringPropertyNames(); for (String key : strings ) { System.out.println(key+" -- "+pro.getProperty(key)); }//filename -- a.txt
四、缓冲流
1、缓冲流
缓冲流,也叫高效流,是对4个基本的 FileXxx 流的增强,所以也是4个流;
—分类:
字节缓冲流: BufferedInputStream , BufferedOutputStream
字符缓冲流: BufferedReader , BufferedWriter
—基本原理:
是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率
2、字节缓冲流【BufferedInputStream】【BufferedOutputStream】
构造方法:
public BufferedInputStream(InputStream in) : 创建一个 新的缓冲输入流。public BufferedOutputStream(OutputStream out) : 创建一个新的缓冲输出流。
缓存流的速度比基本的流对象的传输速度快了很多;
3、字符缓冲流【BufferedReader】【BufferedWriter】
构造方法:
public BufferedReader(Reader in) :创建一个 新的缓冲输入流。 public BufferedWriter(Writer out) : 创建一个新的缓冲输出流。
特有的方法:
BufferedReader: public String readLine() : 读一行文字。 BufferedWriter: public void newLine() : 写一行行分隔符,(也就是换行)。
——文字排序的案例:
public class BufferedTest { public static void main(String[] args) throws IOException { // 创建map集合,保存文本数据,键为序号,值为文字 HashMap<String, String> lineMap = new HashMap<>(); // 创建流对象 BufferedReader br = new BufferedReader(new FileReader("in.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt")); // 读取数据 String line = null; while ((line = br.readLine())!=null) { // 解析文本 String[] split = line.split("\\."); // 保存到集合 lineMap.put(split[0],split[1]); } // 释放资源 br.close(); // 遍历map集合 for (int i = 1; i <= lineMap.size(); i++) { String key = String.valueOf(i); // 获取map中文本 String value = lineMap.get(key); // 写出拼接文本 bw.write(key+"."+value); // 写出换行 bw.newLine(); } // 释放资源 bw.close(); }
五、转换流
1、转换流【InputStreamReader】【OutputStreamWriter类】
构造方法:
InputStreamReader(InputStream in) : 创建一个使用默认字符集的字符流。 InputStreamReader(InputStream in, String charsetName) : 创建一个指定字符集的字符流
——OutputStreamWriter类
构造方法:
OutputStreamWriter(OutputStream in) : 创建一个使用默认字符集的字符流。 OutputStreamWriter(OutputStream in, String charsetName) : 创建一个指定字符集的字符流。
2、案例:转换文件编码
将GBK编码的文本文件,转换为UTF-8编码的文本文件。
- 指定GBK编码的转换流,读取文本文件。
- 使用UTF-8编码的转换流,写出文本文件。
public class TransDemo { public static void main(String[] args) { // 1.定义文件路径 String srcFile = "file_gbk.txt"; String destFile = "file_utf8.txt"; // 2.创建流对象 // 2.1 转换输入流,指定GBK编码 InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile) , "GBK"); // 2.2 转换输出流,默认utf8编码 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destFile)); // 3.读写数据 // 3.1 定义数组 char[] cbuf = new char[1024]; // 3.2 定义长度 int len; // 3.3 循环读取 while ((len = isr.read(cbuf))!=-1) { // 循环写出 osw.write(cbuf,0,len); } // 4.释放资源 osw.close(); isr.close(); }
六、序列化流
1、序列化【ObjectOutputStream类】
构造方法:
public ObjectOutputStream(OutputStream out) : 创建一个指定OutputStream的ObjectOutputStream
—序列化条件:
1、实现 java.io.Serializable 接口,只是标记接口;没有具体方法;
2、该类的所有属性必须是可序列化的。若有不需要可序列化的,使用transient 关键字修饰
public class Employee implements java.io.Serializable { public String name; public String address; public transient int age; // transient瞬态修饰成员,不会被序列化 }
—写出对象的方法:
public final void writeObject (Object obj) : 将指定的对象写出
User user = new User(); user.name = "zhangsan"; // 创建序列化流对象 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt")); // 写出对象 out.writeObject(user); // 释放资源 out.close(); fileOut.close();
2、反序列化【ObjectInputStream类】
反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
构造方法:
public ObjectInputStream(InputStream in) : 创建一个指定InputStream的ObjectInputStream。
方法:
public final Object readObject () : 读取一个对象。
案例:
// 创建反序列化流 FileInputStream fileIn = new FileInputStream("employee.txt"); ObjectInputStream in = new ObjectInputStream(fileIn); // 读取一个对象(User是一个bean对象名) User e = (User) in.readObject(); // 释放资源 in.close(); fileIn.close();
七、打印流【PrintStream】
public PrintStream(String fileName) : 使用指定的文件名创建一个新的打印流
更改打印流的输出位置:
public class PrintDemo { public static void main(String[] args) throws IOException { // 调用系统的打印流,控制台直接输出97 System.out.println(97); // 创建打印流,指定文件的名称 PrintStream ps = new PrintStream("ps.txt"); // 设置系统的打印流流向,输出到ps.txt System.setOut(ps); // 调用系统的打印流,ps.txt中输出97 System.out.println(97); }
八、字符编码和字符集
编码: 按照某种规则,将字符存储到计算机中;
解码: 将存储在计算机中的二进制数按照某种规则解析显示出来;
常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。
九、常用工具类
1、读取文件中数据
/** * @param filePath 文件目录 * @return */ public static String getFileData(String filePath) { try { // 1.创建流对象 FileInputStream fis = null; fis = new FileInputStream(filePath); StringBuilder stringBuilder = new StringBuilder(); // 2.读写数据 byte[] b = new byte[1024]; int len; while ((len = fis.read(b)) != -1) { String s = new String(b, 0, len); stringBuilder.append(s); } // 3.关闭资源 fis.close(); return stringBuilder.toString(); } catch (IOException e) { log.error("获取文件失败:{}", e.getMessage()); return null; } }
十、Xmind整理
https://download.csdn.net/download/weixin_44624117/12702080
链接:https://pan.baidu.com/s/1zF1ryT89AHdXdkLyduaNew 提取码:5l0s