在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

Java使用内存映射实现大文件的上传

2016-12-20 13:13| 发布者: zhangjf| 查看: 473| 评论: 0

摘要: 在处理大文件时,如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作,都将导致进程因频繁读写外存而降低速度.如下为一个对比实验。package test; import java.io.Buf ...

在处理大文件时,如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作,都将导致进程因频繁读写外存而降低速度.如下为一个对比实验。

  1. package test;
  2. import java.io.BufferedInputStream;
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.IOException;
  6. import java.io.RandomAccessFile;
  7. import java.nio.MappedByteBuffer;
  8. import java.nio.channels.FileChannel;
  9. public class Test {
  10. public static void main(String[] args) {
  11. try {
  12. FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");
  13. int sum=0;
  14. int n;
  15. long t1=System.currentTimeMillis();
  16. try {
  17. while((n=fis.read())>=0){
  18. sum+=n;
  19. }
  20. } catch (IOException e) {
  21. // TODO Auto-generated catch block
  22. e.printStackTrace();
  23. }
  24. long t=System.currentTimeMillis()-t1;
  25. System.out.println("sum:"+sum+" time:"+t);
  26. } catch (FileNotFoundException e) {
  27. // TODO Auto-generated catch block
  28. e.printStackTrace();
  29. }
  30. try {
  31. FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");
  32. BufferedInputStream bis=new BufferedInputStream(fis);
  33. int sum=0;
  34. int n;
  35. long t1=System.currentTimeMillis();
  36. try {
  37. while((n=bis.read())>=0){
  38. sum+=n;
  39. }
  40. } catch (IOException e) {
  41. // TODO Auto-generated catch block
  42. e.printStackTrace();
  43. }
  44. long t=System.currentTimeMillis()-t1;
  45. System.out.println("sum:"+sum+" time:"+t);
  46. } catch (FileNotFoundException e) {
  47. // TODO Auto-generated catch block
  48. e.printStackTrace();
  49. }
  50. MappedByteBuffer buffer=null;
  51. try {
  52. buffer=new RandomAccessFile("/home/tobacco/test/res.txt","rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1253244);
  53. int sum=0;
  54. int n;
  55. long t1=System.currentTimeMillis();
  56. for(int i=0;i<1253244;i++){
  57. n=0x000000ff&buffer.get(i);
  58. sum+=n;
  59. }
  60. long t=System.currentTimeMillis()-t1;
  61. System.out.println("sum:"+sum+" time:"+t);
  62. } catch (FileNotFoundException e) {
  63. // TODO Auto-generated catch block
  64. e.printStackTrace();
  65. } catch (IOException e) {
  66. // TODO Auto-generated catch block
  67. e.printStackTrace();
  68. }
  69. }
  70. }
复制代码

测试文件为一个大小为1253244字节的文件。测试结果:

  1. sum:220152087 time:1464
  2. sum:220152087 time:72
  3. sum:220152087 time:25
复制代码

说明读数据无误。删去其中的数据处理部分。

  1. package test;
  2. import java.io.BufferedInputStream;
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.IOException;
  6. import java.io.RandomAccessFile;
  7. import java.nio.MappedByteBuffer;
  8. import java.nio.channels.FileChannel;
  9. public class Test {
  10. public static void main(String[] args) {
  11. try {
  12. FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");
  13. int sum=0;
  14. int n;
  15. long t1=System.currentTimeMillis();
  16. try {
  17. while((n=fis.read())>=0){
  18. //sum+=n;
  19. }
  20. } catch (IOException e) {
  21. // TODO Auto-generated catch block
  22. e.printStackTrace();
  23. }
  24. long t=System.currentTimeMillis()-t1;
  25. System.out.println("sum:"+sum+" time:"+t);
  26. } catch (FileNotFoundException e) {
  27. // TODO Auto-generated catch block
  28. e.printStackTrace();
  29. }
  30. try {
  31. FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");
  32. BufferedInputStream bis=new BufferedInputStream(fis);
  33. int sum=0;
  34. int n;
  35. long t1=System.currentTimeMillis();
  36. try {
  37. while((n=bis.read())>=0){
  38. //sum+=n;
  39. }
  40. } catch (IOException e) {
  41. // TODO Auto-generated catch block
  42. e.printStackTrace();
  43. }
  44. long t=System.currentTimeMillis()-t1;
  45. System.out.println("sum:"+sum+" time:"+t);
  46. } catch (FileNotFoundException e) {
  47. // TODO Auto-generated catch block
  48. e.printStackTrace();
  49. }
  50. MappedByteBuffer buffer=null;
  51. try {
  52. buffer=new RandomAccessFile("/home/tobacco/test/res.txt","rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1253244);
  53. int sum=0;
  54. int n;
  55. long t1=System.currentTimeMillis();
  56. for(int i=0;i<1253244;i++){
  57. //n=0x000000ff&buffer.get(i);
  58. //sum+=n;
  59. }
  60. long t=System.currentTimeMillis()-t1;
  61. System.out.println("sum:"+sum+" time:"+t);
  62. } catch (FileNotFoundException e) {
  63. // TODO Auto-generated catch block
  64. e.printStackTrace();
  65. } catch (IOException e) {
  66. // TODO Auto-generated catch block
  67. e.printStackTrace();
  68. }
  69. }
  70. }
复制代码

测试结果:

  1. sum:0 time:1458
  2. sum:0 time:67
  3. sum:0 time:8
复制代码

由此可见,将文件部分或者全部映射到内存后进行读写,速度将提高很多。

这是因为内存映射文件首先将外存上的文件映射到内存中的一块连续区域,被当成一个字节数组进行处理,读写操作直接对内存进行操作,而后再将内存区域重新映射到外存文件,这就节省了中间频繁的对外存进行读写的时间,大大降低了读写时间。

来源:tobacco的专栏

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-8 02:38

Copyright 2015-2025 djqfx

返回顶部