8

RCurl では、CFILEC レベルのファイル ハンドルを操作する関数とクラスが定義されています。マニュアルから:

その目的は、これらを libcurl にオプションとして渡して、ファイルから読み書きできるようにすることです。これは R 接続でも実行でき、これらの接続を操作するコールバック関数を指定できます。ただし、C レベルの FILE ハンドルを使用すると、大きなファイルの場合は大幅に高速になる可能性があります。

ダウンロードに関連する例がないので、試しました:

library(RCurl)
u = "http://cran.r-project.org/web/packages/RCurl/RCurl.pdf"
f = CFILE("RCurl.pdf", mode="wb")
ret= getURL(u,  write = getNativeSymbolInfo("R_curl_write_binary_data")$address,
                file  = f@ref)

fileオプションをに置き換えてみましたwritedata = f@ref。ファイルはダウンロードされましたが、破損しています。引数のカスタム コールバックの記述は、write非バイナリ データに対してのみ機能します。

RCurl で (メモリにロードせずに) バイナリ ファイルをディスクに直接ダウンロードする方法はありますか?

4

2 に答える 2

7

私はあなたが使いたいと思いwritedata、ファイルを閉じることを忘れないでください

library(RCurl)
filename <- tempfile()
f <- CFILE(filename, "wb")
url <- "http://cran.fhcrc.org/Rlogo.jpg"
curlPerform(url = url, writedata = f@ref)
close(f)

より精巧な記述については、これが最善の方法かどうかはわかりませんが、Linux は次のように教えてくれます。

man curl_easy_setopt

プロトタイプを持つ C 関数へのポインターである curl オプション CURL_WRITEFUNCTION があること

size_t function(void *ptr, size_t  size, size_t nmemb, void *stream);

また、R では ?curlPerform の最後に「writefunction」オプションとして C 関数を呼び出す例があります。だから私はファイルcurl_writer.cを作成しました

#include <stdio.h>

size_t
writer(void *buffer, size_t size, size_t nmemb, void *stream)
{
    fprintf(stderr, "<writer> size = %d, nmemb = %d\n",
            (int) size, (int) nmemb);
    return size * nmemb;
}

コンパイルしました

R CMD SHLIB curl_writer.c

Linux ではファイル curl_writer.so を生成し、次に R で生成します

dyn.load("curl_writer.so")
writer <- getNativeSymbolInfo("writer", PACKAGE="curl_writer")$address
curlPerform(URL=url, writefunction=writer)

stderrに乗る

<writer> size = 1, nmemb = 2653
<writer> size = 1, nmemb = 520
OK 

これら 2 つのアイデアは統合できます。つまり、C 関数を変更して、渡した FILE * を使用することにより、任意の関数を使用して任意のファイルに書き込むことができます。

#include <stdio.h>

size_t
writer(void *buffer, size_t size, size_t nmemb, void *stream)
{
    FILE *fout = (FILE *) stream;
    fprintf(fout, "<writer> size = %d, nmemb = %d\n",
            (int) size, (int) nmemb);
    fflush(fout);
    return size * nmemb;
}

コンパイル後にRに戻ります

dyn.load("curl_writer.so")
writer <- getNativeSymbolInfo("writer", PACKAGE="curl_writer")$address
f <- CFILE(filename <- tempfile(), "wb")
curlPerform(URL=url, writedata=f@ref, writefunction=writer)
close(f)

getURLここでも使用できますwritedata=f@ref, write=writer。元の質問の問題は、R_curl_write_binary_data実際には内部関数であり、RCurl によって作成されたようなファイル ハンドルではなく、RCurl によって管理されるバッファに書き込むことだと思いますCFILE。同様に、writedatawithoutを指定するとwrite(ソース コードから getURL への書き込み関数のエイリアスのように見えます)、ファイルへのポインターが別の何かへのポインターを期待する関数に送信されます。getURL には、writedata と write の両方を指定する必要があります。

于 2013-03-17T16:43:13.330 に答える
1

私もこの問題に取り組んでいますが、まだ答えがありません。

しかし、私はこれを見つけました:

http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTWRITEDATA

Windows で R を使用していますか? 私は。

writedata 関数に関するこのドキュメントでは、Windows ではwritedata と共に writefunction を使用する必要があることを示しています。

ここを読んでください: http://www.omegahat.org/RCurl/RCurlJSS.pdf RCurl は writefunction が R 関数であることを期待しているので、Windows に自分で実装できることがわかりました。C 関数を使用してデータを書き込むよりも遅くなりますが、ネットワーク リンクの速度がボトルネックになると思います。

getURI(url="sftp://hostname/home/me/onegeebee", curl=con, write=function(x) writeChar(x, f, eos=NULL))
Error in curlPerform(curl = curl, .opts = opts, .encoding = .encoding) : embedded nul in string: ' <`á\017_\021

(これは転送速度をテストするためにサーバー上に1GBのファイルを作成した後です)

データ内の NUL バイトを詰まらせない答えはまだ見つかりません。RCurl パッケージの内部のどこかで、データを R に渡して、指定した writefunction を実行するときに、データを文字列に変換しようとしているようです。C 関数を使用する場合は、これを行ってはなりません。特に、推奨される R_curl_write_binary_data コールバックを CFILE とともに使用すると、毎回 win32 で rsession.exe が強制終了されます。

于 2013-05-30T20:07:53.543 に答える