Android端PDF转Base64后反向转换失效问题求助
问题描述
我需要将PDF文件上传至服务器,因此要先把PDF文件转换为BASE64字符串。目前转码流程可正常执行,但将得到的BASE64字符串转回PDF时无法生成正确文件,出现如下图所示的报错。
相关代码
文件选择代码
@SuppressLint("NewApi") @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult( requestCode, resultCode, data ); if (requestCode == PDF_REQ_CODE && resultCode == RESULT_OK && data != null && data.getData() != null) { uri = data.getData(); //String path=data.getData().getPath(); btnPdfFileChooser.setText( "PDF is Selected" ); //Toast.makeText(FileUploadActivity.this, uri.toString(), Toast.LENGTH_SHORT).show(); //InputStream inputStream = c.getContentResolver().openInputStream(path) PdfUploadFunction(); } }
上传函数(暂未编写服务端接口调用更新数据的逻辑)
private void PdfUploadFunction() { // Getting pdf name from EditText. PdfNameHolder = strPdfFileName.toString().trim(); // Getting file path using Filepath class. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { PdfPathHolder = FilePath.getPath( this, uri ); } // If file path object is null then showing toast message to move file into internal storage. if (PdfPathHolder == null) { Toast.makeText( this, "Please move your PDF file to internal storage & try again.", Toast.LENGTH_LONG ).show(); } // If file path is not null then PDF uploading file process will starts. else { String base64 = getBase64FromPath( PdfPathHolder ); //String base64 = encodeFileToBase64Binary( PdfPathHolder ); Toast.makeText( this, "base64-" + base64, Toast.LENGTH_LONG ).show(); Log.e( "base64-", base64.toString() ); } }
BASE64转码代码
public static String getBase64FromPath(String path) { byte[] byteArray = null; try { File file = new File( path ); InputStream inputStream = new FileInputStream(file); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] b = new byte[1024 * 11]; int bytesRead = 0; while ((bytesRead = inputStream.read(b)) != -1) { bos.write(b, 0, bytesRead); } byteArray = bos.toByteArray(); Log.e("Byte array", ">" + byteArray); } catch (IOException e) { e.printStackTrace(); } return Base64.encodeToString(byteArray, Base64.NO_WRAP); }
解决方案
核心问题原因
- 不要通过
FilePath.getPath()获取uri对应的文件路径,Android 10及以上版本的分区存储限制下,通过uri拿到的路径很多时候不可访问,或者拿到的是媒体库的虚拟路径,读取到的文件字节流是错误的。 - 转码逻辑没有处理流关闭的问题,小概率会出现字节流读取不完整的情况。
- 部分场景下Base64编码参数不合适,如果服务端解码要求带换行或者使用URL_SAFE模式也会出现解码失败,但最核心的问题还是文件路径读取错误。
修复代码
1. 调整文件读取逻辑,直接通过ContentResolver读取uri对应的输入流,不要转成文件路径
修改PdfUploadFunction方法:
private void PdfUploadFunction() { PdfNameHolder = strPdfFileName.toString().trim(); try { // 直接通过uri获取输入流,不需要转换为本地路径 InputStream inputStream = getContentResolver().openInputStream(uri); String base64 = getBase64FromInputStream(inputStream); Log.e( "base64-", base64 ); Toast.makeText( this, "base64生成成功", Toast.LENGTH_LONG ).show(); } catch (Exception e) { e.printStackTrace(); Toast.makeText( this, "文件读取失败,请检查文件权限", Toast.LENGTH_LONG ).show(); } }
2. 修改Base64转码方法,直接接收输入流处理,同时补全流关闭逻辑
public static String getBase64FromInputStream(InputStream inputStream) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] b = new byte[1024 * 8]; int bytesRead = 0; try { while ((bytesRead = inputStream.read(b)) != -1) { bos.write(b, 0, bytesRead); } byte[] byteArray = bos.toByteArray(); return Base64.encodeToString(byteArray, Base64.NO_WRAP); } catch (IOException e) { e.printStackTrace(); return null; } finally { // 关闭所有流避免资源泄漏 try { inputStream.close(); bos.close(); } catch (IOException e) { e.printStackTrace(); } } }
验证方法
生成base64字符串后,可以先在本地做解码验证:将得到的base64字符串解码为字节数组,写入本地存储为新的PDF文件,如果新文件可以正常打开,再调用服务端接口上传。
如果服务端解码仍然失败,确认服务端的解码规则是否和Android端编码规则一致:是否需要Base64.URL_SAFE参数、是否要求去掉base64前缀(如data:application/pdf;base64,)。
内容的提问来源于stack exchange,提问作者Pranav MS
相关产品推荐
相关产品推荐

