Java 在不关闭的情况下使流无效

Java 在不关闭的情况下使流无效,java,file-io,file-descriptor,fileinputstream,finalizer,Java,File Io,File Descriptor,Fileinputstream,Finalizer,这是一个后续行动 根据我前面的问题,我不能依赖这样的代码(目前碰巧在JDK8中工作): 但是,为了防止意外错误,并且作为一种自我文档的形式,我希望在使用完每个文件流后使其无效,而不关闭底层文件描述符 每个FileInputStream都是独立的,其定位由RandomAccessFile控制。我共享相同的FileDescriptor,以防止多次打开同一路径时出现任何争用情况。当我处理完一个FileInputStream后,我想使它失效,以便在使用第二个FileInputStream时不可能意外地从

这是一个后续行动

根据我前面的问题,我不能依赖这样的代码(目前碰巧在JDK8中工作):

但是,为了防止意外错误,并且作为一种自我文档的形式,我希望在使用完每个文件流后使其无效,而不关闭底层文件描述符

每个FileInputStream都是独立的,其定位由RandomAccessFile控制。我共享相同的FileDescriptor,以防止多次打开同一路径时出现任何争用情况。当我处理完一个FileInputStream后,我想使它失效,以便在使用第二个FileInputStream时不可能意外地从中读取数据(这会导致第二个FileInputStream跳过数据)

我该怎么做

注:

  • 我使用的库需要与java.io兼容*
  • 如果您建议使用一个库(如果可能的话,我更喜欢内置java语义),它必须是linux(主要目标)的通用库(打包库)和windows(实验目标库)的可用库
  • 但是,windows支持并不是绝对必需的
编辑:作为对评论的回应,以下是我的工作流程:


在unix下,通常可以通过使用文件描述符来避免此类问题


因为java不提供这样的特性,所以一个选项是一个本机库,它公开了这个特性。举个例子。另一方面,jnr依赖的jdk实现属性比您最初的问题多得多。

纯Java解决方案可能是创建一个转发装饰器,用于检查每个方法调用是否验证流。对于
InputStream
,此装饰程序可能如下所示:

public final class CheckedInputStream extends InputStream {
  final InputStream delegate;
  boolean validated;

  public CheckedInputStream(InputStream stream) throws FileNotFoundException {
    delegate = stream;
    validated = true;
  }

  public void invalidate() {
    validated = false;
  }

  void checkValidated() {
    if (!validated) {
      throw new IllegalStateException("Stream is invalidated.");
    }
  }

  @Override
  public int read() throws IOException {
    checkValidated();
    return delegate.read();
  }

  @Override
  public int read(byte b[]) throws IOException {
    checkValidated();
    return read(b, 0, b.length);
  }

  @Override
  public int read(byte b[], int off, int len) throws IOException {
    checkValidated();
    return delegate.read(b, off, len);
  }

  @Override
  public long skip(long n) throws IOException {
    checkValidated();
    return delegate.skip(n);
  }

  @Override
  public int available() throws IOException {
    checkValidated();
    return delegate.available();
  }

  @Override
  public void close() throws IOException {
    checkValidated();
    delegate.close();
  }

  @Override
  public synchronized void mark(int readlimit) {
    checkValidated();
    delegate.mark(readlimit);
  }

  @Override
  public synchronized void reset() throws IOException {
    checkValidated();
    delegate.reset();
  }

  @Override
  public boolean markSupported() {
    checkValidated();
    return delegate.markSupported();
  }
}
您可以像这样使用它:

CheckedInputStream f_1 = new CheckedInputStream(new FileInputStream(r.getFD()));
                      // some io, not shown
                   f_1.invalidate();

                   f_1.read(); // throws IllegalStateException

如果您解释需要在同一个FD上打开不同流的原因,可能会有所帮助。我假设您希望按顺序多次读取文件,但为什么不使用适当的争用控制共享
RandomAccessFile
?这有一种代码的味道,或者可能是一种错误。我的目标是提供实验性windows构建的软件。我更新了我的问题以反映这一点。这非常好-您的CheckedInputStream类保护我不受从传入流中读取的库方法的影响。所以,如果我从流1创建流2,将流2传递给库1,求0,从流1读取,并调用库1函数(我不知道从流2读取),从流1读取的第二次数据将跳过数据。CheckedInputClass保护我不受此影响。只有两个问题:CheckedInputClass是否可以通过编程而不是手动定义?如果这是python,我将重写uuu getattribute,使用元类或类装饰器。苹果和橘子我知道,但java确实有一些反射能力。第二:为什么字节码编译器没有警告我没有捕获CheckedInputStream抛出的IllegalStateException(即,您的示例,没有try/catch)?1。我认为Java中没有一种简单的方法可以生成这样一个类。对于大多数集合类,Guava提供了转发装饰器(例如),但是对于您的用例,您仍然需要覆盖每个方法,这样对您没有帮助。2.IllegalStateException是一个RuntimeException,因此是一个。
public final class CheckedInputStream extends InputStream {
  final InputStream delegate;
  boolean validated;

  public CheckedInputStream(InputStream stream) throws FileNotFoundException {
    delegate = stream;
    validated = true;
  }

  public void invalidate() {
    validated = false;
  }

  void checkValidated() {
    if (!validated) {
      throw new IllegalStateException("Stream is invalidated.");
    }
  }

  @Override
  public int read() throws IOException {
    checkValidated();
    return delegate.read();
  }

  @Override
  public int read(byte b[]) throws IOException {
    checkValidated();
    return read(b, 0, b.length);
  }

  @Override
  public int read(byte b[], int off, int len) throws IOException {
    checkValidated();
    return delegate.read(b, off, len);
  }

  @Override
  public long skip(long n) throws IOException {
    checkValidated();
    return delegate.skip(n);
  }

  @Override
  public int available() throws IOException {
    checkValidated();
    return delegate.available();
  }

  @Override
  public void close() throws IOException {
    checkValidated();
    delegate.close();
  }

  @Override
  public synchronized void mark(int readlimit) {
    checkValidated();
    delegate.mark(readlimit);
  }

  @Override
  public synchronized void reset() throws IOException {
    checkValidated();
    delegate.reset();
  }

  @Override
  public boolean markSupported() {
    checkValidated();
    return delegate.markSupported();
  }
}
CheckedInputStream f_1 = new CheckedInputStream(new FileInputStream(r.getFD()));
                      // some io, not shown
                   f_1.invalidate();

                   f_1.read(); // throws IllegalStateException