KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > schlichtherle > io > rof > MemoryMappedReadOnlyFile


1 /*
2  * MemoryMappedReadOnlyFile.java
3  *
4  * Created on 17. Dezember 2005, 18:36
5  */

6 /*
7  * Copyright 2005 Schlichtherle IT Services
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */

21
22 package de.schlichtherle.io.rof;
23
24 import java.io.EOFException JavaDoc;
25 import java.io.File JavaDoc;
26 import java.io.FileNotFoundException JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.RandomAccessFile JavaDoc;
29 import java.nio.BufferUnderflowException JavaDoc;
30 import java.nio.ByteBuffer JavaDoc;
31 import java.nio.MappedByteBuffer JavaDoc;
32 import java.nio.channels.FileChannel JavaDoc;
33
34 /**
35  * A {@link ReadOnlyFile} using channels to map the underlying file into
36  * memory.
37  *
38  * @deprecated This code does not reliably work on the Windows platform,
39  * and hence its not used in TrueZIP.
40  * The reason is that the mapped file remains allocated until the
41  * garbage collector frees it even if the file channel and/or the
42  * RandomAccessFile has been closed. Subsequent delete/write
43  * operations on the file will then fail. For more information,
44  * please refer to
45  * <a HREF="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154">
46  * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154</a>.
47  *
48  * @author Christian Schlichtherle
49  */

50 public class MemoryMappedReadOnlyFile implements ReadOnlyFile {
51
52     private FileChannel JavaDoc channel;
53
54     private ByteBuffer JavaDoc window;
55
56     public MemoryMappedReadOnlyFile(File JavaDoc file) throws FileNotFoundException JavaDoc {
57         channel = new RandomAccessFile JavaDoc(file, "r").getChannel();
58         try {
59             positionWindow(0);
60         } catch (IOException JavaDoc failure) {
61             FileNotFoundException JavaDoc fnfe = new FileNotFoundException JavaDoc(failure.toString());
62             fnfe.initCause(failure);
63             throw fnfe;
64         }
65     }
66
67     private void positionWindow(long pos) throws IOException JavaDoc {
68         assert pos % Integer.MAX_VALUE == 0;
69
70         long chSize = channel.size();
71         if (pos > chSize) // must not be >=, otherwise window == null if chSize == 0!
72
return; // ignore moving past EOF
73

74         MappedByteBuffer JavaDoc mbb = channel.map(FileChannel.MapMode.READ_ONLY, pos,
75                 Math.min(chSize - pos, Integer.MAX_VALUE));
76         window = mbb;//.load(); // TODO: Check: What does this actually do? Load the *entire* window?
77
}
78
79     private final void advanceWindow() throws IOException JavaDoc {
80         positionWindow(channel.position() + Integer.MAX_VALUE);
81     }
82
83     public long length() throws IOException JavaDoc {
84         ensureOpen();
85
86         return channel.size();
87     }
88
89     public long getFilePointer() throws IOException JavaDoc {
90         ensureOpen();
91
92         return channel.position() + window.position();
93     }
94
95     public void seek(final long pos) throws IOException JavaDoc {
96         if (pos < 0)
97             throw new IOException JavaDoc("File pointer must not be negative!");
98
99         ensureOpen();
100
101         if (pos > channel.size())
102             throw new IOException JavaDoc("File pointer (" + pos
103                     + ") is larger than file length (" + channel.size() + ")!");
104
105         final long chPos = channel.position();
106         if (pos < chPos || chPos + Integer.MAX_VALUE <= pos)
107             positionWindow(pos / Integer.MAX_VALUE * Integer.MAX_VALUE); // round down
108

109         window.position((int) (pos % Integer.MAX_VALUE));
110     }
111
112     public int read() throws IOException JavaDoc {
113         if (window.remaining() <= 0) {
114             advanceWindow();
115             if (window.remaining() <= 0)
116                 return -1; // EOF
117
}
118         return window.get() & 0xFF;
119     }
120
121     public final int read(byte b[]) throws IOException JavaDoc {
122         return read(b, 0, b.length);
123     }
124
125     public int read(final byte[] buf, final int off, final int len)
126     throws IOException JavaDoc {
127         // Check parameters.
128
if (buf == null)
129             throw new NullPointerException JavaDoc("buf");
130         if (off < 0 || len < 0 || off + len > buf.length)
131             throw new IndexOutOfBoundsException JavaDoc();
132         if (len == 0)
133             return 0; // be fault-tolerant and compatible to RandomAccessFile
134

135         // Check state.
136
ensureOpen();
137
138         int n = window.remaining();
139         if (n <= 0) {
140             advanceWindow();
141             n = window.remaining();
142             if (n <= 0)
143                 return -1; // EOF
144
}
145
146         if (len < n)
147             n = len;
148         window.get(buf, off, n);
149
150         return n;
151     }
152
153     public void readFully(byte[] b) throws IOException JavaDoc {
154         readFully(b, 0, b.length);
155     }
156
157     public void readFully(byte[] buf, int off, int len) throws IOException JavaDoc {
158         int n = 0;
159     do {
160         int count = read(buf, off + n, len - n);
161         if (count < 0)
162         throw new EOFException JavaDoc();
163         n += count;
164     } while (n < len);
165     }
166
167     public int skipBytes(int n) throws IOException JavaDoc {
168         if (n <= 0)
169             return 0; // for compatibility to RandomAccessFile in case of closed
170

171         // Check state.
172
ensureOpen();
173
174     final long pos = channel.position() + window.position();
175     final long len = channel.size();
176     long newPos = pos + n;
177     if (newPos > len)
178         newPos = len;
179     seek(newPos);
180
181     return (int) (newPos - pos);
182     }
183     
184     public void close() throws IOException JavaDoc {
185         // Check state.
186
if (channel == null)
187             return;
188
189         // Paranoid, but safe.
190
window = null;
191         System.gc(); // sometimes works, sometimes not!
192
try {
193             channel.close();
194         } finally {
195             channel = null;
196         }
197     }
198
199     /** Throws an IOException if this read only file has been closed. */
200     private final void ensureOpen() throws IOException JavaDoc {
201         if (channel == null)
202             throw new IOException JavaDoc("Read only file has been closed!");
203     }
204 }
205
Popular Tags