예제 #1
0
  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;
  }
예제 #2
0
  /**
   * @throws IOException
   * @throws BadDescriptorException
   */
  public boolean feof() throws IOException, BadDescriptorException {
    checkReadable();

    if (eof) {
      return true;
    } else {
      return false;
    }
  }
예제 #3
0
  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;
  }
예제 #4
0
  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;
  }
예제 #5
0
  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;
  }
예제 #6
0
  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;
  }
예제 #7
0
  /**
   * @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;
    }
  }
예제 #8
0
  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;
  }