0

我正在创建一个应用程序,它使用 FTP/CLoudRail 通过 Internet 访问文件。在打开文件时,我使用这种方法首先获取输入流,然后将其解析为 ParcelFileDescriptor。问题是,当打开 PDF 文件时,我得到了 brokenPipe 错误。请注意,其他文件类型(如图像/文本文件)不会发生这种情况

这是我使用的代码:

@Override
public ParcelFileDescriptor openDocument(final String documentId, final String mode,
                                         CancellationSignal signal)
        throws FileNotFoundException {
    Log.d(TAG,"Opening document");
    final CloudFile file = getFileForDocId(documentId);
    final CloudConnection connection = getCloudConnection(documentId);
    //TODO Open a file
    try {
        final boolean isWrite = (mode.indexOf('w') != -1);
        if (isWrite) {
            return null;
        } else {
            InputStream inputStream = connection.getConnectedClient().download(file.getPath());
            if(null != inputStream){
                return ParcelFileDescriptorUtil.pipeFrom(inputStream);
            }
        }

        return null;
    } catch (Exception e) {
        CrashReportingManager.logException(e);
        throw new FileNotFoundException("Failed to open document with id " + documentId +
                " and mode " + mode);
    }
}

这是 ParcelFileDescriptorUtil:

public class ParcelFileDescriptorUtil {
public static ParcelFileDescriptor pipeFrom(InputStream inputStream)
        throws IOException {
    final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
    final OutputStream output = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);

    new TransferThread(inputStream, output).start();

    return pipe[0];
}

@SuppressWarnings("unused")
public static ParcelFileDescriptor pipeTo(OutputStream outputStream)
        throws IOException {
    final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
    final InputStream input = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0]);

    new TransferThread(input, outputStream).start();

    return pipe[1];
}

static class TransferThread extends Thread {
    final InputStream mIn;
    final OutputStream mOut;

    TransferThread(InputStream in, OutputStream out) {
        super("ParcelFileDescriptor Transfer Thread");
        mIn = in;
        mOut = out;
        setDaemon(true);
    }

    @Override
    public void run() {
        try {
            IoUtils.copy(mIn, mOut);
        } catch (IOException e) {
            Log.e("TransferThread", "writing failed");
            CrashReportingManager.logException(e);
        } finally {
            IoUtils.flushQuietly(mOut);
            IoUtils.closeQuietly(mIn);
            IoUtils.closeQuietly(mOut);
        }
    }
}

public static int parseMode(String mode) {
    final int modeBits;
    if ("r".equals(mode)) {
        modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
    } else if ("w".equals(mode) || "wt".equals(mode)) {
        modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
                | ParcelFileDescriptor.MODE_CREATE
                | ParcelFileDescriptor.MODE_TRUNCATE;
    } else if ("wa".equals(mode)) {
        modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
                | ParcelFileDescriptor.MODE_CREATE
                | ParcelFileDescriptor.MODE_APPEND;
    } else if ("rw".equals(mode)) {
        modeBits = ParcelFileDescriptor.MODE_READ_WRITE
                | ParcelFileDescriptor.MODE_CREATE;
    } else if ("rwt".equals(mode)) {
        modeBits = ParcelFileDescriptor.MODE_READ_WRITE
                | ParcelFileDescriptor.MODE_CREATE
                | ParcelFileDescriptor.MODE_TRUNCATE;
    } else {
        throw new IllegalArgumentException("Bad mode '" + mode + "'");
    }
    return modeBits;
}

@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static ParcelFileDescriptor pipeFrom(InputStream inputStream, IThreadListener listener)
        throws IOException {
    ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
    ParcelFileDescriptor readSide = pipe[0];
    ParcelFileDescriptor writeSide = pipe[1];

    // start the transfer thread
    new TransferThread2(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writeSide),
            listener)
            .start();

    return readSide;
}

public static ParcelFileDescriptor pipeTo(OutputStream outputStream, IThreadListener listener)
        throws IOException {
    ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
    ParcelFileDescriptor readSide = pipe[0];
    ParcelFileDescriptor writeSide = pipe[1];

    // start the transfer thread
    new TransferThread2(new ParcelFileDescriptor.AutoCloseInputStream(readSide), outputStream,
            listener)
            .start();

    return writeSide;
}

static class TransferThread2 extends Thread {
    final InputStream mIn;
    final OutputStream mOut;
    final IThreadListener mListener;

    TransferThread2(InputStream in, OutputStream out, IThreadListener listener) {
        super("ParcelFileDescriptor Transfer Thread");
        mIn = in;
        mOut = out;
        mListener = listener;
        setDaemon(true);
    }

    @Override
    public void run() {
        byte[] buf = new byte[1024*8];
        int len;

        try {
            while ((len = mIn.read(buf)) > 0) {
                mOut.write(buf, 0, len);
            }
            mOut.flush(); // just to be safe
        } catch (IOException e) {
            Log.e("TransferThread", "writing failed");
            e.printStackTrace();
        } finally {
            try {
                mIn.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                mOut.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mListener != null)
            mListener.onThreadFinished(this);
    }
}

奇怪的是,通常情况下,当您没有 root 权限时会发生这种情况。但是,对于显示 pdf,您当然不需要它。

顺便说一句,这是错误:

12-22 17:37:48.516 9112-9691/com.tproductions.Openit.pro W/System.err: java.io.IOException: write failed: EPIPE (Broken pipe)
12-22 17:37:48.516 9112-9691/com.tproductions.Openit.pro W/System.err:     at libcore.io.IoBridge.write(IoBridge.java:558)
12-22 17:37:48.516 9112-9691/com.tproductions.Openit.pro W/System.err:     at java.io.FileOutputStream.write(FileOutputStream.java:326)
12-22 17:37:48.516 9112-9691/com.tproductions.Openit.pro W/System.err:     at com.tproductions.Openit.libcore.io.IoUtils.copyLarge(IoUtils.java:310)
12-22 17:37:48.516 9112-9691/com.tproductions.Openit.pro W/System.err:     at com.tproductions.Openit.libcore.io.IoUtils.copy(IoUtils.java:283)
12-22 17:37:48.517 9112-9691/com.tproductions.Openit.pro W/System.err:     at com.tproductions.Openit.misc.ParcelFileDescriptorUtil$TransferThread.run(ParcelFileDescriptorUtil.java:70)
12-22 17:37:48.517 9112-9691/com.tproductions.Openit.pro W/System.err: Caused by: android.system.ErrnoException: write failed: EPIPE (Broken pipe)
12-22 17:37:48.517 9112-9691/com.tproductions.Openit.pro W/System.err:     at libcore.io.Linux.writeBytes(Native Method)
12-22 17:37:48.517 9112-9691/com.tproductions.Openit.pro W/System.err:     at libcore.io.Linux.write(Linux.java:286)
12-22 17:37:48.517 9112-9691/com.tproductions.Openit.pro W/System.err:     at libcore.io.BlockGuardOs.write(BlockGuardOs.java:345)
12-22 17:37:48.517 9112-9691/com.tproductions.Openit.pro W/System.err:     at libcore.io.IoBridge.write(IoBridge.java:553)
12-22 17:37:48.517 9112-9691/com.tproductions.Openit.pro W/System.err:  ... 4 more
4

1 回答 1

0

现在问题已经解决了。奇怪的是,导致它的原因是我在应用程序中打开 PDF 文件的方式。我正在传递 new InputStreamDataSource() 但是,然后我关闭了输入流,这导致了异常。奇怪的是,它现在可以工作了

于 2017-12-22T18:26:42.007 回答