使用 Gmail API 从 Uri 通过电子邮件在 Android 中发送文件时损坏 excel 文件
Corrupted excel file when emailing it in Android from a Uri using the Gmail API
我正在尝试从 Microsoft 的 Excel Android 应用程序共享到我的自定义 Android 应用程序,它将获取共享的 excel 工作簿并通过电子邮件发送通过 Gmail 的 API.
在我的应用程序发送电子邮件并尝试在我的计算机上打开 excel 文件后,出现错误,“我们发现 'May 25.xlsx' 中的某些内容存在问题”。
但是,它确实可以使用 Google 表格在桌面 Chrome 浏览器中打开。
这是工作簿的 URI:content://com.microsoft.office.excel.excelApplication.provider/docsui_temp_share_files/fea009cf-65c3-46f4-8dda-50758298b9fc/May%2025.xlsx
这是将其转换为文件的代码。
Context ctx; //defined by Android
Uri uri; //comes in populated with the value above
String filename; //generated from the Uri in a separate method
InputStream is = ctx.getContentResolver().openInputStream(uri);
File directory = ctx.getCacheDir();
FileOutputStream fos = null;
File fileToReturn = null;
try {
final File tempFile = File.createTempFile(filename.split("\.")[0], "." + filename.split("\.")[1], directory);
tempFile.deleteOnExit();
fos = new FileOutputStream(tempFile);
byte[] bytes = new byte[1024 * 16];
int read = -1;
while ((read = is.read(bytes)) != -1) {
fos.write(bytes);
}
fileToReturn = tempFile;
}
finally {
if (fos != null) {
fos.close();
}
}
这是创建要发送的 MimeMessage 的代码。附件参数具有从上面创建的文件。
private MimeMessage createEmail(List<String> toAddresses,
String from,
String subject,
String bodyText, ArrayList<File> attachments) throws MessagingException {
if(attachments == null){
attachments = new ArrayList<>();
}
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage email = new MimeMessage(session);
InternetAddress fAddress = new InternetAddress(from);
for(String toAddress : toAddresses) {
InternetAddress toInternetAddress = new InternetAddress(toAddress);
email.addRecipient(javax.mail.Message.RecipientType.TO, toInternetAddress );
}
email.setFrom(fAddress);
email.setSubject(subject);
Multipart multipart = new MimeMultipart();
BodyPart textBody = new MimeBodyPart();
textBody.setText(bodyText);
multipart.addBodyPart(textBody);
for (File attachment : attachments){
MimeBodyPart attachmentBody = new MimeBodyPart();
DataSource source = new FileDataSource(attachment.getAbsolutePath());
attachmentBody.setDataHandler(new DataHandler(source));
attachmentBody.setFileName(attachment.getName());
multipart.addBodyPart(attachmentBody);
}
email.setContent(multipart);
return email;
}
以及发送电子邮件的代码。
private String sendMessage(Gmail service,
String userId,
MimeMessage email)
throws MessagingException, IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
email.writeTo(bytes);
ByteArrayContent messageByteArrayContent = new ByteArrayContent("message/rfc822", bytes.toByteArray());
Message message;
message = service.users().messages().send(userId, null, messageByteArrayContent).execute();
}
这是电子邮件的内容。
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="----=_Part_0_262386509.1596398610889"
Date: Sun, 2 Aug 2020 13:03:34 -0700
------=_Part_0_262386509.1596398610889
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
May 252265647717182285060.xlsx
------=_Part_0_262386509.1596398610889
Content-Type: application/octet-stream; name="May 25.xlsx"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="May 25.xlsx"
------=_Part_0_262386509.1596398610889--
请注意 Content-Type 是 application/octect-stream。
我通过手动添加 Content-Type header 实现了 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,但无济于事。
此代码几乎可以发送任何其他内容。如果我先保存 excel 文件并从我的文件管理器应用程序共享它,它就可以正常打开。
而且它似乎特定于 excel 文件。如果我从 Excel 应用程序(这是一个选项)将其共享为 pdf,则 pdf 可以正常打开。
如果我尝试从 Google 表格应用共享并将其作为 .xlsx 文件共享,我也会遇到同样的错误。但同样,如果我尝试将其作为其他任何内容(例如 .csv 或 .pdf)进行共享,它在另一侧可以正常打开。
这是电子邮件,如果它是从 Google 表格应用程序共享的 .pdf 文件。同样,内容类型是 application/octet-stream,但在这里可以正常打开。
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="----=_Part_4_203349844.1596399067869"
Date: Sun, 2 Aug 2020 13:11:10 -0700
------=_Part_4_203349844.1596399067869
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Untitled spreadsheet8410545067288443069.pdf
------=_Part_4_203349844.1596399067869
Content-Type: application/octet-stream; name="Untitled spreadsheet8410545067288443069.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="Untitled spreadsheet8410545067288443069.pdf"
------=_Part_4_203349844.1596399067869--
在编写 xlsx 文件的代码中,您总是读取指定的缓冲区大小 (1024 * 16),然后写入文件。我认为在上次读取时,如果您读取的字节小于字节数组的缓冲区大小,您将写入额外的不必要字节。这可能是您的文件损坏原因。
我正在尝试从 Microsoft 的 Excel Android 应用程序共享到我的自定义 Android 应用程序,它将获取共享的 excel 工作簿并通过电子邮件发送通过 Gmail 的 API.
在我的应用程序发送电子邮件并尝试在我的计算机上打开 excel 文件后,出现错误,“我们发现 'May 25.xlsx' 中的某些内容存在问题”。
但是,它确实可以使用 Google 表格在桌面 Chrome 浏览器中打开。
这是工作簿的 URI:content://com.microsoft.office.excel.excelApplication.provider/docsui_temp_share_files/fea009cf-65c3-46f4-8dda-50758298b9fc/May%2025.xlsx
这是将其转换为文件的代码。
Context ctx; //defined by Android
Uri uri; //comes in populated with the value above
String filename; //generated from the Uri in a separate method
InputStream is = ctx.getContentResolver().openInputStream(uri);
File directory = ctx.getCacheDir();
FileOutputStream fos = null;
File fileToReturn = null;
try {
final File tempFile = File.createTempFile(filename.split("\.")[0], "." + filename.split("\.")[1], directory);
tempFile.deleteOnExit();
fos = new FileOutputStream(tempFile);
byte[] bytes = new byte[1024 * 16];
int read = -1;
while ((read = is.read(bytes)) != -1) {
fos.write(bytes);
}
fileToReturn = tempFile;
}
finally {
if (fos != null) {
fos.close();
}
}
这是创建要发送的 MimeMessage 的代码。附件参数具有从上面创建的文件。
private MimeMessage createEmail(List<String> toAddresses,
String from,
String subject,
String bodyText, ArrayList<File> attachments) throws MessagingException {
if(attachments == null){
attachments = new ArrayList<>();
}
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage email = new MimeMessage(session);
InternetAddress fAddress = new InternetAddress(from);
for(String toAddress : toAddresses) {
InternetAddress toInternetAddress = new InternetAddress(toAddress);
email.addRecipient(javax.mail.Message.RecipientType.TO, toInternetAddress );
}
email.setFrom(fAddress);
email.setSubject(subject);
Multipart multipart = new MimeMultipart();
BodyPart textBody = new MimeBodyPart();
textBody.setText(bodyText);
multipart.addBodyPart(textBody);
for (File attachment : attachments){
MimeBodyPart attachmentBody = new MimeBodyPart();
DataSource source = new FileDataSource(attachment.getAbsolutePath());
attachmentBody.setDataHandler(new DataHandler(source));
attachmentBody.setFileName(attachment.getName());
multipart.addBodyPart(attachmentBody);
}
email.setContent(multipart);
return email;
}
以及发送电子邮件的代码。
private String sendMessage(Gmail service,
String userId,
MimeMessage email)
throws MessagingException, IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
email.writeTo(bytes);
ByteArrayContent messageByteArrayContent = new ByteArrayContent("message/rfc822", bytes.toByteArray());
Message message;
message = service.users().messages().send(userId, null, messageByteArrayContent).execute();
}
这是电子邮件的内容。
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="----=_Part_0_262386509.1596398610889"
Date: Sun, 2 Aug 2020 13:03:34 -0700
------=_Part_0_262386509.1596398610889
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
May 252265647717182285060.xlsx
------=_Part_0_262386509.1596398610889
Content-Type: application/octet-stream; name="May 25.xlsx"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="May 25.xlsx"
------=_Part_0_262386509.1596398610889--
请注意 Content-Type 是 application/octect-stream。
我通过手动添加 Content-Type header 实现了 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,但无济于事。
此代码几乎可以发送任何其他内容。如果我先保存 excel 文件并从我的文件管理器应用程序共享它,它就可以正常打开。
而且它似乎特定于 excel 文件。如果我从 Excel 应用程序(这是一个选项)将其共享为 pdf,则 pdf 可以正常打开。
如果我尝试从 Google 表格应用共享并将其作为 .xlsx 文件共享,我也会遇到同样的错误。但同样,如果我尝试将其作为其他任何内容(例如 .csv 或 .pdf)进行共享,它在另一侧可以正常打开。
这是电子邮件,如果它是从 Google 表格应用程序共享的 .pdf 文件。同样,内容类型是 application/octet-stream,但在这里可以正常打开。
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="----=_Part_4_203349844.1596399067869"
Date: Sun, 2 Aug 2020 13:11:10 -0700
------=_Part_4_203349844.1596399067869
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Untitled spreadsheet8410545067288443069.pdf
------=_Part_4_203349844.1596399067869
Content-Type: application/octet-stream; name="Untitled spreadsheet8410545067288443069.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="Untitled spreadsheet8410545067288443069.pdf"
------=_Part_4_203349844.1596399067869--
在编写 xlsx 文件的代码中,您总是读取指定的缓冲区大小 (1024 * 16),然后写入文件。我认为在上次读取时,如果您读取的字节小于字节数组的缓冲区大小,您将写入额外的不必要字节。这可能是您的文件损坏原因。