1 6 21 22 package de.schlichtherle.io.rof; 23 24 import java.io.File ; 25 import java.io.FileNotFoundException ; 26 import java.io.IOException ; 27 28 40 public class BufferedReadOnlyFile extends FilterReadOnlyFile { 41 42 45 private static final int WINDOW_LEN = 4096; 46 47 48 protected static final long min(long a, long b) { 49 return a < b ? a : b; 50 } 51 52 53 protected static final long max(long a, long b) { 54 return a < b ? b : a; 55 } 56 57 private long length; 58 59 63 private long fp; 64 65 69 private long windowOff; 70 71 74 private final byte[] window; 75 76 private boolean closed; 77 78 87 public BufferedReadOnlyFile( 88 final File file) 89 throws NullPointerException , 90 FileNotFoundException , 91 IOException { 92 this(null, file, WINDOW_LEN); 93 } 94 95 105 public BufferedReadOnlyFile( 106 final File file, 107 final int windowLen) 108 throws NullPointerException , 109 FileNotFoundException , 110 IOException { 111 this(null, file, windowLen); 112 } 113 114 123 public BufferedReadOnlyFile( 124 final ReadOnlyFile rof) 125 throws NullPointerException , 126 FileNotFoundException , 127 IOException { 128 this(rof, null, WINDOW_LEN); 129 } 130 131 141 public BufferedReadOnlyFile( 142 final ReadOnlyFile rof, 143 final int windowLen) 144 throws NullPointerException , 145 FileNotFoundException , 146 IOException { 147 this(rof, null, windowLen); 148 } 149 150 private BufferedReadOnlyFile( 151 ReadOnlyFile rof, 152 final File file, 153 final int windowLen) 154 throws NullPointerException , 155 FileNotFoundException , 156 IOException { 157 super(rof); 158 159 if (rof == null) { 161 if (file == null) 162 throw new NullPointerException (); 163 rof = createReadOnlyFile(file); 164 } else { assert file == null; 166 } 167 if (windowLen <= 0) 168 throw new IllegalArgumentException (); 169 170 super.rof = rof; 171 length = rof.length(); 172 fp = rof.getFilePointer(); 173 window = new byte[windowLen]; 174 invalidateWindow(); 175 176 assert window.length > 0; 177 } 178 179 188 protected ReadOnlyFile createReadOnlyFile(File file) 189 throws IOException { 190 return new SimpleReadOnlyFile(file); 191 } 194 195 public long length() throws IOException { 196 final long newLength = rof.length(); 197 if (newLength != length) { 198 length = newLength; 199 invalidateWindow(); 200 } 201 202 return length; 203 } 204 205 public long getFilePointer() throws IOException { 206 ensureOpen(); 207 208 return fp; 209 } 210 211 public void seek(final long fp) throws IOException { 212 if (fp < 0) 213 throw new IOException ("File pointer must not be negative!"); 214 215 ensureOpen(); 216 217 final long length = length(); 218 if (fp > length) 219 throw new IOException ("File pointer (" + fp 220 + ") is larger than file length (" + length + ")!"); 221 222 this.fp = fp; 223 } 224 225 public int read() throws IOException { 226 ensureOpen(); 228 if (fp >= length()) 229 return -1; 230 231 positionWindow(); 233 return window[(int) (fp++ % window.length)]; 234 } 235 236 public int read(final byte[] buf, final int off, final int len) 237 throws IOException { 238 if (buf == null) 240 throw new NullPointerException ("buf"); 241 final int offPlusLen = off + len; 242 if ((off | len | offPlusLen | buf.length - offPlusLen) < 0) 243 throw new IndexOutOfBoundsException (); 244 if (len == 0) 245 return 0; 247 ensureOpen(); 249 final long length = length(); 250 if (fp >= length) 251 return -1; 252 253 final int windowLen = window.length; 255 int read = 0; 257 { 258 final int o = (int) (fp % windowLen); 260 if (o != 0) { 261 positionWindow(); 263 read = (int) min(len, windowLen - o); 264 read = (int) min(read, length - fp); 265 System.arraycopy(window, o, buf, off, read); 266 fp += read; 267 } 268 } 269 270 { 271 while (read + windowLen < len && fp + windowLen <= length) { 273 positionWindow(); 275 System.arraycopy(window, 0, buf, off + read, windowLen); 276 read += windowLen; 277 fp += windowLen; 278 } 279 } 280 281 if (read < len && fp < length) { 283 positionWindow(); 285 final int n = (int) min(len - read, length - fp); 286 System.arraycopy(window, 0, buf, off + read, n); 287 read += n; 288 fp += n; 289 } 290 291 assert read > 0; 294 return read; 295 } 296 297 public int skipBytes(int n) throws IOException { 298 if (n <= 0) 299 return 0; 301 ensureOpen(); 303 304 if (fp >= length()) 305 return 0; 306 final long remaining = length() - fp; 307 if (n > remaining) 308 n = (int) remaining; 309 fp += n; 310 311 return n; 312 } 313 314 315 private final void ensureOpen() throws IOException { 316 if (closed) 317 throw new IOException ("RaesReadOnlyFile has been closed!"); 318 } 319 320 325 public void close() throws IOException { 326 if (!closed) { 328 closed = true; 329 rof.close(); 330 } 331 } 332 333 337 345 private void positionWindow() throws IOException { 346 final long fp = this.fp; 348 final int windowLen = window.length; 349 final long nextWindowOff = windowOff + windowLen; 350 if (windowOff <= fp && fp < nextWindowOff) 351 return; 352 353 try { 354 windowOff = (fp / windowLen) * windowLen; if (windowOff != nextWindowOff) 357 rof.seek(windowOff); 358 359 int n = 0; 364 do { 365 int read = rof.read(window, n, windowLen - n); 366 if (read < 0) 367 break; 368 n += read; 369 } while (n < windowLen); 370 } catch (IOException ioe) { 371 windowOff = -windowLen - 1; throw ioe; 373 } 374 } 375 376 380 private final void invalidateWindow() { 381 windowOff = Long.MIN_VALUE; 382 } 383 } 384 | Popular Tags |