Java——IO流

IO流

一、java.io.File 类

File类是java.io包下代表与平台无关的文件和目录,也就是说如果希望在程序中操作文件和目录都可以通过File类来完成,File类能新建、删除、重命名文件和目录。

(1)递归打印多级目录

分析:多级目录的打印。遍历之前,无从知道到底有多少级目录,所以我们可以使用递归实现。

代码实现:

	@Test
	public void test3() {
		 File dir = new File("d:/atguigu");
		 listSubFiles(dir);
	}

	public void listSubFiles(File dir) {
		if (dir != null && dir.isDirectory()) {
			File[] listFiles = dir.listFiles();
			if (listFiles != null) {
				for (File sub : listFiles) {
					listSubFiles(sub);//递归调用
				}
			}
		}
		System.out.println(dir);
	}

(2)递归打印某目录下(包括子目录)中所有满足条件的文件

示例代码:列出"D:/atguigu"下所有".java"文件

	@Test
	public void test5() {
		 File dir = new File("D:/atguigu");
		 listByFileFilter(dir);
	}
	
	public void listByFileFilter(File file) {
		if (file != null && file.isDirectory()) {
			File[] listFiles = file.listFiles(new FilenameFilter() {

				@Override
				public boolean accept(File dir, String name) {
					return name.endsWith(".java") || new File(dir,name).isDirectory();
				}
			});
			if (listFiles != null) {
				for (File sub : listFiles) {
					if(sub.isFile()){
						System.out.println(sub);
					}else
						listByFileFilter(sub);
				}
			}
		}
	}

(3)递归求目录总大小

	@Test
	public void test4() {
		 File dir = new File("D:/atguigu");
		 long length = getLength(dir);
		 System.out.println("大小:" + length);
	}
	
	public long getLength(File dir){
		if (dir != null && dir.isDirectory()) {
			File[] listFiles = dir.listFiles();
			if(listFiles!=null){
				long sum = 0;
				for (File sub : listFiles) {
					sum += getLength(sub);
				}
				return sum;
			}
		}else if(dir != null && dir.isFile()){
			return dir.length();
		}
		return 0;
	}

(4)递归删除非空目录

如果目录非空,连同目录下的文件和文件夹一起删除

	@Test
	public void test6() {
		 File dir = new File("D:/atguigu/javase");
		 forceDeleteDir(dir);
	}
	public void forceDeleteDir(File dir) {
		if (dir != null && dir.isDirectory()) {
			File[] listFiles = dir.listFiles();
			if(listFiles!=null){
				for (File sub : listFiles) {
					forceDeleteDir(sub);
				}
			}
		}
		dir.delete();
	}

二、IO流

表示对数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input输出output ,即流向内存是输入流,流出内存的输出流。

IO 流 的分类可以分为以下三种:

  • 输入流和输出流
    按照流的流向来分,可以分为输入流和输出流。输入,输出都是从程序运行所在内存的角度来划分的。
    • 输入流只能从中读取数据,而不能向其写入数据。InputStream 和 Reader 作为基类
    • 输出流只能向其写入数据,不能从中读取数据。OutputStream 和 Writer 作为基类
  • 字节流和字符流
    字节流和字符流的用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不同。
    • 字节流操作的数据单元是8位字节,由 InputStream 和 OutputStream 作为基类。
    • 字符流操作的数据单元是16位的字符, 由 Reader 和 Writer 作为基类
  • 节点流和处理流
    按照流的角色来分,可以分为节点流和处理流。
    • 节点流:可以人向一个特定的IO设备(如磁盘、网络) 读 / 写。也被称为低级流。
    • 处理流:用于对一个已存在的流进行连接或封装,通过封装后的流来实现数据读/写功能。也称为高级流

一、字节流

一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。

1.1 字节输出流【OutputStream】

java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。

  • FileOutputStream类
    java.io.FileOutputStream 类是文件输出流,用于将数据写出到文件。
1.2 字节输入流【InputStream】
  • FileInputStream类
    java.io.FileInputStream 类是文件输入流,从文件中读取字节。

二、字符流

当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
文件字符输出流默认自带一个 8k 大小的数据缓冲区, 写出数据时先进入缓冲区,当缓冲区满后才会自动写出到文件。目的时提高 IO 性能

flush 方法: 刷新缓冲区, 把数据直接写出去
close方法:先刷新缓冲区, 再关闭流

1.1 字符输入流【Reader】

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

  • FileReader类
    java.io.FileReader 类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
    节缓冲区:一个字节数组,用来临时存储字节数据。
1.2 字符输出流【Writer】

java.io.Writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。

  • FileWriter类

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

三、缓冲流

缓冲流,也叫高效流,按照数据类型分类:

字节缓冲流BufferedInputStreamBufferedOutputStream
字符缓冲流BufferedReaderBufferedWriter

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

1.1 字节缓冲流
  • BufferedInputStream
  • BufferedOutputStream
1.2 字符缓冲流
  • BufferedReader
  • BufferedWriter

四、转换流

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

1.1 InputStreamReader类

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

1.2 OutputStreamWriter类

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

五、数据流

前面学习的IO流,在程序代码中,要么将数据直接按照字节处理,要么按照字符处理。那么,如果要在程序中直接处理Java的基础数据类型,怎么办呢?

String name = “巫师”;
int age = 300;
char gender = ‘男’;
int energy = 5000;
double price = 75.5;
boolean relive = true;

完成这个需求,可以使用DataOutputStream进行写,随后用DataInputStream进行读取,而且顺序要一致。

示例代码:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class TestData {
	public void save() throws IOException{
		String name = "巫师";
		int age = 300;
		char gender = '男';
		int energy = 5000;
		double price = 75.5;
		boolean relive = true;
		
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("game.dat"));
		dos.writeUTF(name);
		dos.writeInt(age);
		dos.writeChar(gender);
		dos.writeInt(energy);
		dos.writeDouble(price);
		dos.writeBoolean(relive);
		dos.close();
	}	
	public void reload()throws IOException{
		DataInputStream dis = new DataInputStream(new FileInputStream("game.dat"));
		String name = dis.readUTF();
		int age = dis.readInt();
		char gender = dis.readChar();
		int energy = dis.readInt();
		double price = dis.readDouble();
		boolean relive = dis.readBoolean();
		
		System.out.println(name+"," + age + "," + gender + "," + energy + "," + price + "," + relive);
		
		dis.close();
	}
}

六、对象流与序列化

Java 提供了一种对象序列化的机制。用字节序列可以表示一个对象,该字节序列包含该对象的类型对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。

反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化对象的数据对象的类型对象中存储的数据信息,都可以用来在内存中创建对象。

1. ObjectOutputStream类

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。

2. ObjectInputStream类

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

3. 序列化操作
  • 该类必须实现java.io.Serializable 接口,Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException

  • 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用 transient 关键字修饰。(比如网络中传输时,考虑安全因素银行卡字段可以使用transient不进行序列化)

  • 静态变量的值不会序列化(静态变量的值不属于某个对象的数据,而是属于类的数据)

  • 另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。发生这个异常的原因如下:

    • 该类的序列版本号与从流中读取的类描述符的版本号不匹配
    • 该类包含未知数据类型
  • Serializable 接口给需要序列化的类,提供了一个序列版本号。serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

七、打印流 PrintStream 与 PrintWriter

打印流只有输出没有输入

八、标准输入 / 输出流

System类中有三个属性字段:

Modifier and TypeField and Description
static PrintStreamerr The “standard” error output stream.
static InputStreamin The “standard” input stream.
static PrintStreamout The “standard” output stream.

System.in 标准输入流,本质是一个字节输入流,默认接受键盘录入的数据。

System.out 标准输出流,本质是一个字节输出流,默认输出数据到控制台。

九、JDK1.7之后引入新 try…catch

它没有finally,也不需要程序员去关闭资源对象,无论是否发生异常,都会关闭资源对象

try(需要关闭的资源对象的声明){
    业务逻辑代码,可能发生异常的代码
}catch(异常类型 e){
    处理异常代码
}catch(异常类型 e){
    处理异常代码
}
....

十、IOUtils工具类

IOUtils是Apache出品的一个方便IO操作的工具类,简化了IO流的读、写、复制及关闭流等操作(使用前需要导包)

    @Test
    public void test2() throws IOException {
        IOUtils.copy(new FileInputStream("ps.txt"), new FileOutputStream("pw.txt"));//复制文件
        IOUtils.write("hello world",new FileOutputStream("ps.txt"),"UTF-8");//写数据到文件
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值