1 6 21 22 package de.schlichtherle.io.rof; 23 24 import java.io.EOFException ; 25 import java.io.File ; 26 import java.io.FileNotFoundException ; 27 import java.io.IOException ; 28 import java.io.RandomAccessFile ; 29 import java.nio.BufferUnderflowException ; 30 import java.nio.ByteBuffer ; 31 import java.nio.MappedByteBuffer ; 32 import java.nio.channels.FileChannel ; 33 34 50 public class MemoryMappedReadOnlyFile implements ReadOnlyFile { 51 52 private FileChannel channel; 53 54 private ByteBuffer window; 55 56 public MemoryMappedReadOnlyFile(File file) throws FileNotFoundException { 57 channel = new RandomAccessFile (file, "r").getChannel(); 58 try { 59 positionWindow(0); 60 } catch (IOException failure) { 61 FileNotFoundException fnfe = new FileNotFoundException (failure.toString()); 62 fnfe.initCause(failure); 63 throw fnfe; 64 } 65 } 66 67 private void positionWindow(long pos) throws IOException { 68 assert pos % Integer.MAX_VALUE == 0; 69 70 long chSize = channel.size(); 71 if (pos > chSize) return; 74 MappedByteBuffer mbb = channel.map(FileChannel.MapMode.READ_ONLY, pos, 75 Math.min(chSize - pos, Integer.MAX_VALUE)); 76 window = mbb; } 78 79 private final void advanceWindow() throws IOException { 80 positionWindow(channel.position() + Integer.MAX_VALUE); 81 } 82 83 public long length() throws IOException { 84 ensureOpen(); 85 86 return channel.size(); 87 } 88 89 public long getFilePointer() throws IOException { 90 ensureOpen(); 91 92 return channel.position() + window.position(); 93 } 94 95 public void seek(final long pos) throws IOException { 96 if (pos < 0) 97 throw new IOException ("File pointer must not be negative!"); 98 99 ensureOpen(); 100 101 if (pos > channel.size()) 102 throw new IOException ("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); 109 window.position((int) (pos % Integer.MAX_VALUE)); 110 } 111 112 public int read() throws IOException { 113 if (window.remaining() <= 0) { 114 advanceWindow(); 115 if (window.remaining() <= 0) 116 return -1; } 118 return window.get() & 0xFF; 119 } 120 121 public final int read(byte b[]) throws IOException { 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 { 127 if (buf == null) 129 throw new NullPointerException ("buf"); 130 if (off < 0 || len < 0 || off + len > buf.length) 131 throw new IndexOutOfBoundsException (); 132 if (len == 0) 133 return 0; 135 ensureOpen(); 137 138 int n = window.remaining(); 139 if (n <= 0) { 140 advanceWindow(); 141 n = window.remaining(); 142 if (n <= 0) 143 return -1; } 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 { 154 readFully(b, 0, b.length); 155 } 156 157 public void readFully(byte[] buf, int off, int len) throws IOException { 158 int n = 0; 159 do { 160 int count = read(buf, off + n, len - n); 161 if (count < 0) 162 throw new EOFException (); 163 n += count; 164 } while (n < len); 165 } 166 167 public int skipBytes(int n) throws IOException { 168 if (n <= 0) 169 return 0; 171 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 { 185 if (channel == null) 187 return; 188 189 window = null; 191 System.gc(); try { 193 channel.close(); 194 } finally { 195 channel = null; 196 } 197 } 198 199 200 private final void ensureOpen() throws IOException { 201 if (channel == null) 202 throw new IOException ("Read only file has been closed!"); 203 } 204 } 205 | Popular Tags |