Swift解压缩zip文件并从Gmail API的base64数据中找到xml文件

Posted

技术标签:

【中文标题】Swift解压缩zip文件并从Gmail API的base64数据中找到xml文件【英文标题】:Swift Unzipping zip file and find xml file from base64 data from Gmail API 【发布时间】:2020-09-10 02:05:33 【问题描述】:

这个问题是关于 ios 13 中使用 SwiftUI 和 Gmail API 的 DMARC 报告查看器应用程序。报告通过 google 以 xml 格式邮寄到我们的管理员电子邮件 ID,该格式将被压缩。所以基本上它是一个拉链附件。所以在这里,GMail API 用于使用过滤器访问那些特定的邮件,并从 API 获取所有 base64 编码的数据。还将其解码为数据类型数据。这么远还可以。下一部分是将字节格式的zip文件的数据解压缩并以String类型提取其中的xml文件。然后我需要解析 XML。我想我可以弄清楚用 XMLParser 进行解析。

问题:如何解压Data类型的zip文件并从中获取String类型的xml文件?

INPUT: String in Base64 format from GMail API fetch (A zip file attachment with only 1 xml file inside)
OUTPUT: String in XML format
PLATFORM: iOS 13/Swift 5.2/SwiftUI/Xcode 11.4
ACTION: 

(INPUT)
base64: String | Decode -> Data
attachment.zip: Data | Decompress -> [Data]
ListOfFiles: [Data] | FirstIndex -> Data
dmarc.xml: Data | ContentOfXML -> String
(OUTPUT)

更新:我尝试了一个名为 Zip 的外部包,但它也失败了。

let path = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let url = path.appendingPathComponent(messageId+".zip")
do 
    try data.write(to: url)
 catch 
    print("Error while writing: "+error.localizedDescription)

do 
    let unzipDirectory = try Zip.quickUnzipFile(url)
    print(unzipDirectory)
 catch let error as NSError 
    print("Error while unzipping: "+error.localizedDescription)

此代码导致以下错误

Error while unzipping: The operation couldn’t be completed. (Zip.ZipError error 1.)

【问题讨论】:

1) 您是否验证了来自 Gmail 的 base 64 编码内容是否有效?可以手动解码吗? 2) 您是否验证了解码后的 base 64 数据确实是 ZIP 文件?例如,您是否尝试从 iPhone 模拟器获取此文件并将其解压缩到您的 Mac 上? 3) 还有其他软件包允许您仅提取文件 - 例如 ZIPFoundation。 我有点想通了核心问题。 w3.org/Protocols/rfc1341/5_Content-Transfer-Encoding.html 这是 google 用于附件编码的内容。这在大多数解码器中都不是标准的。因此它看起来像坏了。 ***.com/a/58590759/2382813 我觉得需要想办法把base64从7bit格式转成8bit格式再解压。 【参考方案1】:

终于找到了。正如Ref 1 中提到的,电子邮件正文以 7 位 US-ASCII 数据编码。所以这就是为什么base64解码不起作用的原因。

如rfc1341中所定义:

7BIT 的编码类型要求正文已经在 七位邮件就绪表示。这是默认值 - 也就是说,如果 Content-Transfer-Encoding 头域不存在。

添加以下内容后,整个代码都可以工作了。

let edata: String = result.data.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")

正如Ref 2 中提到的,它只需要在从 gmail api 接收的 base64 数据中将“-”替换为“+”和“_”替换为“/”。

func getAttachedData(messageId: String, attachmentId: String) 
    decode(self.urlBase+messageId+"/attachments/"+attachmentId+"?"+self.urlKey)  (result: Attachment) in
        let edata: String = result.data.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")
        if let data = Data(base64Encoded: edata, options: .ignoreUnknownCharacters) 
            let filemanager = FileManager.default
            let path = try! filemanager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
            let url = path.appendingPathComponent(messageId+".zip")
            do 
                try data.write(to: url)
             catch 
                print("Error while writing: "+error.localizedDescription)
            
            do 
                let unzipDirectory = try Zip.quickUnzipFile(url)
                print("Unzipped")
                do 
                    let filelist = try filemanager.contentsOfDirectory(at: unzipDirectory, includingPropertiesForKeys: [], options: [])

                    for filename in filelist 
                        print(filename.lastPathComponent)
                        print(filename.relativeString)
                        do 
                            let text = try String(contentsOf: filename, encoding: .utf8)
                            print(text)
                            DispatchQueue.main.async 
                                self.attachments.append(text)
                            
                         catch let error as NSError 
                            print("Error: \(error.localizedDescription)")
                        
                    
                 catch let error 
                    print("Error: \(error.localizedDescription)")
                
             catch let error as NSError 
                print("Error while unzipping: "+error.localizedDescription)
            
        
    

参考 1:https://***.com/a/58590759/2382813

参考 2:https://***.com/a/24986452/2382813

【讨论】:

以上是关于Swift解压缩zip文件并从Gmail API的base64数据中找到xml文件的主要内容,如果未能解决你的问题,请参考以下文章

解压缩来自服务器的 zip 文件,而不在 ios swift 中本地保存,类似于 android 的操作?

Swift 压缩和解压文件的框架 Zip

使用 Minizip API 从 Zip 存档中删除 Zip 条目

configparser 从 zip 加载配置文件

centos 怎么解压缩zip

zip---解压缩文件