我正在创建一个应用程序,它使用 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