I/O操作

1. 引言

       文件可以分为文本或者二进制的, 文本文件是由字符序列构成的,二进制文件是由位(bit)构成的。
  Java提供了许多类实现文本I/O和二进制I/O。这些类可以分为文本I/O和二进制I/O。
  二进制I/O不涉及编码和解码,因此二进制I/O比文本I/O更加高效。对于文本I/O而言,编码和解码时自动进行的。

在实际的开发过程中使用commons-io.jar包中封装好的类

2. 基本概念

字符流、字节流
  字节流:字节流是按照字节去读写数据的,读取是以单个字节为单位,操作对象一般为二进制文件 根类是InputStream和OutputStream
  字符流:按照字符去读取数据的,一般用于字符文件,字符流是由java虚拟机将单个字节转换为两个字节的unicode字符,操作对象一般为文本,根类为Reader和Writer

节点流和处理流
  节点流:可以直接从数据源或者目的地读写数
  处理流(包装流):不直接连接到数据源或者目的地,是其他流进行封装,他的构造方法主要是传入节点流的子类,处理流的子类必须传入节点流的子类。主要是简化操作和提高性能。

3. I/O类结构

图片来自网络:
Alt

4. 字节流

       抽象类InputStream是读取二进制数据的根类,抽象类OutputStream是写入二进制数据的根类。
  FileInputStream和FileOutputStream类用于从/向文件读取/写入字节。

5. ByteArrayInputStream和ByteArrayOutputStream

       字节数组输入流ByteArrayInputStream:在内存中创建一个字节数组缓冲区,从输入流中读取的数据保存在字节数组缓冲区中,从字节数组中读取数据。
  字节数组输出流ByteArrayOutputStream:在创建字节数组输出流的同时,内存会为该输出流创建一个默认大小的字节数组,用来存储写入的字节内容。

5.1. DateInputStream和DateOutputStream

DataInputStream从数据流中读取字节,并将其转换为指定的基本数据类型或字符串。
  DataOutputStream将基本数据类型或者字符串转换为字节,并将字节输出到数据流。

5.2. BufferedInputStream和BufferedOutputStream

       BufferedInputStream和BufferedOutputStream类可以通过减少磁盘读写次数来提高输入输出的速度。将磁盘上的数据一次性的读入到内存的缓冲区中,然后将缓冲区中的个别数据传递到程序中,反之,先将数据写入到缓冲区,当缓冲区满后,一次性将数据写入到磁盘中,减少磁盘的读写次数。
  缓冲区的大小默认是512个字节。

public static void main(String[] args) {
	//创建源
	String path = "src/main/java/io/temp.txt";

	//使用缓冲输入流
	try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(path))) {

		byte[] b = new byte[1024];
		int len = -1;
		//读取字节数据
		while ((len = bufferedInputStream.read(b)) != -1) {
			//将字节数组转换为字符串
			String string = new String(b, 0, b.length);
			System.out.println(string);
		}
	} catch (IOException e) {

		e.printStackTrace();
	}
}

5.3. 对象I/O

5.3.1. ObjectInputStream和ObjectOutputStream

       ObjectInputStrem和ObjectOutputStream用于读写可序列化的对象,还可以实现基本数据类型与字符串的输入与输
出,可以代替DataOutputStream和DataInputStream。

public static void main(String[] args) {
	//创建源
	String path = "src/main/java/io/temp2.txt";
	try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(path))) {

		//输出字符串
		objectOutputStream.writeUTF("hello world");
		//输出对象
		objectOutputStream.writeObject("hello world1");
		//创建对象在输出
		ArrayList<String> arrayList = new ArrayList<String>();
		arrayList.add("helloworld3");
		objectOutputStream.writeObject(arrayList);

	} catch (IOException e) {

		e.printStackTrace();
	}

	//输入流,自动关闭流
	try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(path))) {
		//读字符串
		System.out.println(objectInputStream.readUTF());
		System.out.println(objectInputStream.readObject());
		ArrayList<String> list = (ArrayList<String>) objectInputStream.readObject();
		System.out.println(list.get(0));
		
	} catch (IOException | ClassNotFoundException e) {

		e.printStackTrace();
	}

}

5.3.2. 关于Serializable接口

       Serializable接口是一种标记接口,实现这个接口可以启动java序列化机制,自动完成存储对象和数组的过程。
  存储对象的过程称为对象序列化,是将对象转换为二进制存储到硬盘上;读取对象的过程称为对象的反序列化,是将硬盘上的对象二进制文件转换为对象读到程序中去。
  要实现对象的序列化必须实现Serializable接口,该接口没有任何方法,可以理解为一个标记,表明这个类是可序列化的。
  SerivalVersionUID字段的作用:这是版本号,保持版本号一直来进行序列化,防止序列化出错。

6. 字符流Reader和Writer

字符流的操作单位是字符,只能用来操作文本。

public static void main(String[] args) {
	//创建源
	String path = "src/main/java/io/temp3.txt";
	//创建字符缓冲流,并指定缓冲流的大小
	try (BufferedWriter writer = new BufferedWriter(new FileWriter(path), 1024)) {
		//写入字符和字符串
		writer.write('h');
		//每个空格均为字符
		writer.write("hello    world");

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

	//读取字符
	try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
		int size = 0;
		//每次读取两个字符
		char[] cbuf = new char[2];
		while ((size = reader.read(cbuf, 0, cbuf.length)) != -1) {
			System.out.println(new String(cbuf, 0, size));
		}
		//当没有字符时会读取到-1
		System.out.println("此时字符已经读取完毕:" + reader.read());

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

}

6.1. 转换流

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

7. 关闭流

       在实际开发中,经常会在程序中打开一些物理资源,如数据库的连接,网络连接,磁盘文件等,打开这些资源呢必须显示关闭,否则会引起的资源泄露。
  JVM中的垃圾回收机制属于java内存管理的一部分,他只回收堆内存中分配出来的内存,至于程序中打开的物理资源垃圾回收机制是无能为力的。

7.1. 不关闭流的影响

如果不关闭资源或者不正确的关闭资源,会导致程序还在占用着资源,浪费资源,随着运行时间的加倍,一方面会内存泄露,另一方面会导致其他资源的代码获取不到资源,这样获取资源的线程会在获取资源上卡住。

7.2. 关于资源泄露

       资源是存在于内存中的,资源泄露也叫做内存泄露。还有一种特指的内存泄露,指的是动态分配得到一个内存块,在使用完成后,忘记释放,这是单纯的内存泄露。
  操作系统规定,进程申请的内存,只要没释放,且进程没有中止,那么这个内存就是属于进程的,这块内存就不能被其他进程所使用。如果你之前申请的内存,在使用完后没有释放,然后又重新申请,这样之前的内存没有任何指针指向,也就无法操作,对于你的进程来说,这个内存就丢失了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值