java - 复制(通过 Web API)完成;不管怎样,我的 pipe 坏了。怎么解决呢?

标签 java box-api broken-pipe

对于one of my projects ,我通过 Box API Java SDK( new one )实现了 Java 7 FileSystem

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

但这与 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?

最佳答案

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

就你而言,你可以做一个 download request手动执行以下操作:

// 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();

关于java - 复制(通过 Web API)完成;不管怎样,我的 pipe 坏了。怎么解决呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27454899/

相关文章:

java - Android 可以通过蓝牙支持 Zeroconf/Bonjour 吗? TCP/IP 怎么样?

Java如何检查二维数组中的一行是否为空。

java - 为什么jython很慢?

java - 如何在每个方法的基础上限制 JAX-RS 中的对象图?

Python socket.send() 只能发送一次,然后socket.error : [Errno 32] Broken pipe occurred

java - 使用 java 中 box.com 的 access_token 和授权 header 向 API V2 发送请求

java - 在java中下载box文件

box-api - 通过传递用户名和密码从 Box 获取未过期的访问 token 或从框中获取访问 token 。?

c++ - 套接字 : send() function returned 'Broken Pipe' error

linux - EC2 ssh broken pipe 终止正在运行的进程