美文网首页
Okio之readByteString(long)引发的异常

Okio之readByteString(long)引发的异常

作者: OkCoco | 来源:发表于2017-11-28 17:01 被阅读0次

上代码:

 private void read() {
        Source source = null;
        BufferedSource buffer = null;
        try {
            testFile = new File(Environment.getExternalStorageDirectory(), "test.txt");
            source = Okio.source(testFile);
            buffer = Okio.buffer(source);
            /** Removes all bytes from this, decodes them as {@code charset}, and returns the string. */
            /** readByteString()系列会返回指定编码的String,同时也会从buffer中移除相应的byteString(不传参数表示全部取出然后移除)。
             * 下面的方法也是一样,只不过移除的字节数量是调用者控制的
             * 注:若test.txt的bytes字节数远远低于2000,故而只单独调用最后一句也会报java.io.EOFException*/
            //System.out.println("String = " + buffer.readString(Charset.forName("UTF-8")));
            //System.out.println("readByteString = " + buffer.readByteString());
            //System.out.println("readByteString20 = " + buffer.readByteString(20));
            System.out.println("readByteString2000 = " + buffer.readByteString(2000));
        } catch (Exception e) {
            System.out.println("exception = " + e.getMessage());
            e.printStackTrace();
        } finally {
            try {
                /**
                 * close()的注释:
                 * Closes this source and releases the resources held by this source. It is an
                 * error to read a closed source. It is safe to close a source more than once.
                 */
                if (buffer != null ) {
                    buffer.close();
                }
                if (source != null) {
                    source.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

上面的代码回抛出java.io.EOFException异常。进行分析:

  1. buffer = Okio.buffer(source)的具体实现:
 /**
   * Returns a new source that buffers reads from {@code source}. The returned
   * source will perform bulk reads into its in-memory buffer. Use this wherever
   * you read a source to get an ergonomic and efficient access to data.
   * 大概就是说从根据source得到一个新的source,新的source可以执行批量读进自己的缓冲区。
   * 这是很高效的
   */
  public static BufferedSource buffer(Source source) {
    return new RealBufferedSource(source);
  }

@Override
 public ByteString readByteString(long byteCount) throws IOException {
    require(byteCount);
    return buffer.readByteString(byteCount);
  }

@Override
 public void require(long byteCount) throws IOException {
    if (!request(byteCount)) throw new EOFException();
  }

@Override
 public boolean request(long byteCount) throws IOException {
    if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount);
    if (closed) throw new IllegalStateException("closed");
    while (buffer.size < byteCount) {
      if (source.read(buffer, Segment.SIZE) == -1) return false;
    }
    return true;
  }

上面的例子中,第一次进来的时候,buffer.size() = 0(注:buffer是new 出来的,即 public final Buffer buffer = new Buffer();),此时While循环成立。source是通过source = Okio.source(testFile);这句代码返回的,内部实现是:


 return new Source() {
      @Override public long read(Buffer sink, long byteCount) throws IOException {
     ...
        try {
          Segment tail = sink.writableSegment(1);
          int maxToCopy = (int) Math.min(byteCount, Segment.SIZE - tail.limit);
          int bytesRead = in.read(tail.data, tail.limit, maxToCopy);
          if (bytesRead == -1) return -1;
          tail.limit += bytesRead;
          sink.size += bytesRead;
          return bytesRead;
        } catch (AssertionError e) {
          if (isAndroidGetsocknameError(e)) throw new IOException(e);
          throw e;
        }
      }
    ...
    };

由于我的test.txt中的字节数量为46,首次循环会将source中的46个字节全部存进buffer中返回,再次执行while循环(因为46<2000),执行到 int bytesRead = in.read(tail.data, tail.limit, maxToCopy);时,注意此处的tail,是一个双向环形链表。tail.limit的值为46,而tail.data的偏移量为46之后再无数据,故而返回-1,即request(long)返回false,require(long)抛出EOFException异常。

相关文章

网友评论

      本文标题:Okio之readByteString(long)引发的异常

      本文链接:https://www.haomeiwen.com/subject/bwbsbxtx.html