io学习三

RandomAccessFile##

RandomAccessFile类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为 文件指针 ;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。

*该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。
RandomAccessFile实现了数据输入输出流的接口;可以随机存储硬盘的文件,但是来自网络的文件就不行

RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream结合起来,再加上它自己的一些方法,比如定位用的getFilePointer( ),在文件里移动用的seek( ),以及判断文件大小的length( )、skipBytes()跳过多少字节数。此外,它的构造函数还要一个表示以只读方式("r"),还是以读写方式("rw")打开文件

package randomfile;

import java.io.RandomAccessFile;

public class Example {
	public static void main(String[] args) throws Exception {
		RandomAccessFile afile = new RandomAccessFile("randomfile", "rw");
		String[] type = new String[4];
		type[0] = "php";
		type[1] = "java";
		type[2] = "c++";
		type[3] = "测试中文adc";
		afile.writeUTF(type[0]);
		afile.writeUTF(type[1]);
		afile.writeUTF(type[2]);
		afile.writeUTF(type[3]);
		afile.seek(afile.length());
		afile.writeUTF("c");
		afile.seek(0);
		while(afile.getFilePointer()<afile.length()){
			System.out.println(afile.readUTF());
		}
	}
}

以上 代码实现的是文件后面追加
这里有个问题:使用writeUTF 会导致文字乱码(我已经指定编码是UTF-8) 在我电脑中显示的是:

解决方法是 尽量用 write(byte[]) 这个方法写 原理参考:
1、String.getBytes()将会按照当前系统默认的encoding方式获得字符串的 Bytes,RandomAccessFile.write(byte[])将这个byte数组正确写入。由于写入的实际就是Windows平台的 nativecode编码,所以文件还能够被正确的阅读。
2、RandomAccessFile.writeBytes(String)将字符串的各个字符(当然是用unicode编码的)的高8位去掉,写入文件。
3、RandomAccessFile.writeChars(String)将字符串的各个字符按照unicode的编码,以Big-endian的方式写入文件。Windows平台上默认文件的编码方式为Little-endian,所以用写字板打开看到的是乱码,但是如果我们用浏览器打开这个文件(testWriteChars.dat)并指定编码方式为Unicode Big-endian,就能看到正常的“中”字了。
4、RandomAccessFile.writeUTF(String)首先写入00 03表示其后将写入3个实际的字节,然后写入“中”的UTF-8编码:E4 B8 AD
通过上面的分析,我建议如果使用RandomAccessFile来写入中文的话,最好用 RandomAccessFile.write(String.getBytes())的方式,如果为了保险起见,还可以进一步指定运行平台的默认 nativecode编码方式,例如使用:RandomAccessFile.write(String.getBytes("gb2312"))
参考 http://www.osedu.net/article/linux/2011-06-30/250.html

RandomAccessFile 随意写测试:

package randomfile;

import java.io.RandomAccessFile;

public class Example {
	public static void main(String[] args) throws Exception {
		RandomAccessFile afile = new RandomAccessFile("randomfile", "rw");
		String[] type = new String[4];
		type[0] = "php";
		type[1] = "java";
		type[2] = "c++";
		type[3] = "测试中文adc";

		afile.write(type[0].getBytes());
		afile.write(type[1].getBytes());
		afile.write(type[2].getBytes());
		afile.write(type[3].getBytes());

		afile.seek(0);

		afile.write("c".getBytes());

		afile.seek(0);

		byte[] buffer = new byte[1024];
		int readCount = 0;

		while ((readCount=afile.read(buffer))!=-1) {
			System.out.print(new String(buffer,0,readCount));
		}
	}
}

这里可以看出RandomAccessFile 写的时候会覆盖以前的内容

RandomAccessFile 实现插入

package randomfile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;

public class Example2 {
	public static void main(String[] args) throws Exception {
		File temp = File.createTempFile("test", "temp");
		temp.deleteOnExit();
		FileInputStream fin = new FileInputStream(temp);
		FileOutputStream fout = new FileOutputStream(temp);
		RandomAccessFile rFile = new RandomAccessFile("randomfile", "rw");
		rFile.seek(0);
		byte[] buffer=new byte[1024];
		int readCount=0;
		while((readCount=rFile.read(buffer))!=-1){
			fout.write(buffer, 0, readCount);
		}
		rFile.seek(0);
		rFile.write("test插入".getBytes());
		
		while((readCount=fin.read(buffer))!=-1){
			rFile.write(buffer, 0, readCount);
		}
		
	}
}

这里使用了File的临时文件:
File 的 createTempFile() 方法
该方法有两种调用方式:
createTempFile(String prefix, String suffix);
在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。
createTempFile(String prefix, String suffix, File directory);
在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。
File file2 = new File("D: emp");// D;/temp 为一个目录
File tempFile1= file2.createTempFile("msg", ".tmp",file2);
File tempFile2 = file2.createTempFile("msg", ".tmp");
System.out.println(tempFile2.getAbsolutePath());
可以这么认为,createTempFile() 方法,在指定的目录下创建一个temp文件,directory 类型为File ,如果路径不存在,则创建失败。createTempFile(String prefix, String suffix);方法默认的保存路径为:C:Documents and SettingsAdministratorLocal SettingsTemp 。

可以看出其实插入操作 只要数据上了一定大小,是很耗费时间的和内存的(临时的文件的内存)
可以尝试使用RandomAccessFile实现多线程的续点下载
**RandomAccessFile的绝大多数功能,但不是全部,已经被JDK 1.4的nio的"内存映射文件(memory-mapped files)"给取代了,你该考虑一下是不是用"内存映射文件"来代替RandomAccessFile了。 **

原文地址:https://www.cnblogs.com/joeCqupt/p/6882648.html