最近在准备面试,翻了翻自己以前写的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. [转]pycharm快捷键

    开始学习python用的ide是pycharm,之前做java一种用eclipse,刚开始使用pycharm快捷键与eclipse有很大不同,慢慢适应中. 下面列举了下pycharm的快捷键,内容转自 ...

  2. 假如时光倒流,我会这么学习Java

    回头看看, 我进入Java 领域已经快15个年头了, 虽然学的也一般, 但是分享下我的心得,估计也能帮大家少走点弯路. [入门] 我在2001年之前是C/C++阵营, 有C和面向对象的基础, 后来转到 ...

  3. Single Number2

    题目链接:http://oj.leetcode.com/problems/single-number-ii/ Given an array of integers, every element app ...

  4. Git相关操作三

    1.显示当前分支: git branch 输入上述命令可以显示出分支,*所在的分支为当前分支. 2.新建分支: git branch new_branch new_branch为新建分支的名称,注意该 ...

  5. java:利用静态字段和构造函数实现已建对象数查询

    问题:使用类的静态字段和构造函数,我们可以跟踪某个类所创建对象的个数. 请写一个类,在任何时候都可以向它查询"你已经创建了多少个对象?". 程序设计思想: 利用静态变量指定一个计数 ...

  6. MySQL复制之实践篇

    本文主要以"一个主库,两个备库"代表"一个主库,多个备库"的拓扑结构来展示MySQL复制的实践过程. 拓扑结构: 主库创建复制账号: grant replica ...

  7. 我只是想获取access_token而已

    起因是想在微信小程序中获取access_token. 之前资源只有一个阿里云虚拟主机和一个域名,于是用C#后端写了GET请求的接口,准备调用自己域名下的接口获取access_token 使用微信的wx ...

  8. POJ3264 (RMQのST解法)

    For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One d ...

  9. NTP时间服务器 搭建

    1.1 NTP简介 NTP(Network Time Protocol,网络时间协议)是用来使网络中的各个计算机时间同步的一种协议.它的用途是把计算机的时钟同步到世界协调时UTC,其精度在局域网内可达 ...

  10. python抓去网页一部分

    import sys, urllib2 headers = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9. ...