{"id":5501,"date":"2014-03-30T23:14:57","date_gmt":"2014-03-30T23:14:57","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2014\/03\/30\/given-a-java-inputstream-how-can-i-determine-the-current-offset-in-the-stream-collection-of-common-programming-errors\/"},"modified":"2014-03-30T23:14:57","modified_gmt":"2014-03-30T23:14:57","slug":"given-a-java-inputstream-how-can-i-determine-the-current-offset-in-the-stream-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2014\/03\/30\/given-a-java-inputstream-how-can-i-determine-the-current-offset-in-the-stream-collection-of-common-programming-errors\/","title":{"rendered":"Given a Java InputStream, how can I determine the current offset in the stream?-Collection of common programming errors"},"content":{"rendered":"<p>You&#8217;ll need to follow the Decorator pattern established in <code>java.io<\/code> to implement this.<\/p>\n<p>Let&#8217;s give it a try here:<\/p>\n<pre><code>import java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\npublic final class PositionInputStream\n  extends FilterInputStream\n{\n\n  private long pos = 0;\n\n  private long mark = 0;\n\n  public PositionInputStream(InputStream in)\n  {\n    super(in);\n  }\n\n  \/**\n   * <br \/>Get the stream position.<br \/><br \/>\n   *\n   * <br \/>Eventually, the position will roll over to a negative number.\n   * Reading 1 Tb per second, this would occur after approximately three \n   * months. Applications should account for this possibility in their \n   * design.<br \/><br \/>\n   *\n   * @return the current stream position.\n   *\/\n  public synchronized long getPosition()\n  {\n    return pos;\n  }\n\n  @Override\n  public synchronized int read()\n    throws IOException\n  {\n    int b = super.read();\n    if (b &gt;= 0)\n      pos += 1;\n    return b;\n  }\n\n  @Override\n  public synchronized int read(byte[] b, int off, int len)\n    throws IOException\n  {\n    int n = super.read(b, off, len);\n    if (n &gt; 0)\n      pos += n;\n    return n;\n  }\n\n  @Override\n  public synchronized long skip(long skip)\n    throws IOException\n  {\n    long n = super.skip(skip);\n    if (n &gt; 0)\n      pos += n;\n    return n;\n  }\n\n  @Override\n  public synchronized void mark(int readlimit)\n  {\n    super.mark(readlimit);\n    mark = pos;\n  }\n\n  @Override\n  public synchronized void reset()\n    throws IOException\n  {\n    \/* A call to reset can still succeed if mark is not supported, but the \n     * resulting stream position is undefined, so it's not allowed here. *\/\n    if (!markSupported())\n      throw new IOException(\"Mark not supported.\");\n    super.reset();\n    pos = mark;\n  }\n\n}\n<\/code><\/pre>\n<p>The InputStreams are intended to be thread safe, so that accounts for the liberal use of synchronization. I played around with <code>volatile<\/code> and <code>AtomicLong<\/code> position variables, but synchronization is probably best because it allows one thread to operate on the stream and query its position without relinquishing the lock.<\/p>\n<pre><code>PositionInputStream is = .\nsynchronized (is) {\n  is.read(buf);\n  pos = is.getPosition();\n}\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>You&#8217;ll need to follow the Decorator pattern established in java.io to implement this. Let&#8217;s give it a try here: import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; public final class PositionInputStream extends FilterInputStream { private long pos = 0; private long mark = 0; public PositionInputStream(InputStream in) { super(in); } \/** * Get the stream position. * [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5501","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/5501","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=5501"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/5501\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=5501"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=5501"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=5501"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}