1 package it.unimi.dsi.fastutil.io; 2 3 23 24 import it.unimi.dsi.fastutil.bytes.ByteArrays; 25 import it.unimi.dsi.fastutil.io.MeasurableInputStream; 26 import it.unimi.dsi.fastutil.io.RepositionableStream; 27 28 import java.io.IOException ; 29 import java.io.InputStream ; 30 import java.nio.channels.FileChannel ; 31 import java.util.EnumSet ; 32 33 76 77 public class FastBufferedInputStream extends MeasurableInputStream implements RepositionableStream { 78 79 80 public final static int DEFAULT_BUFFER_SIZE = 8 * 1024; 81 82 83 public static enum LineTerminator { 84 85 CR, 86 87 LF, 88 89 CR_LF 90 } 91 92 93 public final static EnumSet <LineTerminator> ALL_TERMINATORS = EnumSet.allOf( LineTerminator.class ); 94 95 96 protected InputStream is; 97 98 99 protected byte buffer[]; 100 101 102 protected int pos; 103 104 107 protected long readBytes; 108 109 110 protected int avail; 111 112 113 private FileChannel fileChannel; 114 115 116 private RepositionableStream rs; 117 118 119 private MeasurableInputStream ms; 120 121 126 127 public FastBufferedInputStream( final InputStream is, final int bufSize ) { 128 this.is = is; 129 buffer = new byte[ bufSize ]; 130 131 if ( is instanceof RepositionableStream ) rs = (RepositionableStream)is; 132 if ( is instanceof MeasurableInputStream ) ms = (MeasurableInputStream)is; 133 134 if ( rs == null ) { 135 136 try { 137 fileChannel = (FileChannel )( is.getClass().getMethod( "getChannel", new Class [] {} ) ).invoke( is, new Object [] {} ); 138 } 139 catch( IllegalAccessException e ) {} 140 catch( IllegalArgumentException e ) {} 141 catch( NoSuchMethodException e ) {} 142 catch( java.lang.reflect.InvocationTargetException e ) {} 143 catch( ClassCastException e ) {} 144 } 145 } 146 147 151 public FastBufferedInputStream( final InputStream is ) { 152 this( is, DEFAULT_BUFFER_SIZE ); 153 } 154 155 162 163 protected boolean noMoreCharacters() throws IOException { 164 if ( avail == 0 ) { 165 avail = is.read( buffer ); 166 if ( avail <= 0 ) { 167 avail = 0; 168 return true; 169 } 170 pos = 0; 171 } 172 return false; 173 } 174 175 176 177 public int read() throws IOException { 178 if ( noMoreCharacters() ) return -1; 179 avail--; 180 readBytes++; 181 return buffer[ pos++ ] & 0xFF; 182 } 183 184 185 public int read( final byte b[], int offset, int length ) throws IOException { 186 if ( length <= avail ) { 187 System.arraycopy( buffer, pos, b, offset, length ); 188 pos += length; 189 avail -= length; 190 readBytes += length; 191 return length; 192 } 193 194 final int head = avail; 195 System.arraycopy( buffer, pos, b, offset, head ); 196 offset += head; 197 length -= head; 198 avail = 0; 199 200 final int residual = length % buffer.length; 201 int result; 202 203 if ( ( result = is.read( b, offset, length - residual ) ) < length - residual ) { 204 final int t = result < 0 205 ? ( head != 0 ? head : -1 ) 206 : result + head; 207 if ( t > 0 ) readBytes += t; 208 return t; 209 } 210 211 avail = is.read( buffer ); 212 if ( avail < 0 ) { 213 avail = pos = 0; 214 final int t = result + head > 0 ? result + head : -1; 215 if ( t > 0 ) readBytes += t; 216 return t; 217 } 218 pos = Math.min( avail, residual ); 219 System.arraycopy( buffer, 0, b, offset + length - residual, pos ); 220 avail -= pos; 221 final int t = result + head + pos; 222 readBytes += t; 223 return t; 224 } 225 226 232 233 public int readLine( final byte[] array ) throws IOException { 234 return readLine( array, 0, array.length, ALL_TERMINATORS ); 235 } 236 237 245 246 public int readLine( final byte[] array, final EnumSet <LineTerminator> terminators ) throws IOException { 247 return readLine( array, 0, array.length, terminators ); 248 } 249 250 258 public int readLine( final byte[] array, final int off, final int len ) throws IOException { 259 return readLine( array, off, len, ALL_TERMINATORS ); 260 } 261 262 308 309 public int readLine( final byte[] array, final int off, final int len, final EnumSet <LineTerminator> terminators ) throws IOException { 310 ByteArrays.ensureOffsetLength( array ,off, len ); 311 if ( len == 0 ) return 0; if ( noMoreCharacters() ) return -1; 313 int i, k = 0, remaining = len, read = 0; for(;;) { 315 for( i = 0; i < avail && i < remaining && ( k = buffer[ pos + i ] ) != '\n' && k != '\r' ; i++ ); 316 System.arraycopy( buffer, pos, array, off + read, i ); 317 pos += i; 318 avail -= i; 319 read += i; 320 remaining -= i; 321 if ( remaining == 0 ) { 322 readBytes += read; 323 return read; } 325 326 if ( avail > 0 ) { if ( k == '\n' ) { pos++; 329 avail--; 330 if ( terminators.contains( LineTerminator.LF ) ) { 331 readBytes += read + 1; 332 return read; 333 } 334 else { 335 array[ off + read++ ] = '\n'; 336 remaining--; 337 } 338 } 339 else if ( k == '\r' ) { pos++; 341 avail--; 342 343 if ( terminators.contains( LineTerminator.CR_LF ) ) { 344 if ( avail > 0 ) { 345 if ( buffer[ pos ] == '\n' ) { pos ++; 347 avail--; 348 readBytes += read + 2; 349 return read; 350 } 351 } 352 else { if ( noMoreCharacters() ) { 354 356 if ( ! terminators.contains( LineTerminator.CR ) ) { 357 array[ off + read++ ] = '\r'; 358 remaining--; 359 readBytes += read; 360 } 361 else readBytes += read + 1; 362 363 return read; 364 } 365 if ( buffer[ 0 ] == '\n' ) { 366 pos++; 368 avail--; 369 readBytes += read + 2; 370 return read; 371 } 372 } 373 } 374 375 if ( terminators.contains( LineTerminator.CR ) ) { 376 readBytes += read + 1; 377 return read; 378 } 379 380 array[ off + read++ ] = '\r'; 381 remaining--; 382 } 383 } 384 else if ( noMoreCharacters() ) { 385 readBytes += read; 386 return read; 387 } 388 } 389 } 390 391 392 393 public void position( long newPosition ) throws IOException { 394 395 final long position = readBytes; 396 397 401 402 if ( newPosition <= position + avail && newPosition >= position - pos ) { 403 pos += newPosition - position; 404 avail -= newPosition - position; 405 readBytes = newPosition; 406 return; 407 } 408 409 if ( rs != null ) rs.position( newPosition ); 410 else if ( fileChannel != null ) fileChannel.position( newPosition ); 411 else throw new UnsupportedOperationException ( "position() can only be called if the underlying byte stream implements the RepositionableStream interface or if the getChannel() method of the underlying byte stream exists and returns a FileChannel" ); 412 readBytes = newPosition; 413 414 avail = Math.max( 0, is.read( buffer ) ); 415 pos = 0; 416 } 417 418 public long position() throws IOException { 419 return readBytes; 420 } 421 422 427 428 public long length() throws IOException { 429 if ( ms == null ) throw new UnsupportedOperationException (); 430 return ms.length(); 431 } 432 433 434 public long skip( long n ) throws IOException { 435 if ( n <= avail ) { 436 final int m = (int)n; 437 pos += m; 438 avail -= m; 439 readBytes += n; 440 return n; 441 } 442 443 final int head = avail; 444 n -= head; 445 avail = 0; 446 447 final int residual = (int)( n % buffer.length ); 448 long result; 449 if ( ( result = is.skip( n - residual ) ) < n - residual ) { 450 avail = 0; 451 readBytes += result + head; 452 return result + head; 453 } 454 455 avail = Math.max( is.read( buffer ), 0 ); 456 pos = Math.min( residual, avail ); 457 avail -= pos; 458 final long t = result + head + pos; 459 readBytes += t; 460 return t; 461 } 462 463 464 public int available() throws IOException { 465 return (int)Math.min( is.available() + (long)avail, Integer.MAX_VALUE ); 466 } 467 468 public void close() throws IOException { 469 if ( is == null ) return; 470 if ( is != System.in ) is.close(); 471 is = null; 472 buffer = null; 473 } 474 475 484 485 public void flush() { 486 if ( is == null ) return; 487 readBytes += avail; 488 avail = pos = 0; 489 } 490 491 498 @Deprecated 499 public void reset() { 500 flush(); 501 } 502 } 503 | Popular Tags |