どのように動作しているのか知らずとも多くの機会で利用する Power Query の関数。それが File.Contents。でも、想像より複雑にかつ合理的な動作をしているはずなのである。
Power Query でファイル( binary )を読み込むときの動作には、
- 可能な限り少ない読み込みで完了すること
- ソースデータのファイルフォーマットごとで適した動作をしていること
という特徴があって、
Csv.Document(
File.Contents( ... )
)
のような利用であるけれども、File.Contents でファイルを取得し Csv.Document で解釈するという理解では Power Query の特徴を表しきれない。File.Contents で binary 読込完了 → 次の処理(ステップなど) ということではなく、次以降の処理を勘案し File.Contents での binary 読込 がコントロールされるのだ。
ウォームアップ
構文と例
File.Contents(
path as text,
optional options as nullable record
) as binary
Returns the contents of the file, path, as binary. The options parameter is currently intended for internal use only.
path 引数は絶対パスを表現する文字列でファイルシステムよりファイル (binary) を取得する動作をする。単独で利用することは少ない。
鍛錬
フラットファイル データソース がわかりやすい
改行文字を区切りとして テーブル でいうところの行として読み込むとき、可能な限り必要な部分を読み込む動作を観察。
テキストファイルや CSV ファイルなどは、4096 byte ごとで読み込むことがわかっているから、改行文字含め 4096 byte を 1 セット(1 行) 10 セット(10 行)の ソールファイル を読み込む経過を観察。
テーブルとして読み込み、行ごとの処理( Table.AddColumn ) を意図的に遅らせ( Function.InvokeAfter )、その時の時刻( DateTime.LocalNow )を記録。このとき、Process Monitor で ReadFile を記録。
let
Source = File.Contents(SourceFile),
BinaryToLines = Lines.FromBinary(Source),
ListToTable = Table.FromColumns({BinaryToLines}),
AddedColumn2 = Table.AddColumn(
ListToTable,
"Column2",
each Function.InvokeAfter(
()=>DateTime.ToText(
{[Column1], DateTime.LocalNow()}{1},
"hh:mm:ss.fffffff tt"
),
#duration(0,0,0,1)
),
Text.Type
),
SelectColumn2 = Table.SelectColumns(
AddedColumn2,
{"Column2"}
)
in
SelectColumn2
意図的に遅延させた行ごとの処理( Table.AddColumn ) に一致するように ReadFile が行われる。
// Query1
let
Source = SourceQuery,
First5Rows = Table.FirstN(Source,5)
in
First5Rows
このクエリ(SourceQuery)の先頭 5 行だけ読み込む( Table.FirstN ) とすれば、ReadFile は 5件で済む。
// Query2
let
Source = SourceQuery,
Last5Rows = Table.LastN(Source, 5)
in
Last5Rows
最後 5 行だけ読み込む( Table.LastN ) とすると、ReadFile は 10 件。ただし、遅延させた行ごとの処理( Table.AddColumn ) 5 行分は ReadFile 10 件 すべて完了してからになる。
// Query3
let
Source = SourceQuery,
Skip5Rows = Table.Skip(Source,5)
in
Skip5Rows
先頭 5 行をスキップ( Table.Skip ) したとき、先頭 5 行分では 遅延させた行ごとの処理( Table.AddColumn ) は発生しない。スキップ完了以降の処理については、遅延させた行ごとの処理( Table.AddColumn ) 通りに ReadFile が発生する。
その他