文件字节流复制文件的原理是:读取一个个字节(或者字节数组),然后再写入文件中去。
缓冲字节流复制文件的原理是:读取一个个字节(或者字节数组)放到缓冲字节数组中,等到缓冲字节数组读满后,再把这几次读取到的字节一并写到文件中去。这样使用缓冲字节流,就能少写几次文件,进而节省时间。
测试代码:
(1)批量读取比较:
public class TestBuffered_File { public static void copyFileBufferd(File srcFile,File destFile,int bufsize) throws IOException { if(!srcFile.exists()) { throw new FileNotFoundException("文件"+srcFile+"不存在"); } if(!srcFile.isFile()) { throw new IllegalArgumentException(srcFile+"不是文件"); } //创建缓冲字节流对象,内部缓冲设置为bufSize BufferedInputStream in=new BufferedInputStream( new FileInputStream(srcFile),bufsize); BufferedOutputStream out=new BufferedOutputStream( new FileOutputStream(destFile),bufsize); int size=0; byte[] buffer=new byte[512]; //读到字节串到内部缓存,默认缓冲区的大小是8192字节 while((size=in.read(buffer))!=-1) { out.write(buffer,0,size);//把读取到的字节串写入到缓冲区,缓冲区写满会自动写入文件 // out.flush();//刷新缓冲区写入文件 } out.flush();//刷新缓冲区写入文件 in.close(); out.close(); } /** * 使用FileInputStream和FileOutputStream 按字节数组拷贝文件 * @param srcFile 源文件File对象 * @param targetFile 目标文件File对象 * @throws IOException */ public static void copyFileByBytes(File srcFile,File targetFile) throws IOException { if(!srcFile.exists()) { throw new IllegalArgumentException( srcFile+"文件不存在"); } if(!srcFile.isFile()) { throw new IllegalArgumentException( srcFile+"不是文件"); } FileInputStream in=new FileInputStream(srcFile); FileOutputStream out=new FileOutputStream(targetFile); byte[] buf=new byte[512]; int size=0; while((size=in.read(buf, 0, buf.length))!=-1) { out.write(buf, 0, size); out.flush();//刷新写入文件中去。 } in.close(); out.close(); } /** * 把时间戳(long 毫秒数)转换为格式化时间字符串 * @param timeStamp long毫秒数 * @return 格式化时间字符串 */ public static String timeStampToDateString(long timeStamp) { Date date = new Date(timeStamp); /* m 小时中的分钟数 s 分钟中的秒数 S 毫秒数 */ DateFormat format = new SimpleDateFormat("mm:ss:SS"); String dateString=format.format(date); return dateString; } public static void main(String[] args) { String packagePath; try { //使用缓冲字节流拷贝文件 long start=System.currentTimeMillis();//获取当前的时间戳 packagePath = FilePath.getSrcPackagePath(TestBufferedCopy.class); copyFileBufferd(new File(packagePath+"李玉刚_刚好遇见你.mp3"), new File(packagePath+"李玉刚_刚好遇见你副本4.mp3"),1024*10); long end=System.currentTimeMillis();//获取复制后的时间戳 System.out.println("使用缓冲字节流(每次读取字节数组512)拷贝文件用时(分钟:秒:毫秒):" +timeStampToDateString(end-start)); //使用文件字节流,按字节数组拷贝文件 start=System.currentTimeMillis(); copyFileByBytes(new File(packagePath+"李玉刚_刚好遇见你.mp3"), new File(packagePath+"李玉刚_刚好遇见你副本5.mp3")); end=System.currentTimeMillis(); System.out.println("使用文件字节流(每次读取字节数组512)拷贝文件用时(分钟:秒:毫秒):" +timeStampToDateString(end-start)); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
运行结果:
使用缓冲字节流(每次读取字节数组512)拷贝文件用时(分钟:秒:毫秒):00:00:34 使用文件字节流(每次读取字节数组512)拷贝文件用时(分钟:秒:毫秒):00:00:101
可见,每次读取相同的字节数组的条件下,缓冲字节流多了缓冲,进而减少写入文件的次数,从而比文件字节流用时少。
(2)逐个字节读取比较:
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import com.lan.filepath.FilePath; public class TestBuffered_FileByByte { public static void copyFileBufferdByByte(File srcFile, File destFile, int bufsize) throws IOException { if (!srcFile.exists()) { throw new FileNotFoundException("文件" + srcFile + "不存在"); } if (!srcFile.isFile()) { throw new IllegalArgumentException(srcFile + "不是文件"); } // 创建缓冲字节流对象,内部缓冲设置为bufSize BufferedInputStream in = new BufferedInputStream( new FileInputStream(srcFile), bufsize); BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(destFile), bufsize); int size = 0; // 读到字节串到内部缓存,默认缓冲区的大小是8192字节 while ((size = in.read()) != -1) { out.write(size);// 把读取到的字节写入到缓冲区,缓冲区写满会自动写入文件 } out.flush();// 刷新缓冲区写入文件 in.close(); out.close(); } /** * 使用FileInputStream和FileOutputStream 按字节数组拷贝文件 * * @param srcFile * 源文件File对象 * @param targetFile * 目标文件File对象 * @throws IOException */ public static void copyFileByByte(File srcFile, File targetFile) throws IOException { if (!srcFile.exists()) { throw new IllegalArgumentException(srcFile + "文件不存在"); } if (!srcFile.isFile()) { throw new IllegalArgumentException(srcFile + "不是文件"); } FileInputStream in = new FileInputStream(srcFile); FileOutputStream out = new FileOutputStream(targetFile); int size = 0; while ((size = in.read()) != -1) { out.write(size); } in.close(); out.close(); } /** * 把时间戳(long 毫秒数)转换为格式化时间字符串 * * @param timeStamp * long毫秒数 * @return 格式化时间字符串 */ public static String timeStampToDateString(long timeStamp) { Date date = new Date(timeStamp); /* * m 小时中的分钟数 s 分钟中的秒数 S 毫秒数 */ DateFormat format = new SimpleDateFormat("mm:ss:SS"); String dateString = format.format(date); return dateString; } public static void main(String[] args) { String packagePath; try { // 使用缓冲字节流拷贝文件 long start = System.currentTimeMillis();// 获取当前的时间戳 packagePath = FilePath.getSrcPackagePath(TestBufferedCopy.class); copyFileBufferdByByte(new File(packagePath + "李玉刚_刚好遇见你.mp3"), new File(packagePath + "李玉刚_刚好遇见你副本6.mp3"), 1024 * 10); long end = System.currentTimeMillis();// 获取复制后的时间戳 System.out.println("使用缓冲字节流(逐个字节)拷贝文件用时(分钟:秒:毫秒):" + timeStampToDateString(end - start)); // 使用文件字节流,按字节数组拷贝文件 start = System.currentTimeMillis(); copyFileByByte(new File(packagePath + "李玉刚_刚好遇见你.mp3"), new File(packagePath + "李玉刚_刚好遇见你副本7.mp3")); end = System.currentTimeMillis(); System.out.println("使用文件字节流(逐个字节)拷贝文件用时(分钟:秒:毫秒):" + timeStampToDateString(end - start)); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
运行结果:
使用缓冲字节流(逐个字节)拷贝文件用时(分钟:秒:毫秒):00:00:279 使用文件字节流(逐个字节)拷贝文件用时(分钟:秒:毫秒):00:35:982
可以看到逐个字节逐个字节的来拷贝文件,使用文件字节流要读一个字节写一个字节,耗时很大。虽然也是每次读取一个字节一个字节的读取,但是使用缓冲字节流读取满缓冲,才写一次文件,也就是读取1024 * 10次,才写一次文件。相比于使用文件字节流节省了1024 * 10-1次写文件的操作。这样就节省更多的时间。
总结:
(1) 如果使用文件字节流,复制文件,每次读取一个数组,写一个数组,比每次读取一个字节,写一个字节更快。
(2) 使用缓冲字节流比文件字节流更快(多分配内存(缓冲)):每次读取一个数组放到一个大的数组中去(缓冲),然后大的数组(缓冲)满了再一次性写入。