任务要求:准确将一个文件从一个文件夹(resource)复制到另一个文件夹(target)下。
方式一
import java.io.*;
public class Demo1 {
public static void main(String[] args) {
File file = new File("resource/sea.mp3");
try {
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream("./target/seaCopy.mp3");
long startTime = System.currentTimeMillis();
int value = fileInputStream.read();
/*Copy过程*/
while(value != -1) {
fileOutputStream.write(value);
value = fileInputStream.read();
}
long endTime = System.currentTimeMillis();
System.out.println("用时" + (endTime - startTime) + "毫秒");
fileInputStream.close();
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
输出结果
用时48530毫秒
*/
歌曲是能听的,并且与源文件大小是一模一样的。但是copy时间较长,输出value,每次都是不一样的。
FileInputStream里的
/**
* Reads a byte of data from this input stream. This method blocks
* if no input is yet available.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* file is reached.
* @exception IOException if an I/O error occurs.
*/
public int read() throws IOException {
return read0();
}
因为它是逐字节一个个读。
文件3m,时间48s多。这样的速度肯定是我们不能接受的。
方式二
不要一次读一点了,一次性读一段信息。read第二个方法。buffer缓冲区。8k=8*1024,但是想想用位运算不是更好。1<<13。
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
import java.io.*;
public class Demo2 {
public static final int BUFFER_SIZE = 1 << 13;
public static void main(String[] args) {
File file = new File("resource/sea.mp3");
try {
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream("./target/seaCopy.mp3");
byte[] buffer = new byte[BUFFER_SIZE];
long startTime = System.currentTimeMillis();
int readLen = fileInputStream.read(buffer);
while (readLen != -1) {
fileOutputStream.write(buffer);
readLen = fileInputStream.read(buffer);
}
long endTime = System.currentTimeMillis();
System.out.println("用时" + (endTime - startTime) + "毫秒");
fileInputStream.close();
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*结果
用时35毫秒
*/
但是问题出来了,这个文件一定是8k的整数倍吗?不一定吧。所以读到最后就会出现问题了!就会造成不必要的数据冗余,在文件最后面。未被覆盖的倒数第二次数据会被再重复一遍。
用而这种方式写的一定是8k(缓冲区)的整数倍。目标文件不符合我们的最终要求,有多的数据,我们要准准确确的copy版。
方式三
用write三参方式
将buffer数组中的偏移量为第一个参数开始,向后的第二个参数的信息写。读多少写多少!
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this file output stream.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @exception IOException if an I/O error occurs.
*/
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, fdAccess.getAppend(fd));
}
import java.io.*;
public class Demo3 {
public static int BUFFER_SIZE = 1 << 13;
public static void main(String[] args) {
File file = new File("resource/sea.mp3");
try {
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream("./target/seaCopy.mp3");
byte[] buffer = new byte[BUFFER_SIZE];
int readLen = 0;
long startTime = System.currentTimeMillis();
readLen = fileInputStream.read(buffer);
while (readLen != -1) {
fileOutputStream.write(buffer, 0, readLen);
readLen = fileInputStream.read(buffer);
}
long endTime = System.currentTimeMillis();
System.out.println("用时" + (endTime - startTime) + "毫秒");
fileInputStream.close();
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*输出结果
用时12毫秒
*/
并且音乐的Copy版和原版大小一样。我们的要求得到了满足并且速度也快。
缓冲区越大越快,那么缓冲区最好设置多少呢?
IP数据包的最大长度是64KB(65535),对于帧(链路层)来说是1500字节(MTU)。
但是考虑ip数据报报文包含数据报头部信息,因此,实际数据量小于64kb。对于大于64k的数据报文会被路由器切割,切割也是耗时的,不如发小一点。