private ByteList bufferedRead(int number) throws IOException, BadDescriptorException { checkReadable(); ensureRead(); int resultSize = 0; // 128K seems to be the minimum at which the stat+seek is faster than reallocation final int BULK_THRESHOLD = 128 * 1024; if (number >= BULK_THRESHOLD && descriptor.isSeekable() && descriptor.getChannel() instanceof FileChannel) { // // If it is a file channel, then we can pre-allocate the output buffer // to the total size of buffered + remaining bytes in file // FileChannel fileChannel = (FileChannel) descriptor.getChannel(); resultSize = (int) Math.min( fileChannel.size() - fileChannel.position() + bufferedInputBytesRemaining(), number); } else { // // Cannot discern the total read length - allocate at least enough for the buffered data // resultSize = Math.min(bufferedInputBytesRemaining(), number); } ByteList result = new ByteList(resultSize); bufferedRead(result, number); return result; }
/** * @throws IOException * @throws BadDescriptorException */ public boolean feof() throws IOException, BadDescriptorException { checkReadable(); if (eof) { return true; } else { return false; } }
public synchronized ByteList read(int number) throws IOException, BadDescriptorException { checkReadable(); ensureReadNonBuffered(); ByteList byteList = new ByteList(number); // TODO this should entry into error handling somewhere int bytesRead = descriptor.read(number, byteList); if (bytesRead == -1) { eof = true; } return byteList; }
public synchronized int fgetc() throws IOException, BadDescriptorException { if (eof) { return -1; } checkReadable(); int c = read(); if (c == -1) { eof = true; return c; } return c & 0xff; }
public synchronized int getline(ByteList dst, byte terminator, long limit) throws IOException, BadDescriptorException { checkReadable(); ensureRead(); descriptor.checkOpen(); int totalRead = 0; boolean found = false; if (ungotc != -1) { dst.append((byte) ungotc); found = ungotc == terminator; ungotc = -1; limit--; ++totalRead; } while (!found) { final byte[] bytes = buffer.array(); final int begin = buffer.arrayOffset() + buffer.position(); final int end = begin + buffer.remaining(); int len = 0; for (int i = begin; i < end && limit-- > 0 && !found; ++i) { found = bytes[i] == terminator; ++len; } if (limit < 1) found = true; if (len > 0) { dst.append(buffer, len); totalRead += len; } if (!found) { int n = refillBuffer(); if (n <= 0) { if (n < 0 && totalRead < 1) { return -1; } break; } } } return totalRead; }
private int bufferedRead(ByteBuffer dst, boolean partial) throws IOException, BadDescriptorException { checkReadable(); ensureRead(); boolean done = false; int bytesRead = 0; // // Copy what is in the buffer, if there is some buffered data // bytesRead += copyBufferedBytes(dst); // // Avoid double-copying for reads that are larger than the buffer size, or // the destination is a direct buffer. // while ((bytesRead < 1 || !partial) && (dst.remaining() >= BUFSIZE || dst.isDirect())) { ByteBuffer tmpDst = dst; if (!dst.isDirect()) { // // We limit reads to BULK_READ_SIZED chunks to avoid NIO allocating // a huge temporary native buffer, when doing reads into a heap buffer // If the dst buffer is direct, then no need to limit. // int bytesToRead = Math.min(BULK_READ_SIZE, dst.remaining()); if (bytesToRead < dst.remaining()) { tmpDst = dst.duplicate(); tmpDst.limit(tmpDst.position() + bytesToRead); } } int n = descriptor.read(tmpDst); if (n == -1) { eof = true; done = true; break; } else if (n == 0) { done = true; break; } else { bytesRead += n; } } // // Complete the request by filling the read buffer first // while (!done && dst.hasRemaining() && (bytesRead < 1 || !partial)) { int read = refillBuffer(); if (read == -1) { eof = true; done = true; break; } else if (read == 0) { done = true; break; } else { // append what we read into our buffer and allow the loop to continue bytesRead += copyBufferedBytes(dst); } } if (eof && bytesRead == 0 && dst.remaining() != 0) { throw newEOFException(); } return bytesRead; }
/** * @deprecated readall do busy loop for the IO which has NONBLOCK bit. You should implement the * logic by yourself with fread(). */ @Deprecated public synchronized ByteList readall() throws IOException, BadDescriptorException { final long fileSize = descriptor.isSeekable() && descriptor.getChannel() instanceof FileChannel ? ((FileChannel) descriptor.getChannel()).size() : 0; // // Check file size - special files in /proc have zero size and need to be // handled by the generic read path. // if (fileSize > 0) { ensureRead(); FileChannel channel = (FileChannel) descriptor.getChannel(); final long left = fileSize - channel.position() + bufferedInputBytesRemaining(); if (left <= 0) { eof = true; return null; } if (left > Integer.MAX_VALUE) { if (getRuntime() != null) { throw getRuntime().newIOError("File too large"); } else { throw new IOException("File too large"); } } ByteList result = new ByteList((int) left); ByteBuffer buf = ByteBuffer.wrap(result.getUnsafeBytes(), result.begin(), (int) left); // // Copy any buffered data (including ungetc byte) // copyBufferedBytes(buf); // // Now read unbuffered directly from the file // while (buf.hasRemaining()) { final int MAX_READ_CHUNK = 1 * 1024 * 1024; // // When reading into a heap buffer, the jvm allocates a temporary // direct ByteBuffer of the requested size. To avoid allocating // a huge direct buffer when doing ludicrous reads (e.g. 1G or more) // we split the read up into chunks of no more than 1M // ByteBuffer tmp = buf.duplicate(); if (tmp.remaining() > MAX_READ_CHUNK) { tmp.limit(tmp.position() + MAX_READ_CHUNK); } int n = channel.read(tmp); if (n <= 0) { break; } buf.position(tmp.position()); } eof = true; result.length(buf.position()); return result; } else if (descriptor.isNull()) { return new ByteList(0); } else { checkReadable(); ByteList byteList = new ByteList(); ByteList read = fread(BUFSIZE); if (read == null) { eof = true; return byteList; } while (read != null) { byteList.append(read); read = fread(BUFSIZE); } return byteList; } }
public synchronized ByteList fgets(ByteList separatorString) throws IOException, BadDescriptorException { checkReadable(); ensureRead(); if (separatorString == null) { return readall(); } final ByteList separator = (separatorString == PARAGRAPH_DELIMETER) ? PARAGRAPH_SEPARATOR : separatorString; descriptor.checkOpen(); if (feof()) { return null; } int c = read(); if (c == -1) { return null; } // unread back buffer.position(buffer.position() - 1); ByteList buf = new ByteList(40); byte first = separator.getUnsafeBytes()[separator.getBegin()]; LineLoop: while (true) { ReadLoop: while (true) { byte[] bytes = buffer.array(); int offset = buffer.position(); int max = buffer.limit(); // iterate over remainder of buffer until we find a match for (int i = offset; i < max; i++) { c = bytes[i]; if (c == first) { // terminate and advance buffer when we find our char buf.append(bytes, offset, i - offset); if (i >= max) { buffer.clear(); } else { buffer.position(i + 1); } break ReadLoop; } } // no match, append remainder of buffer and continue with next block buf.append(bytes, offset, buffer.remaining()); int read = refillBuffer(); if (read == -1) break LineLoop; } // found a match above, check if remaining separator characters match, appending as we go for (int i = 0; i < separator.getRealSize(); i++) { if (c == -1) { break LineLoop; } else if (c != separator.getUnsafeBytes()[separator.getBegin() + i]) { buf.append(c); continue LineLoop; } buf.append(c); if (i < separator.getRealSize() - 1) { c = read(); } } break; } if (separatorString == PARAGRAPH_DELIMETER) { while (c == separator.getUnsafeBytes()[separator.getBegin()]) { c = read(); } ungetc(c); } return buf; }