I think you want to use writedata
and remember to close the file
library(RCurl)
filename <- tempfile()
f <- CFILE(filename, "wb")
url <- "http://cran.fhcrc.org/Rlogo.jpg"
curlPerform(url = url, writedata = f@ref)
close(f)
For more elaborate writing, I'm not sure if this is the best way, but Linux tells me, from
man curl_easy_setopt
that there's a curl option CURL_WRITEFUNCTION that is a pointer to a C function with prototype
size_t function(void *ptr, size_t size, size_t nmemb, void *stream);
and in R at the end of ?curlPerform there's an example of calling a C function as the 'writefunction' option. So I created a file 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;
}
Compiled it
R CMD SHLIB curl_writer.c
which on Linux produces a file curl_writer.so, and then in R
dyn.load("curl_writer.so")
writer <- getNativeSymbolInfo("writer", PACKAGE="curl_writer")$address
curlPerform(URL=url, writefunction=writer)
and get on stderr
<writer> size = 1, nmemb = 2653
<writer> size = 1, nmemb = 520
OK
These two ideas can be integrated, i.e., writing to an arbitrary file using an arbitrary function, by modifying the C function to use the FILE * we pass in, as
#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;
}
and then back in R after compiling
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
can be used here, too, provided writedata=f@ref, write=writer
; I think the problem in the original question is that R_curl_write_binary_data
is really an internal function, writing to a buffer managed by RCurl, rather than a file handle like that created by CFILE
. Likewise, specifying writedata
without write
(which seems from the source code to getURL to be an alias for writefunction) sends a pointer to a file to a function expecting a pointer to something else; for getURL both writedata and write need to be provided.