0

对于我的一个项目FileSystem,我在 Box API Java SDK(的)上实现了 Java 7 。

但是,对于下载文件,当您想要内容流时,它只提供OutputStream作为参数的方法;具体来说,我目前正在使用这个

但这不适用于 JDK API。我需要能够实现FileSystemProvider#newInputStream()......因此我选择使用Pipe{Input,Output}Stream.

此外,由于 Box SDK API 方法是同步的(在这里并不重要),我将它们包装在Future. 我的代码如下(为简洁起见省略了导入):

@ParametersAreNonnullByDefault
public final class BoxFileInputStream
    extends InputStream
{
    private final Future<Void> future;
    private final PipedInputStream in;

    public BoxFileInputStream(final ExecutorService executor,
        final BoxFile file)
    {
        in = new PipedInputStream(16384);
        future = executor.submit(new Callable<Void>()
        {
            @Override
            public Void call()
                throws IOException
            {
                try {
                    file.download(new PipedOutputStream(in));
                    return null;
                } catch (BoxAPIException e) {
                    throw BoxIOException.wrap(e);
                }
            }
        });
    }

    @Override
    public int read()
        throws IOException
    {
        try {
            return in.read();
        } catch (IOException e) {
            future.cancel(true);
            throw new BoxIOException("download failure", e);
        }
    }

    @Override
    public int read(final byte[] b)
        throws IOException
    {
        try {
            return in.read(b);
        } catch (IOException e) {
            future.cancel(true);
            throw new BoxIOException("download failure", e);
        }
    }

    @Override
    public int read(final byte[] b, final int off, final int len)
        throws IOException
    {
        try {
            return in.read(b, off, len);
        } catch (IOException e) {
            future.cancel(true);
            throw new BoxIOException("download failure", e);
        }
    }

    @Override
    public long skip(final long n)
        throws IOException
    {
        try {
            return in.skip(n);
        } catch (IOException e) {
            future.cancel(true);
            throw new BoxIOException("download failure", e);
        }
    }

    @Override
    public int available()
        throws IOException
    {
        try {
            return in.available();
        } catch (IOException e) {
            future.cancel(true);
            throw new BoxIOException("download failure", e);
        }
    }

    @Override
    public void close()
        throws IOException
    {
        IOException streamException = null;
        IOException futureException = null;

        try {
            in.close();
        } catch (IOException e) {
            streamException = e;
        }

        try {
            future.get(5L, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            futureException = new BoxIOException("donwload interrupted", e);
        } catch (ExecutionException e) {
            futureException = new BoxIOException("download failure",
                e.getCause());
        } catch (CancellationException e) {
            futureException = new BoxIOException("download cancelled", e);
        } catch (TimeoutException e) {
            futureException = new BoxIOException("download timeout", e);
        }

        if (futureException != null) {
            if (streamException != null)
                futureException.addSuppressed(streamException);
            throw futureException;
        }

        if (streamException != null)
            throw streamException;
    }

    @Override
    public synchronized void mark(final int readlimit)
    {
        in.mark(readlimit);
    }

    @Override
    public synchronized void reset()
        throws IOException
    {
        try {
            in.reset();
        } catch (IOException e) {
            future.cancel(true);
            throw new BoxIOException("download failure", e);
        }
    }

    @Override
    public boolean markSupported()
    {
        return in.markSupported();
    }
}

该代码始终失败并显示以下堆栈跟踪(即在int read(byte[])

Exception in thread "main" com.github.fge.filesystem.box.exceptions.BoxIOException: download failure
    at com.github.fge.filesystem.box.io.BoxFileInputStream.read(BoxFileInputStream.java:81)
    at java.nio.file.Files.copy(Files.java:2735)
    at java.nio.file.Files.copy(Files.java:2854)
    at java.nio.file.CopyMoveHelper.copyToForeignTarget(CopyMoveHelper.java:126)
    at java.nio.file.Files.copy(Files.java:1230)
    at Main.main(Main.java:37)
    [ IDEA specific stack trace elements follow -- irrelevant]
Caused by: java.io.IOException: Pipe broken
    at java.io.PipedInputStream.read(PipedInputStream.java:322)
    at java.io.PipedInputStream.read(PipedInputStream.java:378)
    at java.io.InputStream.read(InputStream.java:101)
    at com.github.fge.filesystem.box.io.BoxFileInputStream.read(BoxFileInputStream.java:78)
    ... 10 more

但是当它失败时,下载已经完成......

好的,问题是,我可以获取文件大小并绕过它,但如果可能的话,我宁愿不这样做;如何修改此代码以避免 EPIPE?

4

2 回答 2

1

SDK 还提供了允许您手动请求高级用例的类BoxAPIRequestBoxAPIResponse这些类仍然会自动处理身份验证、错误、回退等,但可以让您对请求进行更精细的控制。

在您的情况下,您可以通过执行以下操作手动发出下载请求:

// Note: this example assumes you already have a BoxAPIConnection.
URL url = new URL("files/" + file.getID() + "/content")
BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
BoxAPIResponse response = request.send();

InputStream bodyStream = response.getBody();
// Use the stream.
response.disconnect();
于 2014-12-15T23:27:38.183 回答
0

好吧,我找到了解决方案,虽然我对它不是很满意......

因为我可以知道我尝试打开输入流的文件大小,所以我只需选择大小并将其减少读取的字节数——除非大小达到 0,在这种情况下所有读取方法都返回 -1。

于 2014-12-14T20:41:50.730 回答