我们知道Power Query能够连接很多不同格式的数据源,但同时还有很多是不能直接支持的,比如word文档、压缩包等等。
有这样一种场景:源数据来自于网络或者远程服务器,每天更新,文件格式是zip,压缩包内有csv。
如果不能直接读取zip,那么我们需要每天把zip下载下来,解压后再导入Power Query,非常麻烦,有什么办法可以解决这个问题呢?
方法一:转换二进制数据流
对于电脑来说,任何文件都是二进制的数字,而M语言中提供了大量的binary类函数,所以我们可以利用函数来间接实现不解压直接读取zip压缩包。
代码来源于Mark White,涉及非常复杂的二进制数据流知识,我也看不懂。所以我稍微改了一下,封装成unzip的自定义函数,新建一个名为unzip的空查询,把下面代码复制粘贴到高级编辑器,需要用的时候直接调用自定义函数=unzip("C:\路径.zip")
就行了。
(path) => let Header = BinaryFormat.Record([ MiscHeader = BinaryFormat.Binary(14), BinarySize = BinaryFormat.ByteOrder(BinaryFormat.UnsignedInteger32, ByteOrder.LittleEndian), FileSize = BinaryFormat.ByteOrder(BinaryFormat.UnsignedInteger32, ByteOrder.LittleEndian), FileNameLen= BinaryFormat.ByteOrder(BinaryFormat.UnsignedInteger16, ByteOrder.LittleEndian), ExtrasLen = BinaryFormat.ByteOrder(BinaryFormat.UnsignedInteger16, ByteOrder.LittleEndian) ]), HeaderChoice = BinaryFormat.Choice( BinaryFormat.ByteOrder(BinaryFormat.UnsignedInteger32, ByteOrder.LittleEndian), each if _ <> 67324752 then BinaryFormat.Record([IsValid = false, Filename=null, Content=null]) else BinaryFormat.Choice( BinaryFormat.Binary(26), each BinaryFormat.Record([ IsValid = true, Filename = BinaryFormat.Text(Header(_)[FileNameLen]), Extras = BinaryFormat.Text(Header(_)[ExtrasLen]), Content = BinaryFormat.Transform( BinaryFormat.Binary(Header(_)[BinarySize]), (x) => try Binary.Buffer(Binary.Decompress(x, Compression.Deflate)) otherwise null ) ]), type binary ) ), ZipFormat = BinaryFormat.List(HeaderChoice, each _[IsValid] = true), Entries = List.Transform( List.RemoveLastN( ZipFormat(File.Contents(path)), 1), (e) => [FileName = e[Filename], Content = e[Content] ] ) in Table.FromRecords(Entries)
效果如下图,测试文件中包含了xls,xlsx,csv三个文件,三种格式都可以支持,解析出来还是binary,然后再根据格式使用Excel.Workbook
或Csv.Document
解析成表即可:
不仅是zip,其他的文件如doc,ppt,pdf等,理论上也都可以通过二进制读出来。
方法二:在PBID中使用R语言
可以看到用Power Query的M语言,因为没有直接的函数支持,导致虽然能实现效果,但过程实在太复杂,反正我是看不懂。
而在Python和R中一两行代码就可以搞定,所以只要是R可以,就可以在Power BI Desktop中使用R.Execute
来调用R。
首先得安装R,这个就不多说了。假设在桌面上有个test.zip,压缩包内有个test.csv,我们需要读取csv的数据。源数据长这样:
先来一个不依赖包的写法:
R语言代码:
unzip("C:/Users/rages/Desktop/test.zip") read.csv("test.csv",header=F)
header=F表示不使用第一行作为标题,header=T则相反。
把R语言写到PBID的高级编辑器中就有两个地方需要注意,一个是文本引号的转义,另一个是数据需要以dataframe数据框的形式返回。
let unzip=R.Execute(" unzip(""C:/Users/rages/Desktop/test.zip"") data<-data.frame(read.csv(""test.csv"",header=F)) "){0}[Value] in unzip
在R中还有一个叫rio的包,可以不解压直接读取压缩包,首次使用需要install.packages('rio')
安装rio包。
R语言中代码为:
library(rio) import("c:/Users/rages/Desktop/test.zip")
代码很简洁,第一步加载rio包,第二步直接读取文件路径。
改写到PBID中为:
let unzip=R.Execute(" library(rio) data<-data.frame(import(""C:/Users/rages/Desktop/test.zip"")) "){0}[Value] in unzip
全才,啥语言都会
施总威武
666666
R语言怎么安装、简要使用,老师能给个网址或介绍下吗?
压缩的文件中含中文名,提取后中文名是乱码了,有办法么?
why the file after unzip is empty?
解压缩之后content那一列是空的,是怎么回事呢?
如果一个压缩包中含有多个压缩包,多个压缩包含有csv文件,应该怎么样调用r解压,thanks
请问老师,提取后中文文件名称出现乱码的问题,能解决吗?
解决中文乱码问题,方法如下:
将 Filename = BinaryFormat.Text(Header(_)[FileNameLen]),
替换为 Filename = BinaryFormat.Text(Header(_)[FileNameLen], TextEncoding.Windows),
将 (e) => [FileName = e[Filename], Content = e[Content] ]
替换为 (e) => [FileName = Text.FromBinary(Text.ToBinary(e[Filename], 1252), 936), Content = e[Content] ]
请问老师,rar文档如何免解压通过PowerQuery查询?
为什么我的压缩包都要解压后重新再压缩才能用unzip读出来
压缩包里面就只有一个文件的话,用第一个方法解压是不成功的。多个文件是可以解压的
确实,压缩包里只有一个文件,解压出来的binary是空的,0字节。
求教,是怎么回事啊?
老师你好,通过这个方法,我将DOCX文件作为ZIP格式打开,成功在里面找到文档中的表格。然后解出对应的数据,也就是说,可以解决用Excel直接获取word文件的内表格数据的问题。非常感谢老师的代码。
但是当我换到DOC文件进行这个操作的时候,就发现doc文件的编写并不一样,docx其实就是一个打包文件,里面包含有xml格式的表格。但doc中没有,根据本文中,老师提及,其实DOC文件还是可以以二进制编码的方式解读其中所包含的信息的,只要转码到可读就行。但是我对其中的几个BinaryFormat公式无法理解,不是很懂老师所写的含义,希望老师能补充一个将DOC文件转码到可读的代码,这将为我解决很大的一个难题。