传递pdf文件的输入流时管道损坏
Posted
技术标签:
【中文标题】传递pdf文件的输入流时管道损坏【英文标题】:broken pipe when passing input stream of pdf file 【发布时间】:2018-06-05 07:06:23 【问题描述】:我正在创建一个应用程序,它使用 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
【问题讨论】:
非常感谢,但我使用的是输入流而不是 Uri 和 mime 类型。有什么我想念的吗? 不,它只是一个内部类,只是简单的 while 循环,您可以在我的 Util 类的 thread2 中看到它 【参考方案1】:现在问题解决了。奇怪的是,导致它的原因是我在应用程序中打开 PDF 文件的方式。我正在传递 new InputStreamDataSource() 但是,然后我关闭了输入流,这导致了异常。奇怪的是,它现在可以工作了
【讨论】:
以上是关于传递pdf文件的输入流时管道损坏的主要内容,如果未能解决你的问题,请参考以下文章