最近在准备面试,翻了翻自己以前写的Demo,发现自己写了不少的工具包,今天整理了一下,分享给大家。

本文包含以下Demo:
1、常用方法测试
2、在文件中间插入一段新的数据
3、多线程下载文件
4、多线程复制文件
5、超大文件的读写

具体注意事项我会全部写在注释中,我就不再啰嗦介绍RandomAccessFile怎么去用,它跟普通文件读写类似,不过就是多了一个游标,可以从文件指定位置开始读取,大家可以一边参照API,一边看我的Demo执行情况,试着自己写写。
大家有好的改进意见、建议或者有什么问题欢迎留言。

RandomAccessFile常用方法

/**
* 这个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();
}
}
}
}

实现Runnable,线程下载逻辑

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();
}
}
}
}

RandomAccessFile多线程下载、复制文件、超大文件读写的更多相关文章

  1. java读取大文件 超大文件的几种方法

    java 读取一个巨大的文本文件既能保证内存不溢出又能保证性能       import java.io.BufferedReader; import java.io.File; import jav ...

  2. 框架基础:ajax设计方案(三)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组

    马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...

  3. 前端通信:ajax设计方案(四)--- 集成ajax上传技术 大文件/超大文件前端切割上传,后端进行重组

    马上要过年了,哎,回家的心情也特别的激烈.有钱没钱,回家过年,家永远是舔舐伤口最好的地方.新的一年继续加油努力. 上次做了前端的ajax的上传文件技术,支持单文件,多文件上传,并对文件的格式和大小进行 ...

  4. RandomAccessFile多线程下载

    public class DownloadServer { ; private static String fileUrl = "https://dldir1.qq.com/qqtv/mac ...

  5. Java--使用多线程下载,断点续传技术原理(RandomAccessFile)

    一.基础知识 1.什么是线程?什么是进程?它们之间的关系? 可以参考之前的一篇文章:java核心知识点学习----并发和并行的区别,进程和线程的区别,如何创建线程和线程的四种状态,什么是线程计时器 简 ...

  6. 图解:HTTP 范围请求,助力断点续传、多线程下载的核心原理

    题图:by Charles Loyer 一.序 Hi,大家好,我是承香墨影! HTTP 协议在网络知识中占据了重要的地位,HTTP 协议最基础的就是请求和响应的报文,而报文又是由报文头(Header) ...

  7. AccessRandomFile多线程下载文件

    写一个工具类 package com.pb.thread.demo; import java.io.File; import java.io.FileNotFoundException; import ...

  8. java 网络编程基础 InetAddress类;URLDecoder和URLEncoder;URL和URLConnection;多线程下载文件示例

    什么是IPV4,什么是IPV6: IPv4使用32个二进制位在网络上创建单个唯一地址.IPv4地址由四个数字表示,用点分隔.每个数字都是十进制(以10为基底)表示的八位二进制(以2为基底)数字,例如: ...

  9. JAVA多线程下载网络文件

    JAVA多线程下载网络文件,开启多个线程,同时下载网络文件.   源码如下:(点击下载 MultiThreadDownload.java) import java.io.InputStream; im ...

随机推荐

  1. win10 3dmax 激活后反复激活和激活码无效问题

    我也是遇到这个问题在网上找答案,像什么断网,清理注册表,删除某个.dat文件 各种试了好多都没管用 弄这个弄了五六个小时才总算成功 心累 现在我总结一下这些方法  我是第一条成功的 其他的我试着都没用 ...

  2. win10 uwp 自定义控件初始化

    我遇到一个问题,我在 xaml 用了我的自定义控件,但是我给他设置了一个值,但是什么时候我才可以获得这个值? 本文告诉大家,从构造函数.loaded.Initialized 的调用过程. 用最简单的方 ...

  3. WPF 设置输入只能英文

    有时输入只能让用户输入英文,那么如何设置输入只能英文? 首先在xaml 写一个 TextBox ,给他一个名字. <TextBox x:Name="txt"></ ...

  4. swiper使用小结

    最近做一个移动端项目想用Swiper移动端插件,需求实现一个轮播图的效果,并且需要自定义分页器,效果跟这个差不多这里demo 好吧,开始动手! 注意参考的3.0Swiper的API文档需要引入3.0版 ...

  5. multiprocessing模块

    multiprocessing模块 由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程. multiproce ...

  6. sql里的null和空的区别

    null表示为未知,未定义: 空表示为空白,或者0: sql查询,排序时null在''的前面: 定义字段为not null,写为空可以写入: null不可以用来比较,只能用is null判断:

  7. PHP设计模式一:工厂方法设计模式

    一.什么是工厂方法模式 作为一种创建型设计模式,工厂方法模式就是要创建“某种东西”.对于工厂方法,要创建的“东西”是一个产品,这个产品与创建它的类之间不存在绑定. 实际上,为了保持这种松耦合,客户会通 ...

  8. PHP异常处理机制

    1. 异常: 异常(Exception)用于在指定的错误发生时改变脚本的正常流程. 当异常被触发时,通常会发生: (1)当前代码状态被保存: (2)代码执行被切换到预定义的异常处理器函数: (3)根据 ...

  9. Fastify 系列教程三 (验证、序列化和生命周期)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) 验证 Fast ...

  10. C++ 对象成员函数(非静态方法)

    1.神奇的inline语法与语义 inline语义C99和C++98都有.之前在单源文件编写的时候一直没有发现问题,但是一考虑到多文件的链接,就发现矛盾了. 一些inline的原则: 1. inlin ...