科帮网

登录/注册
您现在的位置:论坛 盖世程序员(我猜到了开头 却没有猜到结局) 盖世程序员 > Java中如何使用内存映射处理大文件
总共48087条微博

动态微博

查看: 3400|回复: 4

Java中如何使用内存映射处理大文件

[复制链接]

57

主题

5

听众

129

金钱

三袋弟子

该用户从未签到

跳转到指定楼层
楼主
发表于 2014-05-10 10:39:23 |只看该作者 |倒序浏览
在处理大文件时,如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作,都将导致进程因频繁读写外存而降低速度.如下为一个对比实验。
+ S5 I/ C5 `5 U0 E5 Q( \4 l: ?& w' V  c' L
package test;  
! O( k, ]- K7 J3 |8 J6 a: P3 k$ _* d2 J
2 y% }2 F# [0 \* k3 E9 Yimport java.io.BufferedInputStream;    v( P+ k5 Q3 s+ e# F
import java.io.FileInputStream;  
, G( y! I9 `1 A3 T/ |+ fimport java.io.FileNotFoundException;  
1 e, c4 r$ e3 o6 k: Limport java.io.IOException;  
* V9 V( K# K. R& [) g1 A6 vimport java.io.RandomAccessFile;  
; Q* {( l! v4 T& x# |import java.nio.MappedByteBuffer;  * p# c  p; @( E; v) z: \/ S
import java.nio.channels.FileChannel;  $ K$ |5 [) h2 C  {5 w

, J, E/ H/ h- u: T% G  ]public class Test {  
5 f  }3 P3 d) ~5 k* L7 o1 ^% M! K2 s9 S$ i2 {
* y( M4 S) n; Y# L# I! G
    public static void main(String[] args) {  3 G# I4 L" V" h0 I% f
        try {  
( K0 [+ }& q  \" h6 D3 ]            FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");  
, ]7 [2 G) r" o2 V1 w' a( C            int sum=0;  0 [- D1 X: O# M( _% D, `# U, Q
            int n;  
9 b+ r6 |1 R  z" ?4 P9 o% t            long t1=System.currentTimeMillis();  
2 B- u: v5 x, G% {; ~4 w/ r6 j$ p& t( {            try {  
( ?6 J7 x# |6 M' n, ?% m                while((n=fis.read())>=0){  2 h8 ]$ I1 h! M9 [( i1 v2 H
                    sum+=n;  ! {0 w/ p2 J+ ]1 f6 J
                }  % h5 E; N2 y  w# r* E' w
            } catch (IOException e) {  7 T2 Q1 F# @3 @4 g" l
                // TODO Auto-generated catch block  
% \& a; F% `9 k: U, `4 y  K9 }3 N                e.printStackTrace();  * b; R( P! a9 x2 f+ J+ m
            }  7 G- w6 ~* h! ?+ s4 U
            long t=System.currentTimeMillis()-t1;  
) Q3 B- t+ G1 Q! l1 V            System.out.println("sum:"+sum+"  time:"+t);  ( E0 B8 x  H) k  z, O0 X5 ]% z  \
        } catch (FileNotFoundException e) {  
+ L% U' s; u$ O            // TODO Auto-generated catch block  - o9 l8 v9 S2 X. N- d. C1 A, e
            e.printStackTrace();  
$ Q# `5 y7 v- l& F( b0 X        }  1 o* r! p& Q" v' [2 a+ U
  U( b9 o  B3 J$ C( n
        try {  
! G1 [1 U" H) y% {. i9 n( ^7 e            FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");  8 y7 j8 i, Y; P$ n$ t  v
            BufferedInputStream bis=new BufferedInputStream(fis);  7 u2 A2 {, L9 x
            int sum=0;  
+ M6 {7 q; |' D% h- @6 e$ Z# N            int n;  + }# r8 y+ I* z
            long t1=System.currentTimeMillis();  
7 B" V. M, |- |8 a1 p& `            try {  / _0 \$ C( k  l
                while((n=bis.read())>=0){  
- B, V- R/ ]; B/ a6 p  c2 u9 m                    sum+=n;  & [& @+ c# X+ V& T' b* `9 W
                }  
5 M8 T4 W5 P; f            } catch (IOException e) {  
7 {2 C9 C: e. R* [+ Z9 s1 N4 v                // TODO Auto-generated catch block  
0 u9 ]  x0 o4 _4 C& B* J5 T% O+ \                e.printStackTrace();  4 i& d8 x$ V3 v3 s0 k$ z4 e& D  z5 e
            }  % ?3 a! l& G* @3 \% E( @) Q- Q
            long t=System.currentTimeMillis()-t1;  
. A3 m$ o2 g/ I5 j& M- q: r            System.out.println("sum:"+sum+"  time:"+t);  ( h# x* X, l+ j5 @+ J, A$ U, u
        } catch (FileNotFoundException e) {  
$ o3 S( U# ^* t1 F! f# J            // TODO Auto-generated catch block  
7 I7 p9 x0 h& o% g3 z* T            e.printStackTrace();  
# ~, E* f' ]: W$ v& v        }  ; b7 K' k) s9 t) R

* ~$ _, A( h4 h6 v7 |" O; W4 f        MappedByteBuffer buffer=null;  
; _5 G  L% n$ o; C        try {  
$ r/ ^5 K+ a8 H: \  ^) I; o4 j            buffer=new RandomAccessFile("/home/tobacco/test/res.txt","rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1253244);  
0 {, o8 M9 v: N8 f' r7 ~  S! Z            int sum=0;  3 w% `# Q* Q% a/ V: T; J/ v
            int n;  ( u. i0 @$ O$ L5 ]! s. T- n% q
            long t1=System.currentTimeMillis();  , k! C- |% e  K. L5 i
            for(int i=0;i<1253244;i++){  1 ^/ T& f/ R$ o* Z
                n=0x000000ff&buffer.get(i);  
% W, m: S1 P; i9 Y" E% \! r& R% u                sum+=n;  ' d$ |! {4 O8 r3 c
            }  : E' u  a" ^8 H! G! T3 a6 M& I
            long t=System.currentTimeMillis()-t1;  - C- k* Q: U. z7 R
            System.out.println("sum:"+sum+"  time:"+t);  - b5 r5 v) [% R2 ^7 C& S
        } catch (FileNotFoundException e) {  % N3 Z" @4 v8 N7 G
            // TODO Auto-generated catch block  
2 k/ @; R8 c/ d, A6 H( [1 ]9 M, d            e.printStackTrace();  
* N6 F' R+ ]2 ~4 Q& P( Q# G        } catch (IOException e) {  
/ R8 y* N8 p8 G            // TODO Auto-generated catch block  
6 T8 G4 e; ]- Z& e+ e/ n# z* O1 @            e.printStackTrace();  
5 o: M6 S" E- R6 ]2 e; ~* t9 f% Y1 P4 u3 s3 ?        }  - C% n; `' \# S/ V6 E

: Q2 X9 g4 U: A5 d( O! o, D3 h    }  + L6 S0 S% ~* D

5 _# {' O/ S2 H5 D}  
6 d' ~  f/ f2 ?: U' m9 h) N& ]测试文件为一个大小为1253244字节的文件。测试结果:
0 w  n# o5 q2 y
. a5 U' B2 x8 U, \, j  Vsum:220152087 time:1464  
0 C9 }& T! r7 ]' \. Jsum:220152087 time:72  
  C7 y  Y1 Z. k" x0 I6 [3 Usum:220152087 time:25
% W9 R% g. {) l说明读数据无误。删去其中的数据处理部分。/ F9 T6 X8 e" G% ?  K" K

' z+ `3 T' M# @package test;  
* Y0 ]' |9 u. D4 K+ P" W: g4 K- v) t1 Q( l1 z. E
import java.io.BufferedInputStream;  4 @. S" [6 [+ F, F
import java.io.FileInputStream;  2 [7 V! v3 F8 _$ c$ S
import java.io.FileNotFoundException;  5 ]; J; E% t0 L  c2 G" \# R
import java.io.IOException;  & P  @. Z5 f$ D/ @8 E
import java.io.RandomAccessFile;  " L$ R6 L2 `5 A
import java.nio.MappedByteBuffer;  ( e2 b) H) i& A( E  E
import java.nio.channels.FileChannel;  
4 c+ W3 [' V3 i; s: J# [+ C
& u) j, [! Y0 T5 M1 g: _public class Test {  5 t  n& \6 m& J" r% V
2 ]8 r+ B) M! s0 j5 D
% K1 V% u! B# v3 `% C
    public static void main(String[] args) {  0 b9 y  N  b0 g, s; M8 C1 x5 ^  t
        try {  0 ]7 z& a2 g8 Z) Y3 G/ n
            FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");  5 {' _8 D$ I# a
            int sum=0;  
' V3 {2 ~! p( J0 v' t' T. [  a            int n;  
+ a- c' y# v! ~2 R            long t1=System.currentTimeMillis();  
: t4 t$ K; w5 U8 V            try {  ) d+ q7 |, J( s8 ?
                while((n=fis.read())>=0){  + k9 x" L" N, D( Q
                    //sum+=n;  
; t! R2 ]2 E0 K. M4 a, _: i3 j" Y# H3 p                }  
  V7 t% S. ?# d( r/ t2 V            } catch (IOException e) {  ' e% W. W% M* G1 n/ x
                // TODO Auto-generated catch block  / E; E, O8 g: m. o# z
                e.printStackTrace();  # L0 W; j6 [  r" f0 L3 V
            }  
& Y5 H4 f0 c8 x& L/ d( H$ y            long t=System.currentTimeMillis()-t1;  
  k  d' Z7 n' \# Z/ D6 W8 J1 f            System.out.println("sum:"+sum+"  time:"+t);  
; |) b6 w" G3 g% M: V        } catch (FileNotFoundException e) {  - R8 {* J( y( N0 i! W5 G
            // TODO Auto-generated catch block  
% u( m$ E$ ]0 A* \/ W            e.printStackTrace();  
$ v5 X7 f4 l- `( z1 E0 y  r        }  
1 ]& k  z8 L( O5 x. l0 D$ _1 o8 {; v) ?5 L- e$ d* E$ q8 y/ Z" m: t
        try {  2 e! \$ z" @8 N0 t% [& \0 {" x) I
            FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");  1 u3 ]4 |. m6 Z  o3 r2 G
            BufferedInputStream bis=new BufferedInputStream(fis);  
- W" {6 f! D0 d: H7 C, p            int sum=0;  ' C- ?. \2 R; j5 l# Y8 I/ i) @
            int n;  , b2 Z1 @* I1 q: P7 P% s
            long t1=System.currentTimeMillis();  
6 D" T. s* l5 ~# z            try {  1 e9 S' m0 N  g! y
                while((n=bis.read())>=0){  
1 j) r6 {8 @& {. P5 b                    //sum+=n;  " Z, q4 F8 \+ P5 t+ x2 S
                }  
" i+ F' G) j2 g( Y            } catch (IOException e) {  & g4 l6 e3 C, U/ B- J
                // TODO Auto-generated catch block    h4 N; ]+ G& p9 C9 c. z" d
                e.printStackTrace();  3 g+ q+ y& k; n2 o6 P
            }  : X3 ~2 q& z, _, n% \4 u) q
            long t=System.currentTimeMillis()-t1;  
: V# l! W: z/ j4 F. X3 }4 U9 @# P            System.out.println("sum:"+sum+"  time:"+t);  
# ~$ R* T+ F; {. I  H        } catch (FileNotFoundException e) {  
: `5 O' \$ N% D# Q            // TODO Auto-generated catch block  % ]0 [7 y6 L5 B, s8 H( t
            e.printStackTrace();  8 t, h2 ^6 e7 Z; ?
        }  ' W/ T" `; Y- j2 j

. a, s& B) s* y( ]2 r  y8 s/ A        MappedByteBuffer buffer=null;  
- {5 v& o" Y; _5 L: \' E! g$ j        try {  
- L  T. B/ U1 f; u, |            buffer=new RandomAccessFile("/home/tobacco/test/res.txt","rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1253244);  ; x# N/ d$ ^1 F& S
            int sum=0;  5 y6 B' e: C7 J% a0 Q4 F
            int n;  
3 T0 F* Y5 l- s8 _            long t1=System.currentTimeMillis();  * V3 X* j$ D" c9 G+ R, l, T. g* u
            for(int i=0;i<1253244;i++){  ) F' X3 d/ P- n6 ?$ D2 r' S
                //n=0x000000ff&buffer.get(i);  
. Z- Z6 @- J# T$ R                //sum+=n;  
2 d. j# ]+ d3 i' R; U% d            }  4 \& S. ~: s: y5 t" q
            long t=System.currentTimeMillis()-t1;  ! X6 w" x# V5 N! H4 d: _# R
            System.out.println("sum:"+sum+"  time:"+t);  
: E2 U# ~: G" Y        } catch (FileNotFoundException e) {  ' }5 V' l2 r1 @* H: y
            // TODO Auto-generated catch block  7 |, h4 x  u/ k. ^$ \
            e.printStackTrace();  
$ t0 e& f5 z& s3 c% D        } catch (IOException e) {  6 Y! \0 r- [* q/ ~7 J+ Z* h- ~8 h8 x; {
            // TODO Auto-generated catch block  : t4 O2 `! e) O/ h
            e.printStackTrace();  
8 Z0 @9 r0 w1 o" A1 Z) b7 A        }  
# h% i6 g. \' \+ q. j, i  q0 ~0 x8 ]6 T8 M; }+ B6 t: A7 N
    }  
& _" h+ J$ R6 d+ P( }- B
5 n; U+ {1 S. |}
) k! I( F6 O( H: X5 w# B测试结果:
5 M+ J6 ?8 |* ]/ _4 R5 ?2 I! P0 @6 E
sum:0 time:1458  
) A( B8 m6 E6 q$ K& Esum:0 time:67  
4 Q' r) g6 e  B/ |: Q. j0 Rsum:0 time:8
: f4 G) M/ c$ I: g9 q由此可见,将文件部分或者全部映射到内存后进行读写,速度将提高很多。# C' W& q3 @5 c0 l
/ h) s% x, N" k0 L+ I( V
这是因为内存映射文件首先将外存上的文件映射到内存中的一块连续区域,被当成一个字节数组进行处理,读写操作直接对内存进行操作,而后再将内存区域重新映射到外存文件,这就节省了中间频繁的对外存进行读写的时间,大大降低了读写时间。
% W" R0 `# ]) ~! d# v
- p3 C# Q2 K1 @2 n* U

科帮网 1、本主题所有言论和图片纯属会员个人意见,与本社区立场无关
2、本站所有主题由该帖子作者发表,该帖子作者与科帮网享有帖子相关版权
3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和科帮网的同意
4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
7、科帮网管理员和版主有权不事先通知发贴者而删除本文


JAVA爱好者①群:JAVA爱好者① JAVA爱好者②群:JAVA爱好者② JAVA爱好者③ : JAVA爱好者③

1

主题

3

听众

341

金钱

四袋长老

该用户从未签到

沙发
发表于 2016-03-17 21:52:47 |只看该作者

% A5 P) [& x9 {. d6 Y) G下来,学习一下。谢谢
回复

使用道具 举报

woniu 实名认证   

2

主题

0

听众

330

金钱

四袋长老

该用户从未签到

板凳
发表于 2016-04-12 12:18:35 |只看该作者
这个项目太棒勒!下下来学习下!
回复

使用道具 举报

5

主题

0

听众

316

金钱

四袋长老

该用户从未签到

地板
发表于 2017-08-12 20:43:43 |只看该作者
不错不错不错不错
回复

使用道具 举报

5

主题

0

听众

316

金钱

四袋长老

该用户从未签到

5#
发表于 2017-08-14 08:32:04 |只看该作者
不错不错不错
回复

使用道具 举报

快速回复
您需要登录后才可以回帖 登录 | 立即注册

   

关闭

站长推荐上一条 /1 下一条

发布主题 快速回复 返回列表 联系我们 官方QQ群 科帮网手机客户端
快速回复 返回顶部 返回列表