最近在准备面试,翻了翻自己以前写的Demo,发现自己写了不少的工具包,今天整理了一下,分享给大家。我发现很多人不喜欢看文字,这次就只发Demo,不再啰嗦介绍RandomAccessFile,大家一边参照API,一边看我的Demo执行情况,试着自己写写。
这些是我的早期作品,有好的改进意见、建议或者有什么问题欢迎留言。
/** * 这个Demo是刚开始接触RandomAccessFile从网络上找到的,如今我也不记得出处 * * @author ?? 2016/11/7 * @version 1.0 */
import java.io.RandomAccessFile;
public class RandomAccessFileDemo {
public static void main(String[] args) throws Exception {
RandomAccessFile file = new RandomAccessFile("file", "rw");
// 占4个字节
file.writeInt(20);
// 占8个字节
file.writeDouble(8.236598);
// 这个长度写在当前文件指针的前两个字节处,可用readShort()读取
file.writeUTF("这是一个UTF字符串");
// 占1个字节
file.writeBoolean(true);
// 占2个字节
file.writeShort(395);
// 占8个字节
file.writeLong(2325451l);
file.writeUTF("又是一个UTF字符串");
// 占4个字节
file.writeFloat(35.5f);
// 占2个字节
file.writeChar('a');
// 把文件指针位置设置到文件起始处
file.seek(0);
// 以下从file文件中读数据,要注意文件指针的位置
System.out.println("——————从file文件指定位置读数据——————");
System.out.println(file.readInt());
System.out.println(file.readDouble());
System.out.println(file.readUTF());
// 将文件指针跳过3个字节,本例中即跳过了一个boolean值和short值。
file.skipBytes(3);
System.out.println(file.readLong());
// 跳过文件中“又是一个UTF字符串”所占字节,注意readShort()方法会移动文件指针,所以不用加2。
file.skipBytes(file.readShort());
System.out.println(file.readFloat());
// 以下演示文件复制操作
System.out.println("——————文件复制(从file到fileCopy)——————");
file.seek(0);
RandomAccessFile fileCopy = new RandomAccessFile("fileCopy", "rw");
// 取得文件长度(字节数)
int len = (int) file.length();
byte[] b = new byte[len];
file.readFully(b);
fileCopy.write(b);
System.out.println("复制完成!");
file.close();
fileCopy.close();
}
}
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
/** * 超大文件读写 * * @author ChenSS 2016/11/7 * @version 1.0 */
public class LargeMappedFiles {
static int length = 0x8000000; // 128 Mb
public static void main(String[] args) throws Exception {
// 为了以可读可写的方式打开文件,这里使用RandomAccessFile来创建文件。
// 注意,文件通道的可读可写要建立在文件流本身可读写的基础之上
RandomAccessFile accessFile = new RandomAccessFile("test.dat", "rw");
FileChannel fileChannel = accessFile.getChannel();
// 使用MappedByteBuffer写128M的内容
MappedByteBuffer out = fileChannel.map(FileChannel.MapMode.READ_WRITE,
0, length);
for (int i = 0; i < length; i++) {
out.put((byte) 'x');
}
// 另一种写入方式,128M结尾追加一句话,待会再想办法读出来
String newData = "这是最后一句话";
// 分配字节缓冲区
ByteBuffer buf = ByteBuffer.allocate(48);
// clear方法将缓冲区清空。
buf.clear();
// 放入字符串
buf.put(newData.getBytes());
// 回到当前缓存的头部
buf.flip();
// hasRemaining告知在当前位置和限制之间是否有元素。
while (buf.hasRemaining()) {
fileChannel.write(buf);
}
System.out.println("========================");
StringBuilder result = new StringBuilder();
// 定义字节缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// 定义解码后字符存储缓冲区
CharBuffer charBuffer = CharBuffer.allocate(1024);
// 定义合适的字符集解码器
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
// 设置此缓冲区的位置
fileChannel.position(length);
while ((fileChannel.read(byteBuffer)) != -1) { // 读取字符串到缓冲区
byteBuffer.flip();
charBuffer.clear();
// 对byteBuffer进行解码
if (fileChannel.position() < fileChannel.size()) {
decoder.decode(byteBuffer, charBuffer, false);
} else {
// 最后一次解码
decoder.decode(byteBuffer, charBuffer, true);
decoder.flush(charBuffer);
}
// 注意此处调用compact方法,而不是clear方法
byteBuffer.compact();
charBuffer.flip();
// 将charBuffer放入返回结果中
char[] chars = new char[charBuffer.remaining()];
charBuffer.get(chars, 0, charBuffer.remaining());
result.append(chars);
}
System.out.println(result);
// 读取文件中间6个字节内容
for (int i = length / 2; i < length / 2 + 6; i++) {
System.out.print((char) out.get(i));
}
fileChannel.close();
accessFile.close();
}
}
/** * 文件追加 * @author ChenSS 2016/11/7 * @version 1.0 */
public class FileAppend {
public static void main(String[] args) {
FileAppend.append(4, "zhuangjiangtao", "file.txt");
}
public static void append(long skip, String str, String fileName) {
try {
RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
byte[] b = str.getBytes();
long len = b.length;
long start = len + skip;
// 重新开辟空间
raf.setLength(raf.length() + len);
for (long i = raf.length() - 1; i >= start; i--) {
raf.seek(i - len);
byte temp = raf.readByte();
raf.seek(i);
raf.writeByte(temp);
}
raf.seek(skip);
raf.write(b);
raf.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
/** * 多线程复制文件 * @author ChenSS 2016/11/7 * @version 1.0 */
public class UsingThreadRandom {
public static void main(String[] args) throws Exception {
File file = new File("aaa.jpg");
startThread(4, file.length(), "aaa.jpg", "baabb.jpg");
}
/** * 开启多线程下载 * * @param threadnum 线程数 * @param fileLength 文件大小(用于确认每个线程下载多少东西) * @param sourseFilePath 源文件目录 * @param targerFilePath 目标文件目录 */
public static void startThread(int threadnum, long fileLength,
String sourseFilePath, String targerFilePath) {
System.out.println("================");
long modLength = fileLength % threadnum;
long targetLength = fileLength / threadnum;
for (int i = 0; i < threadnum; i++) {
System.out.println((targetLength * i) + "-----"
+ (targetLength * (i + 1)));
new FileWriteThread((targetLength * i), (targetLength * (i + 1)),
sourseFilePath, targerFilePath).start();
}
if (modLength != 0) {
new FileWriteThread((targetLength * 4), modLength, sourseFilePath,
targerFilePath).start();
}
}
/** * 写线程:指定文件开始位置、目标位置、源文件、目标文件, */
static class FileWriteThread extends Thread {
private long begin;
private long end;
private RandomAccessFile soursefile;
private RandomAccessFile targerFile;
public FileWriteThread(long begin, long end, String sourseFilePath,
String targerFilePath) {
this.begin = begin;
this.end = end;
try {
this.soursefile = new RandomAccessFile(sourseFilePath, "rw");
this.targerFile = new RandomAccessFile(targerFilePath, "rw");
} catch (FileNotFoundException e) {
}
}
public void run() {
try {
soursefile.seek(begin);
targerFile.seek(begin);
int hasRead = 0;
byte[] buffer = new byte[1024];
while (begin < end && -1 != (hasRead = soursefile.read(buffer))) {
begin += hasRead;
targerFile.write(buffer, 0, hasRead);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
soursefile.close();
targerFile.close();
} catch (Exception e) {
}
}
}
}
}
import java.io.File;
/** * * @author ChenSS 2016/11/7 * @version 1.0 */
public class Test {
private static final int NUMBER = 10;
// public static final String URL_DOWNLOAD =
// "http://www.swsm.net/data/attachment/forum/201506/19/171831uzzeejjxke1jkgme.jpg";
public static final String URL_DOWNLOAD = "https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png";
public static final String PATH_TARGET = "F:/temp/download/";
public static void main(String[] args) {
Loader loder = new Loader();
File file = loder.createFile(PATH_TARGET, URL_DOWNLOAD);
loder.startLoadThread(NUMBER, file, URL_DOWNLOAD);
}
}
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
/** * * @author ChenSS 2016/11/7 * @version 1.0 */
public class Loader {
/** * 创建目标文件(希望保存的文件和下载的同名) * * @param targetPath * 目标路径 * @param sourseURL * 根据源URL获取文件名 * @return */
public File createFile(String targetPath, String sourseURL) {
return new File(targetPath
+ sourseURL.substring(sourseURL.lastIndexOf("/") + 1));
}
/** * 如果出现不整除的情况(如:11字节,4个线程,每个线程3字节,多出1字节),但是实际上RandomAccessFile的read() * 读到文件尾会返回-1,因此不考虑余数问题 * * @param threadNum * 线程数量 * @param targetFile * 目标文件 * @param sourseURL * 源文件URL */
public void startLoadThread(int threadNum, File targetFile, String sourseURL) {
try {
// 网络连接
URLConnection connection = new URL(sourseURL).openConnection();
long sourseSize = connection.getContentLengthLong();
// 为目标文件分配空间
this.openSpace(targetFile, sourseSize);
// 分线程下载文件
long avgSize = sourseSize / threadNum + 1;
for (int i = 0; i < threadNum; i++) {
System.out
.println(avgSize * i + "------" + (avgSize * (i + 1)));
new Thread(new DownloadsTask(avgSize * i, avgSize * (i + 1),
targetFile, sourseURL)).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/** * 为目标文件分配空间 * * @param targetfile * 目标文件 * @param sourseSize * 源文件大小 */
private void openSpace(File targetfile, Long sourseSize) {
RandomAccessFile randomAccessFile = null;
try {
randomAccessFile = new RandomAccessFile(targetfile, "rw");
randomAccessFile.setLength(sourseSize);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (randomAccessFile != null)
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
/** * * @author ChenSS 2016/11/7 * @version 1.0 */
public class DownloadsTask implements Runnable {
private long start;
private long end;
private File file;
private String loadUrl;
/** * 构造函数 * * @param start * 开始位置 * @param end * 结束位置 * @param targetFile * 目标文件 * @param loadUrl * 下载网址 */
public DownloadsTask(long start, long end, File targetFile, String loadUrl) {
this.start = start;
this.end = end;
this.file = targetFile;
this.loadUrl = loadUrl;
}
@Override
public void run() {
BufferedInputStream bufferedInputStream = null;
RandomAccessFile randomAccessFile = null;
try {
URL url = new URL(loadUrl);
URLConnection conn = url.openConnection();
bufferedInputStream = new BufferedInputStream(conn.getInputStream());
randomAccessFile = new RandomAccessFile(file, "rw");
// 源文件和目标文件的指针指向同一个位置
bufferedInputStream.skip(start);
randomAccessFile.seek(start);
long readLen = end - start;
// 如果比默认长度小,就没必要按照默认长度读取文件了
byte[] bs = new byte[(int) (2048 < readLen ? 2048 : readLen)];
while (start < end
&& (readLen = bufferedInputStream.read(bs)) != -1) {
start += readLen;
randomAccessFile.write(bs, 0, (int) readLen);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭流
try {
if (null != bufferedInputStream)
bufferedInputStream.close();
if (null != randomAccessFile)
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}