2013-03-17 9 views
7

In RCurl ist eine Funktion und eine Klasse CFILE definiert, um mit C-Level-Dateihandles zu arbeiten. Aus dem Handbuch:Erstellen einer Dateihandle auf C-Ebene in RCurl zum Schreiben von heruntergeladenen Dateien

Die Absicht besteht darin, diese an libcurl als Optionen übergeben zu können, damit sie von oder in die Datei lesen oder schreiben können. Wir können dies auch mit R-Verbindungen tun und Callback-Funktionen spezifizieren, die diese Verbindungen manipulieren. Die Verwendung des FILE-Handle auf C-Ebene ist jedoch bei großen Dateien wahrscheinlich wesentlich schneller.

Es gibt keine Beispiele zu Downloads im Zusammenhang also habe ich versucht:

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 = [email protected]) 

Ich habe auch versucht, indem die file Option mit writedata = [email protected] ersetzen. Die Datei wird heruntergeladen, ist jedoch beschädigt. Das Schreiben von benutzerdefiniertem Callback für das Argument write funktioniert nur für nicht binäre Daten.

Gibt es eine Idee, eine Binärdatei in RCurl direkt auf die Festplatte zu laden (ohne sie in den Speicher zu laden)?

Antwort

6

Ich glaube, Sie writedata verwenden wollen, und denken Sie daran, die Datei

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

Für aufwendigere schriftlich zu schließen, ich bin nicht sicher, ob dies der beste Weg ist, aber Linux sagt mir, von

man curl_easy_setopt 

, dass es eine Option curl CURL_WRITEFUNCTION, die ein Zeiger auf eine C-Funktion mit Prototyp ist

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

und in R am Ende von? CurlPerform gibt es ein Beispiel für den Aufruf einer C-Funktion als "writefunction" -Option. Also habe ich eine Datei 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; 
} 

Zusammengestellt es

R CMD SHLIB curl_writer.c 

, die auf Linux eine Datei curl_writer.so produziert und dann in R

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

und erhalten auf stderr

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

Diese beiden Ideen kann integriert werden, das heißt, auf eine beliebige Datei zu schreiben, eine beliebige Funktion, die von der C-Funktion Modifizieren des FILE * zu verwenden, geben wir in, wie

#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; 
} 

und dann in R zurück, nachdem

dyn.load("curl_writer.so") 
writer <- getNativeSymbolInfo("writer", PACKAGE="curl_writer")$address 
f <- CFILE(filename <- tempfile(), "wb") 
curlPerform(URL=url, [email protected], writefunction=writer) 
close(f) 
Kompilieren

getURL kann auch hier verwendet werden, vorausgesetzt, [email protected], write=writer; Ich denke, das Problem in der ursprünglichen Frage ist, dass R_curl_write_binary_data ist wirklich eine interne Funktion, Schreiben in einen Puffer von RCurl, anstatt ein Dateihandle wie das von CFILE erstellt verwaltet.Entsprechend wird writedata ohne write (das aus dem Quellcode zu getURL als Alias ​​für writefunction zu dienen scheint) angegeben, sendet einen Zeiger auf eine Datei an eine Funktion, die einen Zeiger auf etwas anderes erwartet; Für getURL müssen sowohl writedata als auch write angegeben werden.

+0

Danke. Wie ich geschrieben habe, habe ich 'getURL (url = url, writedata = f @ ref)' versucht, was nicht funktioniert. Es scheint also, dass nur eine Teilmenge der Parameter in 'listCurlOptions()' an 'getURL' übergeben werden kann. Einige werden nur von 'curlPerform' akzeptiert. Ich denke nicht, dass dies im Handbuch erwähnt wird. – antonio

+0

@antonio von 'getURL' und dem RCurl-Quellcode, ist das Standardargument' write' für eine benutzerdefinierte Datei nicht geeignet, und R_curl_write_binary_data arbeitet an einer internen Datenstruktur, nicht an einem Datei-Handle; Es reicht, wenn ich sowohl 'write'- als auch' writedata'-Argumente bereitstelle, um getURL zu verwenden. –

+0

Wie Sie gesagt haben, muss man sich den Quellcode anschauen. Einige weitere Hinweise im Handbuch könnten hilfreich sein. – antonio

1

Ich arbeite auch an diesem Problem und habe noch keine Antwort.

Allerdings habe ich diese finden:

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

Stehen Sie arbeiten an R unter Windows? Ich bin.

Diese Dokumentation für die writedata-Funktion zeigt an, dass Sie unter Windows writefunction zusammen mit writedata verwenden müssen.

Hier lesen: http://www.omegahat.org/RCurl/RCurlJSS.pdf Ich habe festgestellt, dass RCurl erwartet, dass die Write-Funktion eine R-Funktion ist, so dass wir das unter Windows selbst implementieren können. Es wird langsamer als mit einer C-Funktion, um die Daten zu schreiben, aber ich wette, dass die Geschwindigkeit der Netzwerkverbindung der Flaschenhals sein wird.

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 

(Dies ist nach einer 1 GB-Datei auf dem Server erstellen Übertragungsgeschwindigkeit zu testen)

Ich habe noch keine Antwort gefunden, die nicht in den Daten auf NUL Bytes nicht ersticken. Es scheint, dass irgendwo im Inneren des RCurl-Pakets, wenn es Daten in R weiterleitet, um die von Ihnen gelieferte Schreibfunktion auszuführen, es versucht, die Daten in eine Zeichenkette umzuwandeln. Dies darf nicht geschehen, wenn Sie eine C-Funktion verwenden. Vor allem mit dem empfohlenen R_curl_write_binary_data Callback zusammen mit CFILE killt rssion.exe auf win32 jedes Mal für mich.

Verwandte Themen