对于文件的读写操作,有很多种不同的方法。下面我们进行一一介绍。
首先,我们先准备好一个3.5M左右大小的文件。如图所示:
方法一:逐字节读写
执行如下代码:
try {
long startTime = System.currentTimeMillis();
File file = new File("./bin/res/leftHand.mp3");
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream("./bin/tag/leftHand.mp3");
int value = 0;
while ((value = fis.read()) != -1) {
fos.write(value);
}
long endTime = System.currentTimeMillis();
System.out.println("耗时:" + (endTime - startTime));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
结果如下:
由此可见,对于文件的读写操作中,用逐字节方式读写(复制)一个3.5MB左右的文件,耗时:44404ms;文件非常完整,但是耗时太久,是非常不合理的。
方法二:多字节读写
对于多字节读写,一个问题就是每次该读多少字节是最合适的呢?由于考虑到我们以后要实现的网络文件的传输。其中的IP数据报报文的报头部分有一个表示报文长度的量,占2B,即,16bit;这就意味着,一个IP数据报文的最大长度应该是2^16B,即,64KB;但是,考虑到IP数据报报文包含数据报头部,因此,实际数据量应该小于64KB;因此,在考虑网络数据传输时,最好以32KB字节作为每一次传输的数据量。32KB也就是1 << 15B。
原因:对于大于64KB的数据报文,会被路由器自动切割成小于64KB的小报文片段。这是TCP协议自动完成的。
综上所述,我们定义一个常量BUFFER_SIZE,其值为:1 << 15,表示每次读取的字节数。
执行如下代码:
public static final int BUFFER_SIZE = 1 << 15;
public static void main(String[] args) {
try {
long startTime = System.currentTimeMillis();
File file = new File("./bin/res/leftHand.mp3");
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream("./bin/tag/leftHand.mp3");
byte[] buffer = new byte[BUFFER_SIZE];
int readLen = fis.read(buffer);
while (readLen != -1) {
fos.write(buffer);
readLen = fis.read(buffer);
}
long endTime = System.currentTimeMillis();
System.out.println("耗时:" + (endTime - startTime));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
执行结果如下:
由结果可见,上述的这种方法虽然耗时很短,但是,读取的文件会比源文件大,所以是不合适的。
方法三:分情况的多字节读写
直接执行如下代码:
try {
long startTime = System.currentTimeMillis();
File file = new File("./bin/res/leftHand.mp3");
long fileLenth = file.length();
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream("./bin/tag/leftHand.mp3");
byte[] buffer = new byte[BUFFER_SIZE];
int restLen = (int ) fileLenth;
int readLen = 0;
int len = 0;
while (restLen > 0 ) {
len = restLen > BUFFER_SIZE ? BUFFER_SIZE : restLen;
readLen = fis.read(buffer, 0, len);
fos.write(buffer, 0, readLen);
restLen -= readLen;
}
long endTime = System.currentTimeMillis();
System.out.println("耗时:" + (endTime - startTime));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
执行结果如下:
由此可见,这种方式虽然耗时没有第二种方式那么短,但是,相差不是很多,而且,解决了一个重大的问题:文件完整。所以,这种方式是最佳的。