file copy 4 methods

本文对比了四种Java文件拷贝方法:传统流复制、NIO管道传输、内存映射文件写入及NIO缓冲区直接操作。通过实验发现,NIO管道传输效率最高。
使用 java 进行文件拷贝 相信很多人都会用,,不过效率上是否最好呢?
最近看了看NIO决定试一试 java NIO 到底有什么性能的提升.

[b]第一种方法:古老的方式[/b]

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的字节数组

[b]第2种方法:使用NIO中的管道到管道传输[/b]

 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

[b]方法3:内存文件景象写(读文件没有使用文件景象,有兴趣的可以回去试试,,我就不试了,估计会更快)[/b]

  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文件中写数据.

[b]第4种方法:管道对管道[/b]

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的文件进行拷贝的测试时间(毫秒)
[quote]
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![/quote]

解释: 在测试结果中看到 古老方式,和管道向管道传输是最快的,,,,,为什么呢?

我分析是这样的,由于另外2种方法内部都使用了 字节数组作为缓存中转,在加上NIO内部有一个贴近系统的缓存区,这无意就增加了另一个缓存器,所以相对于这2个方法就要慢许多,,如果不使用 字节数组作为数据中转的话相信速度会更快的
Java 中调用 HTTP 请求上传文件可以通过 `HttpURLConnection` 或第三方库(如 Apache HttpClient、OkHttp)实现。以下是两种常见方法的示例代码: --- ### **方法 1:使用 `HttpURLConnection`(原生 Java)** ```java import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.file.Files; public class FileUploader { public static void main(String[] args) { String targetUrl = "https://example.com/upload"; String filePath = "path/to/your/file.txt"; String boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"; // 随机分隔符 try { // 1. 创建连接 URL url = new URL(targetUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); // 2. 构造请求体 try (OutputStream output = connection.getOutputStream(); PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"), true)) { // 添加文件部分 File file = new File(filePath); writer.append("--" + boundary).append("\r\n"); writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"").append("\r\n"); writer.append("Content-Type: " + Files.probeContentType(file.toPath())).append("\r\n"); writer.append("\r\n").flush(); Files.copy(file.toPath(), output); output.flush(); writer.append("\r\n").flush(); // 结束标记 writer.append("--" + boundary + "--").append("\r\n").flush(); } // 3. 读取响应 int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { String line; StringBuilder response = new StringBuilder(); while ((line = in.readLine()) != null) { response.append(line); } System.out.println("上传成功!响应:" + response.toString()); } } else { System.out.println("上传失败,状态码:" + responseCode); } } catch (Exception e) { e.printStackTrace(); } } } ``` --- ### **方法 2:使用 Apache HttpClient(推荐)** 添加 Maven 依赖: ```xml <dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.2.1</version> </dependency> ``` 代码示例: ```java import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.entity.mime.FileBody; import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.io.entity.EntityUtils; import java.io.File; import java.io.IOException; public class HttpClientFileUpload { public static void main(String[] args) { String targetUrl = "https://example.com/upload"; File file = new File("path/to/your/file.txt"); try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpPost httpPost = new HttpPost(targetUrl); // 构建多部分请求体 MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.addPart("file", new FileBody(file, ContentType.DEFAULT_BINARY, file.getName())); httpPost.setEntity(builder.build()); // 执行请求 try (CloseableHttpResponse response = httpClient.execute(httpPost)) { System.out.println("响应状态:" + response.getCode()); System.out.println("响应内容:" + EntityUtils.toString(response.getEntity())); } } catch (IOException e) { e.printStackTrace(); } } } ``` --- ### **关键点说明** 1. **`multipart/form-data`**:文件上传必须使用此格式,通过分隔符(boundary)区分字段。 2. **原生 `HttpURLConnection`**:代码较复杂,适合轻量级需求。 3. **Apache HttpClient**:更简洁高效,支持流式上传和大文件处理。 4. **错误处理**:检查响应状态码(如 200 表示成功),并处理异常。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值