最近在准备面试,翻了翻自己以前写的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. 用 eclipse 创建一个简单的 meaven spring springMvc mybatis 项目

    下面是整体步骤: 1: 先创建一个Maven 项目: 选择跳过骨架: 因为要搭建的是 web 项目  所以这个地方选择 war 包; 点击完成 这样就完成 Maven项目的搭建: 接下俩 先把 Mav ...

  2. Azure 基础:使用 powershell 创建虚拟机

    在进行与 azure 相关的自动化过程中,创建虚拟主机是避不开的操作.由于系统本身的复杂性,很难用一两条简单的命令完成虚拟主机的创建.所以专门写一篇文章来记录使用 PowerShell 在 azure ...

  3. 转 node.js里面的http模块深入理解

    问题1:HTTP服务继承了TCP服务模型,是从connection为单位的服务到以request为单位的服务的封装,那么request事件何时触发? 注意:在开启keepalive后,一个TCP会话可 ...

  4. LeetCode 495. Teemo Attacking (提莫攻击)

    In LOL world, there is a hero called Teemo and his attacking can make his enemy Ashe be in poisoned ...

  5. LeetCode 461. Hamming Distance (汉明距离)

    The Hamming distance between two integers is the number of positions at which the corresponding bits ...

  6. Google Guava

    公司用到了 Joiner  HashMultimap 等  都是属于Google Guava包中的东西 官方文档 http://ifeve.com/google-guava/ 有时间了整理一下

  7. input框内的单引号,双引号转译

    主要是在后台传前端之前先把变量值替换单引号双引号成转译付. $bianlian是要替换的变量 两种方法 1.php后台输出值先转译 //双引号替换成转译符 $bianlian=preg_replace ...

  8. 如何在 Apple TV 上使用描述文件

    您可以使用 OS X 上的 Apple Configurator 在 Apple TV 上安装配置描述文件. 开始前,请在 Mac 上安装最新版本的 Apple Configurator(如果尚未安装 ...

  9. Python 抽象篇:面向对象之类的方法与属性

    概览:类成员之字段:-普通字段,保存在对象中,执行职能通过对象访问-静态字段,保存在类中,执行可以通过对象访问,也可以通过类访问类成员之方法:-普通方法,保存在类中,由对象来调用,self->对 ...

  10. SharePoint Server 2013 安装篇 - 如何解决无法找到 .net 4.5 的问题

    SharePoint Server 2013 在安装前,是不能安装 VS 等会自动安装 .net 4.5.x 以上版本的 .net Framework 的软件的.因为安装了 .net Framewor ...