使用 java 进行文件拷贝 相信很多人都会用,,不过效率上是否最好呢?
最近看了看NIO决定试一试 java NIO 到底有什么性能的提升.
第一种方法:古老的方式
public
static
long
forJava(File f1,File f2)
throws
Exception{
long
time
=
new
Date().getTime();
int
length
=
2097152
;
FileInputStream in
=
new
FileInputStream(f1);
FileOutputStream out
=
new
FileOutputStream(f2);
byte
[] buffer
=
new
byte
[length];
while
(
true
){
int
ins
=
in.read(buffer);
if
(ins
==-
1
){
in.close();
out.flush();
out.close();
return
new
Date().getTime()
-
time;
}
else
out.write(buffer,
0
,ins);
}
}
方法的2参数分别是原始文件,和拷贝的目的文件.这里不做过多介绍.
实现方法很简单,分别对2个文件构建输入输出流,并且使用一个字节数组作为我们内存的缓存器, 然后使用流从f1 中读出数据到缓存里,在将缓存数据写到f2里面去.这里的缓存是2MB的字节数组
第2种方法:使用NIO中的管道到管道传输
public
static
long
forTransfer(File f1,File f2)
throws
Exception{
long
time
=
new
Date().getTime();
int
length
=
2097152
;
FileInputStream in
=
new
FileInputStream(f1);
FileOutputStream out
=
new
FileOutputStream(f2);
FileChannel inC
=
in.getChannel();
FileChannel outC
=
out.getChannel();
int
i
=
0
;
while
(
true
){
if
(inC.position()
==
inC.size()){
inC.close();
outC.close();
return
new
Date().getTime()
-
time;
}
if
((inC.size()
-
inC.position())
<
20971520
)
length
=
(
int
)(inC.size()
-
inC.position());
else
length
=
20971520
;
inC.transferTo(inC.position(),length,outC);
inC.position(inC.position()
+
length);
i
++
;
}
}
实现方法:在第一种实现方法基础上对输入输出流获得其管道,然后分批次的从f1的管道中像f2的管道中输入数据每次输入的数据最大为2MB
方法3:内存文件景象写(读文件没有使用文件景象,有兴趣的可以回去试试,,我就不试了,估计会更快)
public
static
long
forImage(File f1,File f2)
throws
Exception{
long
time
=
new
Date().getTime();
int
length
=
2097152
;
FileInputStream in
=
new
FileInputStream(f1);
RandomAccessFile out
=
new
RandomAccessFile(f2,
"
rw
"
);
FileChannel inC
=
in.getChannel();
MappedByteBuffer outC
=
null
;
MappedByteBuffer inbuffer
=
null
;
byte
[] b
=
new
byte
[length];
while
(
true
){
if
(inC.position()
==
inC.size()){
inC.close();
outC.force();
out.close();
return
new
Date().getTime()
-
time;
}
if
((inC.size()
-
inC.position())
<
length){
length
=
(
int
)(inC.size()
-
inC.position());
}
else
{
length
=
20971520
;
}
b
=
new
byte
[length];
inbuffer
=
inC.map(MapMode.READ_ONLY,inC.position(),length);
inbuffer.load();
inbuffer.get(b);
outC
=
out.getChannel().map(MapMode.READ_WRITE,inC.position(),length);
inC.position(b.length
+
inC.position());
outC.put(b);
outC.force();
}
}
实现方法:跟伤2个例子不一样,这里写文件流没有使用管道而是使用内存文件映射(假设文件f2在内存中).在循环中从f1的管道中读取数据到字节数组里,然后在像内存映射的f2文件中写数据.
第4种方法:管道对管道
public
static
long
forChannel(File f1,File f2)
throws
Exception{
long
time
=
new
Date().getTime();
int
length
=
2097152
;
FileInputStream in
=
new
FileInputStream(f1);
FileOutputStream out
=
new
FileOutputStream(f2);
FileChannel inC
=
in.getChannel();
FileChannel outC
=
out.getChannel();
ByteBuffer b
=
null
;
while
(
true
){
if
(inC.position()
==
inC.size()){
inC.close();
outC.close();
return
new
Date().getTime()
-
time;
}
if
((inC.size()
-
inC.position())
<
length){
length
=
(
int
)(inC.size()
-
inC.position());
}
else
length
=
2097152
;
b
=
ByteBuffer.allocateDirect(length);
inC.read(b);
b.flip();
outC.write(b);
outC.force(
false
);
}
}
这里实现方式与第3种实现方式很类似,不过没有使用内存影射.
下面是对49.3MB的文件进行拷贝的测试时间(毫秒)
Start Copy File... file size:50290KB
CopyFile:b1.rmvb mode:forChannel RunTime:3203
CopyFile:b1.rmvb mode:forImage RunTime:3328
CopyFile:b1.rmvb mode:forJava RunTime:2172
CopyFile:b1.rmvb mode:forTransfer RunTime:1406
End Copy File!
PS:这个一个上传方法 用的uploadify插件
public ReturnObject uploadFile(String deleteFileName,
HttpServletRequest request,HttpServletResponse response)
throws IOException{
System.out.println("附件上传sessionInfo:"
+ ContextUtils.getSession().getId());
String basePath = Global.BASE_UPLOAD_FOLDER; // 获取基础路径
String TemporaryFile=Global.BASE_UPLOAD_TEMPORARYFILE;//获取临时文件夹
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)request;
Map<String,MultipartFile> fileMap = multipartRequest.getFileMap();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
SimpleDateFormat sp = new SimpleDateFormat("yyyyMMdd");
// TODO multi-tenant.id 目前租户ID都是707 待以后完善后multi-tenant.id 就是租户ID
String ctxPath = basePath + File.separator + 707 + File.separator
+ ContextUtils.getCurrentSecurityUser().getUsername()
+ File.separator+TemporaryFile+File.separator;// 完整路径
String ctxPathView = sp.format(new Date()) + "/";// 用于在数据库存储的路径-从文件夹开始
String ymd = sdf.format(new Date());
// 如果不存在,创建文件夹
File file = new File(ctxPath);
if (!file.exists()){
file.mkdirs();
}
ReturnObject ro = new ReturnObject();
String fileNames = "";
for (Map.Entry<String,MultipartFile> entity : fileMap.entrySet()){
MultipartFile mf = entity.getValue();
String fileFullname = mf.getOriginalFilename();
// String fileName = mf.getOriginalFilename();
String fileName = ymd + "_" + fileFullname;
File uploadFile = new File(ctxPath + fileName);
try{
FileCopyUtils.copy(mf.getBytes(),uploadFile); //可以利用此方法进行文件移动,通过流直接移动
// copy成功之后保存上传数据记录
UploadFile uploadBean = new UploadFile();
uploadBean.setUpdUser(ContextUtils.getCurrentSecurityUser()
.getUsername());
uploadBean.setOriginName(fileFullname);
uploadBean.setFileName(fileName);
uploadBean.setUpdTime(new Date());
uploadBean.setIsFunction("other");
if (uploadBean != null){
uploadFileService.save(uploadBean);
}
fileNames += fileName + ",";
}
catch (IOException e){
e.printStackTrace();
ro.setSuccess(false);
ro.setMsg(e.getMessage());
return ro;
}
}
if (fileNames.endsWith(",")){
fileNames = fileNames.substring(0,fileNames.length() - 1);
}
ro.setSuccess(true);
ro.setMsg("上传文件成功");
HashMap<String,Object> hsfiled = new HashMap<String,Object>();
hsfiled.put("fileNames",fileNames);
hsfiled.put("filepatch",ctxPathView);// 数据库保存路径(从时间开始截取的)
ro.setObj(hsfiled);
// 清空不需要的历史文件
try{
log.info("删除不需要的文件:" + deleteFileName);
String ctPath = basePath + File.separator + File.separator
+ deleteFileName;
// 如果不存在,创建文件夹
if (deleteFileName != null){
File fileTobeDelete = new File(ctPath);
if (fileTobeDelete.exists()){
fileTobeDelete.delete();
}
}
}
catch (Exception e){
log.error("删除历史文件出错:" + e.getMessage());
}
return ro;
}