2010-03-19 4 views
3

Я использую C++ с libcurl для передачи SFTP/FTPS. Перед загрузкой файла мне нужно проверить, существует ли файл, не загружая его.с помощью libcurl для проверки наличия файла на SFTP-сайте

Если файл не существует, я бегу на следующие проблемы:

//set up curlhandle for the public/private keys and whatever else first. 
curl_easy_setopt(CurlHandle, CURLOPT_URL, "sftp://[email protected]:host/nonexistent-file"); 
curl_easy_setopt(CurlHandle, CURLOPT_NOBODY, 1); 
curl_easy_setopt(CurlHandle, CURLOPT_FILETIME, 1); 
int result = curl_easy_perform(CurlHandle); 
//result is CURLE_OK, not CURLE_REMOTE_FILE_NOT_FOUND 
//using curl_easy_getinfo to get the file time will return -1 for filetime, regardless 
//if the file is there or not. 

Если я не использую CURLOPT_NOBODY, это работает, я получаю CURLE_REMOTE_FILE_NOT_FOUND.

Однако, если файл существует, он загружается, что отнимает у меня время, так как я просто хочу знать, есть оно там или нет.

Любые другие методы/варианты Мне не хватает? Обратите внимание, что он должен работать и для ftps.


Редактировать: Данная ошибка возникает при использовании sftp. С FTPS/FTP я получаю CURLE_FTP_COULDNT_RETR_FILE, с которым я могу работать.

+0

Вы когда-нибудь решали эту проблему? У меня такая же проблема. – Lextar

ответ

0

Я нашел способ сделать эту работу. Основная идея - попытаться прочитать файл, а затем прервать операцию чтения, если файл существует, чтобы избежать загрузки всего файла. Так что это будет либо получить возвращенную ошибку из Curl для «файл не существует», или «ошибка записи данных»:

static size_t abort_read(void *ptr, size_t size, size_t nmemb, void *data) 
{ 
    (void)ptr; 
    (void)data; 
    /* we are not interested in the data itself, 
    so we abort operation ... */ 
    return (size_t)(-1); // produces CURLE_WRITE_ERROR 
} 
.... 
curl_easy_setopt(curl,CURLOPT_URL, url); 
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); 
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, abort_read); 
CURLcode res = curl_easy_perform(curl); 
/* restore options */ 
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); 
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); 
curl_easy_setopt(curl, CURLOPT_URL, NULL); 
return (res==CURLE_WRITE_ERROR); 
2

Испытано это в Libcurl 7.38.0

curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); 
curl_easy_setopt(curl, CURLOPT_HEADER, 1L); 

CURLcode iRc = curl_easy_perform(curl); 

if (iRc == CURLE_REMOTE_FILE_NOT_FOUND) 
    // File doesn't exist 
else if (iRc == CURLE_OK) 
    // File exists 

Однако CURLOPT_NOBODY и CURLOPT_HEADER для SFTP не возвращает ошибку , если файл не существует в некоторых предыдущих версиях libcurl. Альтернативное решение для этого:

// Ask for the first byte 
curl_easy_setopt(curl, CURLOPT_RANGE, 
    (const char *)"0-0"); 

CURLcode iRc = curl_easy_perform(curl); 

if (iRc == CURLE_REMOTE_FILE_NOT_FOUND) 
    // File doesn't exist 
else if (iRc == CURLE_OK || iRc == CURLE_BAD_DOWNLOAD_RESUME) 
    // File exists 
+0

Зачем запрашивать 10 байтов вместо 1 байта? –

+0

@RemyLebeau: Это несущественно. Цель состоит в том, чтобы загрузить только столько, чтобы узнать, существует ли файл. 1 байт или 10 байтов по сети практически не имеет никакого значения. –

+0

@RemyLebeau: Действительно, альтернативное решение в его нынешнем виде ошибочно. Если это 0-байтовый удаленный файл, возвращается ошибка CURLE_BAD_DOWNLOAD_RESUME, поскольку указанное смещение больше ожидаемого. Редактирование моего ответа. –