Java IO详解(七)------随机访问文件流

 File 类的介绍:https://cloud.tencent.com/developer/article/1012532

Java IO 流的分类介绍:https://cloud.tencent.com/developer/article/1012539

Java IO 字节输入输出流:https://cloud.tencent.com/developer/article/1012565

Java IO 字符输入输出流:https://cloud.tencent.com/developer/article/1012570

Java IO 包装流:https://cloud.tencent.com/developer/article/1012576

Java IO 对象流(序列化与反序列化):https://cloud.tencent.com/developer/article/1012578

1、什么是 随机访问文件流 RandomAccessFile?

  该类的实例支持读取和写入随机访问文件。 随机访问文件的行为类似于存储在文件系统中的大量字节。 有一种游标,或索引到隐含的数组,称为文件指针 ; 输入操作读取从文件指针开始的字节,并使文件指针超过读取的字节。 如果在读/写模式下创建随机访问文件,则输出操作也可用; 输出操作从文件指针开始写入字节,并将文件指针提前到写入的字节。 写入隐式数组的当前端的输出操作会导致扩展数组。 文件指针可以通过读取getFilePointer方法和由设置seek方法。

  通俗来讲:我们以前讲的 IO 字节流,包装流等都是按照文件内容的顺序来读取和写入的。而这个随机访问文件流我们可以再文件的任意地方写入数据,也可以读取任意地方的字节。

我们查看 底层源码,可以看到:

public class RandomAccessFile implements DataOutput, DataInput, Closeable {

  实现了 DataOutput类,DataInput类,那么这两个类是什么呢?

2、数据流:DataOutput,DataInput

  ①、DataOutput:提供将数据从任何Java基本类型转换为一系列字节,并将这些字节写入二进制流。 还有一种将String转换为modified UTF-8格式(这种格式会在写入的数据之前默认增加两个字节的长度)并编写结果字节系列的功能。

  ②、DataInput:提供从二进制流读取字节并从其中重建任何Java原语类型的数据。 还有,为了重建设施String从数据modified UTF-8格式。 

下面我们以其典型实现:DataOutputSteam、DataInputStream 来看看它的用法:

//数据输出流
		File file = new File("io"+File.separator+"a.txt");
		DataOutputStream dop = new DataOutputStream(new FileOutputStream(file));
		//写入三种类型的数据
		dop.write(65);
		dop.writeChar('哥');
		dop.writeUTF("帅锅");
		dop.close();
		
		//数据输入流
		DataInputStream dis = new DataInputStream(new FileInputStream(file));
		System.out.println(dis.read());  //65
		System.out.println(dis.readChar());	//哥
		System.out.println(dis.readUTF());	//帅锅
		dis.close();

3、通过上面的例子,我们可以看到因为 RandomAccessFile 实现了数据输入输出流,那么 RandomAccessFile 这一个类就可以完成 输入输出的功能了。

这里面第二个参数:String mode 有以下几种形式:(ps:为什么这里的值是固定的而不弄成枚举形式,不然很容易写错,这是因为随机访问流出现在枚举类型之前,属于Java 历史遗留问题)

 第一种:用 随机流顺序读取数据

public class RandomAccessFileTest {
	public static void main(String[] args) throws Exception {
		File file = new File("io"+File.separator+"a.txt");
		write(file);
		read(file);
	}
	
	/**
	 * 随机流读数据
	 */
	private static void read(File file) throws Exception {
		//以 r 即只读的方法读取数据
		RandomAccessFile ras = new RandomAccessFile(file, "r");
		byte b = ras.readByte();
		System.out.println(b); //65
		
		int i = ras.readInt();
		System.out.println(i); //97
		
		String str = ras.readUTF(); //帅锅
		System.out.println(str);
		ras.close();
	}

	/**
	 * 随机流写数据
	 */
	private static void write(File file) throws Exception{
		//以 rw 即读写的方式写入数据
		RandomAccessFile ras = new RandomAccessFile(file, "rw");
		ras.writeByte(65);
		ras.writeInt(97);
		ras.writeUTF("帅锅");
		
		ras.close();
	}

}

第二种:随机读取,那么我们先介绍这两个方法

这里所说的偏移量,也就是字节数。一个文件是有N个字节数组成,那么我们可以通过设置读取或者写入的偏移量,来达到随机读取或写入的目的。

我们先看看Java 各数据类型所占字节数:

下面是 随机读取数据例子:

/**
	 * 随机流读数据
	 */
	private static void read(File file) throws Exception {
		//以 r 即只读的方法读取数据
		RandomAccessFile ras = new RandomAccessFile(file, "r");
		
		byte b = ras.readByte();
		System.out.println(b); //65
		//我们已经读取了一个字节的数据,那么当前偏移量为 1
		System.out.println(ras.getFilePointer());  //1 
		//这时候我们设置 偏移量为 5,那么可以直接读取后面的字符串(前面是一个字节+一个整型数据=5个字节)
		ras.seek(5);
		String str = ras.readUTF(); //帅锅
		System.out.println(str);
		
		//这时我们设置 偏移量为 0,那么从头开始
		ras.seek(0);
		System.out.println(ras.readByte()); //65
		
		//需要注意的是:UTF 写入的数据默认会在前面增加两个字节的长度
		
		ras.close();
	}

 随机流复制文件:

/**
	 * 随机流复制文件
	 * @param fileA
	 * @param B
	 * @throws Exception 
	 */
	private static void copyFile(File fileA,File fileB) throws Exception{
		
		RandomAccessFile srcRA = new RandomAccessFile(fileA, "rw");
		RandomAccessFile descRA = new RandomAccessFile(fileB, "rw");
		
		//向 文件 a.txt 中写入数据
		srcRA.writeByte(65);
		srcRA.writeInt(97);
		srcRA.writeUTF("帅锅");
		//获取 a.txt 文件的字节长度
		int len = (int) srcRA.length();
		srcRA.seek(0);
		System.out.println(srcRA.readByte()+srcRA.readInt()+srcRA.readUTF());
		
		//开始复制
		srcRA.seek(0);
		//定义一个数组,用来存放 a.txt 文件的数据
		byte[] buffer = new byte[len];
		//将 a.txt 文件的内容读到 buffer 中
		srcRA.readFully(buffer);
		//再将 buffer 写入到 b.txt文件中
		descRA.write(buffer);
		
		//读取 b.txt 文件中的数据
		descRA.seek(0);
		System.out.println(descRA.readByte()+descRA.readInt()+descRA.readUTF());
		//关闭流资源
		srcRA.close();
		descRA.close();
	}

ps:一般多线程下载、断点下载都可以运用此随机流

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏耕耘实录

Linux三大剑客之awk

版权声明:本文为耕耘实录原创文章,各大自媒体平台同步更新。欢迎转载,转载请注明出处,谢谢

19640
来自专栏Android 研究

APK安装流程详解5——Installer、InstallerConnection和Installd守护进程

因为Installer继承自SystemService,所以我们看下Installer的onStart方法 代码在Installer.java 396行

18310
来自专栏恰童鞋骚年

Hadoop学习笔记—7.计数器与自定义计数器

  在上图所示中,计数器有19个,分为四个组:File Output Format Counters、FileSystemCounters、File Input...

12220
来自专栏Spark生态圈

[Spark SQL] 源码解析之Analyzer

Analyzer模块将Unresolved LogicalPlan结合元数据catalog进行绑定,最终转化为Resolved LogicalPlan。跟着代码...

14220
来自专栏菩提树下的杨过

rpc框架之 thrift 学习 2 - 基本概念

thrift的基本构架: ? 上图源自:http://jnb.ociweb.com/jnb/jnbJun2009.html 底层Underlying I/O以上...

27670
来自专栏Hongten

JSP 九大内置对象

① out - javax.servlet.jsp.jspWriter    out对象用于把结果输出到网页上。

55820
来自专栏JMCui

Netty 系列六(编解码器).

    网络传输的单位是字节,如何将应用程序的数据转换为字节,以及将字节转换为应用程序的数据,就要说到到我们该篇介绍的编码器和解码器。

12510
来自专栏SDNLAB

POF技术分享(三):Packet处理流程

前言: 之前对POF基本原理、POF交换机源码结构进行解读,但是,要想完成POF交换机的二次开发和拓展,有必要对POF交换机特有的数据包处理流程、POF交换机和...

396120
来自专栏ImportSource

Junit 5新特性全集

本文略长,但都是大白话,如果你能一口气看完,你赢了。 如果你来不及看这么长,那么建议你滑到文末,直接看黑体部分就知道大概了。 在5中的一个测试类的基本生命周期是...

515120
来自专栏祝威廉

ElasticSearch Aggregations GroupBy 实现源码分析

也就是按newtype 字段进行group by,然后对num求平均值。在我们实际的业务系统中,这种统计需求也是最多的。

53230

扫码关注云+社区

领取腾讯云代金券