パスワードがかかっているzipファイル(群)の扱い

csvファイルをパスワード付きで圧縮されたzipファイル群があります。
この時、例えばpythonだと、zipfileモジュールを使って
zipファイルから直接(=展開したファイルを実体化させずに)
圧縮されているcsvファイルの内容を取り扱うことができます。

イメージで言うと、

(files にはファイル名のリストが入っているとして)

for file_name in files:
with zipfile.ZipFile(input_path+file_name,‘r’) as target_zip:

上記でtarget_zipにzipfileオブジェクトで放り込むことにより、
そこから直接readする(このときに展開パスワードも設定)ことができるのですが、
同じようなことをRスクリプトで行うことは可能でしょうか?

unzipを使ってみたのですが以下の点で課題を感じています。

  1. パスワードが掛かっているファイルが展開できない

  2. read_csv等で取り出す前に、unzipにより必ずファイルが実体化されてしまう
    (わりとサイズの大きいファイル群なので、できれば展開させたくないのです)

「いいね!」 1

@Yasuhiro_Yatsuu さん

最近バタバタしていて、回答が遅くなりました!
かつExplratoryで試していないのですが下記のように読み込みの際にカスタムスクリプトを作ればいけそうです。

iris.csv.zipというパスワード付きzipファイルがあり、この中にはiris.csvというcsvがあります。
パスワードはpassだとします。

$cd ~/Desktop/zipped_data
$ls
iris.csv.zip

Hmiscパッケージをインストールしてもらい、そのパッケージの関数であるHmisc::getZip()readr::read_csv()と併用するのはいかがでしょうか。パスワードを直接書き残すのはあまりよろしくないと思いますので、そのあたりは会社のセキュリティまわりと相談して、何らかの方法でパスワードを渡してください。

df <- readr::read_csv(Hmisc::getZip(url = "/Users/aki/Desktop/zipped_data/iris.csv.zip", password = "pass"))

head(df)
# A tibble: 6 x 5
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
         <dbl>       <dbl>        <dbl>       <dbl> <chr>  
1          5.1         3.5          1.4         0.2 setosa 
2          4.9         3            1.4         0.2 setosa 
3          4.7         3.2          1.3         0.2 setosa 
4          4.6         3.1          1.5         0.2 setosa 
5          5           3.6          1.4         0.2 setosa 
6          5.4         3.9          1.7         0.4 setosa 

tail(df)
# A tibble: 6 x 5
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species  
         <dbl>       <dbl>        <dbl>       <dbl> <chr>    
1          6.7         3.3          5.7         2.5 virginica
2          6.7         3            5.2         2.3 virginica
3          6.3         2.5          5           1.9 virginica
4          6.5         3            5.2         2   virginica
5          6.2         3.4          5.4         2.3 virginica
6          5.9         3            5.1         1.8 virginica

データ読み込み後もcsvは実体化されていません。

$ls
iris.csv.zip

複数パスワード付きcsvファイルがzipされているのであれば、for-loopまたはpurrrパッケージのmap系の関数を使い、今までに質問していただいた回答を組み合わせれば複数読み込み、ユニオンですた状態で取り込めると思います。

詳細はわかりかねますが、実体化させたくないくらい大きいファイルならばDBで管理したほうが良いような気がします…

よろしくおねがいします!

##################
/# 追記
##################
Explratoryで試したところ、問題なく読み込めました!

15

他にもっと良い方法があるかもしれませんが、これしか思いつきませんでした〜!

「いいね!」 2

なんと、そういうライブラリがあるのですね!
早速・・・と試してみましたが、残念ながらうまくいきません。

事象としては、スクリプト側を

df <- readr::read_csv(Hmisc::getZip(url = “/Users/Username/Desktop/zipped_data/a2.zip”, password = “1234”))

として実行をかけると、

Error :
Cannot read file C:/Users/Username/.exploratory/tmp/(Tempフォルダの中のファイル名) ファイルを格納しているボリュームが外部的に変更されたため、開かれているファイルが無効になりました。

とのエラーで完了しません。
エラー原因を調べてみていますが、どうもこれはWindows10側で吐いているような印象を持っています。

unzipでだめだったときにsystemも考えたのですが、やはりこれもOS側起因(windowsはコマンドプロンプト、Powershellのいずれでもパスワード付きzipを展開できる方法を探し当てられなかった)で諦めた経緯があり、OSでダメということだとちょっと厳しいかな。。。という気もしています。

Rでこのようなエラーが存在するか、もしご存知でしたらご教示いただけるとたいへん助かります。

@Yasuhiro_Yatsuu さま

windows環境で検証してみたところ・・・おおまなエラーの原因は下記2点が考えられそうです。

  • Hmisc::getZip()の挙動の観点
  • ②Exploratoryのtempフォルダへの変更

Hmisc::getZip()の挙動の観点

この関数の実装を調べたところ、内部でunzipコマンドを生成し、コマンドラインに渡しているようです。そのため、windowsではunzipコマンドが利用できないので、エラーが発生する模様です。

なので、下記のサイトからコマンドプロンプトでunzipが利用できるように、Binariesをダウンロードして、環境変数を設定することで、コマンドプロンプトでunzipコマンドを利用できるようにしました。

その結果、Windows環境のRStudioで、Hmisc::getZip()を利用しても関数がエラーを返さなくなりました。画像のとおりです。

zip

②Exploratoryのtempフォルダへの変更

そのため、これで行けるかと思い、Exploratoryで同じスクリプトを試したところ、同じエラーがでました。

Error :
Cannot read file C:/Users/username/.exploratory/tmp/(Tempフォルダの中のファイル名) ファイルを格納しているボリュームが外部的に変更されたため、開かれているファイルが無効になりました。

なので、Windowsというよりは、おそらくExploratoryの何らかの設定の関係で、tmpフォルダを関数が利用できず、エラーを返していると思われます。修正方法はわかりません…。

なので、Exploratory上で今回ようにデータを展開したいのであれば、Hmisc::getZip()と似たような関数を自分で書くか(詳しく調べてないので、できる出来ないは不明)、問い合わせるかのいずれかになるかと思います!

よろしくおねがいします!

「いいね!」 1

詳しくお調べいただいてたいへん恐縮です。
本当にありがとうございます。

何が書いてあるかはなんとなくわかるのですが、
なぜそうなるかは半分ぐらい理解できません(笑)

ひとつひとつ試してみました。

Rstudioで動かせるということなので、Exploratoryを入れたときに
一緒に入るR x64 3.6.1でやってみます。

df <- readr::read_csv(Hmisc::getZip(url = “/Users/Username/Downloads/ziptest/a2.zip”, password = “1234”))

guess_header_(datasource, tokenizer, locale) でエラー:
Cannot read file C:/Users/Username/AppData/Local/Temp/RtmpUR3fJx/file49c3a8c30fb: ファイルを格納しているボリュームが外部的に変更されたため、開かれているファイルが無効になりました。

・・・ああそうか、unzip for windows入れてPATH通さないといけないんだよね、ではもう一回。

df <- readr::read_csv(Hmisc::getZip(url = “/Users/Username/Downloads/ziptest/a2.zip”, password = “1234”))

guess_header_(datasource, tokenizer, locale) でエラー:
Cannot read file C:/Users/Username/AppData/Local/Temp/RtmpUR3fJx/file49c3a8c30fb: ファイルを格納しているボリュームが外部的に変更されたため、開かれているファイルが無効になりました。

・・・おや?(^^;
どういうことだろうとコマンドプロンプトで実行してみます。

C:\Users\Username\Downloads\ziptest>unzip -P 1234 a2.zip

Archive: a2.zip
skipping: a2.csv need PK compat. v5.1 (can do v2.1)

マヂか・・・ZIPのバージョンで引っかかったのなんて初めてだな、この結果がR上だとそういうエラーになるのね。。。
つかunzip for windowsはLastChangeが14 February 2005か、5.1まで持ってくるのは難しそうだな・・・
じゃあzipもGNUの使ってみるか、ということでZip for Windowsを入れて
そちらで圧縮したファイルで再チャレンジ。

C:\Users\Username\Downloads\ziptest>unzip -P 1234 a21.zip

Archive: a21.zip
inflating: a2.csv

というわけでコマンドプロンプト上ではunzipでパスワードを展開できる状態であることを確認し、
Rで再度挑戦。

df <- readr::read_csv(Hmisc::getZip(url = “/Users/Username/Downloads/ziptest/a21.zip”, password = “1234”))

Parsed with column specification:
cols(
column1 = col_character(),
column2 = col_double()
)

df

A tibble: 2 x 2

column1 column2

1 C 3
2 D 4

おお、いけた、ということで①はクリア。

で、次に②Exploratory上で試してみます。

Error :
Cannot read file C:/Users/Username/.exploratory/tmp/Rtmp02LBRI/file1b45d2e3e5a: ファイルを格納しているボリュームが外部的に変更されたため、開かれているファイルが無効になりました。

うむむ、やはり同じエラーですね。

ところで、環境変数については、以前オンラインセミナーで質問したことがあり、

という回答を受けています。
このときはノートで使えるか、と聞いていますが、
Exploratoryの仕組み的にRスクリプトで使うのも変わらないのではないかと思っていて、
そちらを試してみました。

まずRで

setwd (“C:/Users/Username/Downloads/ziptest”)
df <- read.table(text=system(paste0("unzip -P “, 1234, " a21.zip “, “a2.csv”),intern = TRUE),stringsAsFactors=FALSE,header=TRUE,sep=”,”)
df

                 Archive...a21.zip

1 inflating: a2.csv

system関数で渡したunzipは、PATHが通っているので動いています。
※ちょっとへんなもの作ってますが動くかどうかだけなので気にしない。

Exploratoryで同じことをやってみます。

Error : ‘unzip’ not found

unzip自体が見つけられないようです。
というわけでExploratoryは環境変数PATHを見てない、ということがわかります。

・・・ところで、そうなるとムクムクと湧いてくる疑問は、
PATHを見てなくてみつけられない、というのなら、
setwdのフォルダの中にunzipがおいてあったらどうなるんだろう、ということです。
unzip for windowsのbinの中のファイルをsetwdで設定したフォルダの中において試してみます。
%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%202020-04-14%20120250

動くんかーい!!!
というわけで動かせないことはない、ということはわかりました。
ただこれを実践するか、というとあまりにもクセが強すぎて微妙なところです(^^;

@Yasuhiro_Yatsuu さん
手順をおって原因の切り分けありがとうございます!

なるほどです…動かせないことはないですが、クセがありますね、たしかに。笑

実体化させたくないくらい大きいデータなのであれば、データベースで扱うように運用をかえるのが手っ取り早いかもしれないですね!