2014-10-30 71 views

回答

5

没有,但你可以使用libcurl,一个例子:

#include <stdio.h> 
#include <curl/curl.h> 

/* 
* This is an example showing how to get a single file from an FTP server. 
* It delays the actual destination file creation until the first write 
* callback so that it won't create an empty file in case the remote file 
* doesn't exist or something else fails. 
*/ 

struct FtpFile { 
    const char *filename; 
    FILE *stream; 
}; 

static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream) 
{ 
    struct FtpFile *out=(struct FtpFile *)stream; 
    if(out && !out->stream) { 
    /* open file for writing */ 
    out->stream=fopen(out->filename, "wb"); 
    if(!out->stream) 
     return -1; /* failure, can't open file to write */ 
    } 
    return fwrite(buffer, size, nmemb, out->stream); 
} 


int main(void) 
{ 
    CURL *curl; 
    CURLcode res; 
    struct FtpFile ftpfile={ 
    "curl.tar.gz", /* name to store the file as if succesful */ 
    NULL 
    }; 

    curl_global_init(CURL_GLOBAL_DEFAULT); 

    curl = curl_easy_init(); 
    if(curl) { 
    /* 
    * You better replace the URL with one that works! 
    */ 
    curl_easy_setopt(curl, CURLOPT_URL, 
        "ftp://ftp.example.com/pub/www/utilities/curl/curl-7.9.2.tar.gz"); 
    /* Define our callback to get called when there's data to be written */ 
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); 
    /* Set a pointer to our struct to pass to the callback */ 
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile); 

    /* Switch on full protocol/debug output */ 
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 

    res = curl_easy_perform(curl); 

    /* always cleanup */ 
    curl_easy_cleanup(curl); 

    if(CURLE_OK != res) { 
     /* we failed */ 
     fprintf(stderr, "curl told us %d\n", res); 
    } 
    } 

    if(ftpfile.stream) 
    fclose(ftpfile.stream); /* close the local file */ 

    curl_global_cleanup(); 

    return 0; 
} 

或(如@保罗指出的),你可以管一个过程(如:wget url)与popen

#include <stdio.h> 

FILE *popen(const char *command, const char *mode); 
int pclose(FILE *stream); 

int main(void) 
{ 
    /* wget -q = silent mode */ 
    FILE *cmd = popen("wget -q -O - ftp://debian.org/debian-security/README.security", "r"); 
    char result[1024]; 

    while (fgets(result, sizeof(result), cmd) != NULL) 
     printf("%s", result); 
    pclose(cmd); 
    return 0; 
} 
1

这不像使用fopen那样简单,但可以完成。

您需要使用libcurl。看看here

从网站:

/***************************************************************************** 
* 
* This example requires libcurl 7.9.7 or later. 
*/ 

#include <stdio.h> 
#include <string.h> 
#ifndef WIN32 
#include <sys/time.h> 
#endif 
#include <stdlib.h> 
#include <errno.h> 

#include <curl/curl.h> 

enum fcurl_type_e { 
    CFTYPE_NONE=0, 
    CFTYPE_FILE=1, 
    CFTYPE_CURL=2 
}; 

struct fcurl_data 
{ 
    enum fcurl_type_e type;  /* type of handle */ 
    union { 
    CURL *curl; 
    FILE *file; 
    } handle;     /* handle */ 

    char *buffer;    /* buffer to store cached data*/ 
    size_t buffer_len;   /* currently allocated buffers length */ 
    size_t buffer_pos;   /* end of data in buffer*/ 
    int still_running;   /* Is background url fetch still in progress */ 
}; 

typedef struct fcurl_data URL_FILE; 

/* exported functions */ 
URL_FILE *url_fopen(const char *url,const char *operation); 
int url_fclose(URL_FILE *file); 
int url_feof(URL_FILE *file); 
size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file); 
char * url_fgets(char *ptr, size_t size, URL_FILE *file); 
void url_rewind(URL_FILE *file); 

/* we use a global one for convenience */ 
CURLM *multi_handle; 

/* curl calls this routine to get more data */ 
static size_t write_callback(char *buffer, 
          size_t size, 
          size_t nitems, 
          void *userp) 
{ 
    char *newbuff; 
    size_t rembuff; 

    URL_FILE *url = (URL_FILE *)userp; 
    size *= nitems; 

    rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */ 

    if(size > rembuff) { 
    /* not enough space in buffer */ 
    newbuff=realloc(url->buffer,url->buffer_len + (size - rembuff)); 
    if(newbuff==NULL) { 
     fprintf(stderr,"callback buffer grow failed\n"); 
     size=rembuff; 
    } 
    else { 
     /* realloc suceeded increase buffer size*/ 
     url->buffer_len+=size - rembuff; 
     url->buffer=newbuff; 
    } 
    } 

    memcpy(&url->buffer[url->buffer_pos], buffer, size); 
    url->buffer_pos += size; 

    return size; 
} 

/* use to attempt to fill the read buffer up to requested number of bytes */ 
static int fill_buffer(URL_FILE *file, size_t want) 
{ 
    fd_set fdread; 
    fd_set fdwrite; 
    fd_set fdexcep; 
    struct timeval timeout; 
    int rc; 

    /* only attempt to fill buffer if transactions still running and buffer 
    * doesnt exceed required size already 
    */ 
    if((!file->still_running) || (file->buffer_pos > want)) 
    return 0; 

    /* attempt to fill buffer */ 
    do { 
    int maxfd = -1; 
    long curl_timeo = -1; 

    FD_ZERO(&fdread); 
    FD_ZERO(&fdwrite); 
    FD_ZERO(&fdexcep); 

    /* set a suitable timeout to fail on */ 
    timeout.tv_sec = 60; /* 1 minute */ 
    timeout.tv_usec = 0; 

    curl_multi_timeout(multi_handle, &curl_timeo); 
    if(curl_timeo >= 0) { 
     timeout.tv_sec = curl_timeo/1000; 
     if(timeout.tv_sec > 1) 
     timeout.tv_sec = 1; 
     else 
     timeout.tv_usec = (curl_timeo % 1000) * 1000; 
    } 

    /* get file descriptors from the transfers */ 
    curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); 

    /* In a real-world program you OF COURSE check the return code of the 
     function calls. On success, the value of maxfd is guaranteed to be 
     greater or equal than -1. We call select(maxfd + 1, ...), specially 
     in case of (maxfd == -1), we call select(0, ...), which is basically 
     equal to sleep. */ 

    rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); 

    switch(rc) { 
    case -1: 
     /* select error */ 
     break; 

    case 0: 
    default: 
     /* timeout or readable/writable sockets */ 
     curl_multi_perform(multi_handle, &file->still_running); 
     break; 
    } 
    } while(file->still_running && (file->buffer_pos < want)); 
    return 1; 
} 

/* use to remove want bytes from the front of a files buffer */ 
static int use_buffer(URL_FILE *file,int want) 
{ 
    /* sort out buffer */ 
    if((file->buffer_pos - want) <=0) { 
    /* ditch buffer - write will recreate */ 
    if(file->buffer) 
     free(file->buffer); 

    file->buffer=NULL; 
    file->buffer_pos=0; 
    file->buffer_len=0; 
    } 
    else { 
    /* move rest down make it available for later */ 
    memmove(file->buffer, 
      &file->buffer[want], 
      (file->buffer_pos - want)); 

    file->buffer_pos -= want; 
    } 
    return 0; 
} 

URL_FILE *url_fopen(const char *url,const char *operation) 
{ 
    /* this code could check for URLs or types in the 'url' and 
    basicly use the real fopen() for standard files */ 

    URL_FILE *file; 
    (void)operation; 

    file = malloc(sizeof(URL_FILE)); 
    if(!file) 
    return NULL; 

    memset(file, 0, sizeof(URL_FILE)); 

    if((file->handle.file=fopen(url,operation))) 
    file->type = CFTYPE_FILE; /* marked as URL */ 

    else { 
    file->type = CFTYPE_CURL; /* marked as URL */ 
    file->handle.curl = curl_easy_init(); 

    curl_easy_setopt(file->handle.curl, CURLOPT_URL, url); 
    curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file); 
    curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L); 
    curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback); 

    if(!multi_handle) 
     multi_handle = curl_multi_init(); 

    curl_multi_add_handle(multi_handle, file->handle.curl); 

    /* lets start the fetch */ 
    curl_multi_perform(multi_handle, &file->still_running); 

    if((file->buffer_pos == 0) && (!file->still_running)) { 
     /* if still_running is 0 now, we should return NULL */ 

     /* make sure the easy handle is not in the multi handle anymore */ 
     curl_multi_remove_handle(multi_handle, file->handle.curl); 

     /* cleanup */ 
     curl_easy_cleanup(file->handle.curl); 

     free(file); 

     file = NULL; 
    } 
    } 
    return file; 
} 

int url_fclose(URL_FILE *file) 
{ 
    int ret=0;/* default is good return */ 

    switch(file->type) { 
    case CFTYPE_FILE: 
    ret=fclose(file->handle.file); /* passthrough */ 
    break; 

    case CFTYPE_CURL: 
    /* make sure the easy handle is not in the multi handle anymore */ 
    curl_multi_remove_handle(multi_handle, file->handle.curl); 

    /* cleanup */ 
    curl_easy_cleanup(file->handle.curl); 
    break; 

    default: /* unknown or supported type - oh dear */ 
    ret=EOF; 
    errno=EBADF; 
    break; 
    } 

    if(file->buffer) 
    free(file->buffer);/* free any allocated buffer space */ 

    free(file); 

    return ret; 
} 

int url_feof(URL_FILE *file) 
{ 
    int ret=0; 

    switch(file->type) { 
    case CFTYPE_FILE: 
    ret=feof(file->handle.file); 
    break; 

    case CFTYPE_CURL: 
    if((file->buffer_pos == 0) && (!file->still_running)) 
     ret = 1; 
    break; 

    default: /* unknown or supported type - oh dear */ 
    ret=-1; 
    errno=EBADF; 
    break; 
    } 
    return ret; 
} 

size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file) 
{ 
    size_t want; 

    switch(file->type) { 
    case CFTYPE_FILE: 
    want=fread(ptr,size,nmemb,file->handle.file); 
    break; 

    case CFTYPE_CURL: 
    want = nmemb * size; 

    fill_buffer(file,want); 

    /* check if theres data in the buffer - if not fill_buffer() 
    * either errored or EOF */ 
    if(!file->buffer_pos) 
     return 0; 

    /* ensure only available data is considered */ 
    if(file->buffer_pos < want) 
     want = file->buffer_pos; 

    /* xfer data to caller */ 
    memcpy(ptr, file->buffer, want); 

    use_buffer(file,want); 

    want = want/size;  /* number of items */ 
    break; 

    default: /* unknown or supported type - oh dear */ 
    want=0; 
    errno=EBADF; 
    break; 

    } 
    return want; 
} 

char *url_fgets(char *ptr, size_t size, URL_FILE *file) 
{ 
    size_t want = size - 1;/* always need to leave room for zero termination */ 
    size_t loop; 

    switch(file->type) { 
    case CFTYPE_FILE: 
    ptr = fgets(ptr,size,file->handle.file); 
    break; 

    case CFTYPE_CURL: 
    fill_buffer(file,want); 

    /* check if theres data in the buffer - if not fill either errored or 
    * EOF */ 
    if(!file->buffer_pos) 
     return NULL; 

    /* ensure only available data is considered */ 
    if(file->buffer_pos < want) 
     want = file->buffer_pos; 

    /*buffer contains data */ 
    /* look for newline or eof */ 
    for(loop=0;loop < want;loop++) { 
     if(file->buffer[loop] == '\n') { 
     want=loop+1;/* include newline */ 
     break; 
     } 
    } 

    /* xfer data to caller */ 
    memcpy(ptr, file->buffer, want); 
    ptr[want]=0;/* allways null terminate */ 

    use_buffer(file,want); 

    break; 

    default: /* unknown or supported type - oh dear */ 
    ptr=NULL; 
    errno=EBADF; 
    break; 
    } 

    return ptr;/*success */ 
} 

void url_rewind(URL_FILE *file) 
{ 
    switch(file->type) { 
    case CFTYPE_FILE: 
    rewind(file->handle.file); /* passthrough */ 
    break; 

    case CFTYPE_CURL: 
    /* halt transaction */ 
    curl_multi_remove_handle(multi_handle, file->handle.curl); 

    /* restart */ 
    curl_multi_add_handle(multi_handle, file->handle.curl); 

    /* ditch buffer - write will recreate - resets stream pos*/ 
    if(file->buffer) 
     free(file->buffer); 

    file->buffer=NULL; 
    file->buffer_pos=0; 
    file->buffer_len=0; 

    break; 

    default: /* unknown or supported type - oh dear */ 
    break; 
    } 
} 

/* Small main program to retrive from a url using fgets and fread saving the 
* output to two test files (note the fgets method will corrupt binary files if 
* they contain 0 chars */ 
int main(int argc, char *argv[]) 
{ 
    URL_FILE *handle; 
    FILE *outf; 

    int nread; 
    char buffer[256]; 
    const char *url; 

    if(argc < 2) 
    url="http://192.168.7.3/testfile";/* default to testurl */ 
    else 
    url=argv[1];/* use passed url */ 

    /* copy from url line by line with fgets */ 
    outf=fopen("fgets.test","w+"); 
    if(!outf) { 
    perror("couldn't open fgets output file\n"); 
    return 1; 
    } 

    handle = url_fopen(url, "r"); 
    if(!handle) { 
    printf("couldn't url_fopen() %s\n", url); 
    fclose(outf); 
    return 2; 
    } 

    while(!url_feof(handle)) { 
    url_fgets(buffer,sizeof(buffer),handle); 
    fwrite(buffer,1,strlen(buffer),outf); 
    } 

    url_fclose(handle); 

    fclose(outf); 


    /* Copy from url with fread */ 
    outf=fopen("fread.test","w+"); 
    if(!outf) { 
    perror("couldn't open fread output file\n"); 
    return 1; 
    } 

    handle = url_fopen("testfile", "r"); 
    if(!handle) { 
    printf("couldn't url_fopen() testfile\n"); 
    fclose(outf); 
    return 2; 
    } 

    do { 
    nread = url_fread(buffer, 1,sizeof(buffer), handle); 
    fwrite(buffer,1,nread,outf); 
    } while(nread); 

    url_fclose(handle); 

    fclose(outf); 


    /* Test rewind */ 
    outf=fopen("rewind.test","w+"); 
    if(!outf) { 
    perror("couldn't open fread output file\n"); 
    return 1; 
    } 

    handle = url_fopen("testfile", "r"); 
    if(!handle) { 
    printf("couldn't url_fopen() testfile\n"); 
    fclose(outf); 
    return 2; 
    } 

    nread = url_fread(buffer, 1,sizeof(buffer), handle); 
    fwrite(buffer,1,nread,outf); 
    url_rewind(handle); 

    buffer[0]='\n'; 
    fwrite(buffer,1,1,outf); 

    nread = url_fread(buffer, 1,sizeof(buffer), handle); 
    fwrite(buffer,1,nread,outf); 


    url_fclose(handle); 

    fclose(outf); 


    return 0;/* all done */ 
} 
4

<stdio.h>fopen没有做到这一点。

但是,没有什么能够阻止某人编写一个名为fopen()的功能来执行其他操作。

FILE *popen(const char *command, const char *mode)可用于产卵运行适当的命令行工具如tftpwget,从而完成一个远程资源下载此成从C代码访问的文件描述符的过程。 popen()调用的语法与您所显示的非常相似。但是,它缺少下载实用程序的程序名称。一个裸露的url或ftp地址将不适用于popen()

参见:

还要注意:

PHP language version of fopen()确实开放裸露的URL。但是PHP!= C

+0

+1,轻松便携!,OP,我在你的答案上有一个编辑,显示一个例子。 – 2014-10-30 10:17:20

+1

@AlterMann谢谢。我已经提出了你的答案。 – Paul 2014-10-30 10:22:20