使用libcurl库上传sftp服务器,上传.txt文件成功,但大小变成1k了

使用libcurl库上传sftp服务器,上传.txt文件成功,且sftp收到的.txt文件大小正常。上传.xlsx文件时也提示成功,sftp上也有收到文件,但文件大小变成1k了,不是实际大小,excel不能打开。(上传.rar文件也变成1k大小),不知道这是为什么,代码如下,请帮忙查看一下。

size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) //回调函数
{
    curl_off_t nread;
    size_t retcode = fread(ptr, size, nmemb, (FILE*)(stream));
    nread = (curl_off_t)retcode;
    return retcode;
}

size_t CTest02Dlg::upload(const char * user,const char * passwd,const char * url, const char * path)
{    
        curl_global_init(CURL_GLOBAL_DEFAULT);
    int nRet(-1);
    CURL *curl;
    CURLcode res;
    //struct curl_slist *headerlist = NULL;
    std::string s1(user);
    std::string s2(passwd);
    std::string s3 = s1;
    s3.append(":");
    s3.append(s2);
    system("ls write_file");
    FILE* pSendFile = fopen(path,"r");
    if(pSendFile == NULL)
    {
        printf("open failed\n");
        return 1;
    }
    printf("------------\n");
    fseek(pSendFile, 0L, SEEK_END);
    printf("------------\n");
    size_t iFileSize = ftell(pSendFile);
    printf("------------\n");
    fseek(pSendFile, 0L, SEEK_SET);
    printf("begin easy_init\n"); 

    curl = curl_easy_init();
    printf("curl_easy_init success\n");
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL,url);
        curl_easy_setopt(curl, CURLOPT_USERPWD,s3.c_str()); 
        curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_SFTP);//
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
        curl_easy_setopt(curl, CURLOPT_READDATA, pSendFile);
        curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 0);
        curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
        curl_easy_setopt(curl, CURLOPT_INFILESIZE, iFileSize);

        printf("curl_easy_setopt success");
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        if(CURLE_OK != res) 
        {
            nRet = 2;
            fprintf(stdout, "curl told us %d\n", res);
        }
        else
        {
            nRet = 0;
        }
    }
    fclose(pSendFile);
        curl_global_cleanup();
    return nRet;
}

void CTest02Dlg::OnBnClickedButton2()
{
    // TODO: 在此添加控件通知处理程序代码
    int nRet = upload("sftpuser","123","sftp://192.168.2.15:22/test/(2023-05-1608_48_00).xlsx","D:\test\(2023-05-1608_48_00).xlsx");
}

来自NewBing和LP的编写:
你的代码看起来是正确的,但是有一些可能的原因会导致你的问题,要进一步进行排查。这里有一些可能的问题:

  1. 文件打开方式:你打开待上传文件时使用的是 "r" 模式,这个模式是用于读取文本文件的。但是 .xlsx 和 .rar 文件是二进制文件,你应该用 "rb" 模式打开文件。试修改你的代码,用 "rb" 模式打开文件:

    FILE* pSendFile = fopen(path,"rb");
    
  2. libcurl版本问题:你的libcurl库版本可能存在问题,有可能是版本过旧或者与你的程序存在不兼容的问题。你可以尝试更新到最新版本的libcurl库,或者尝试使用其他版本的libcurl库看看问题是否仍然存在。

  3. 服务器问题:服务器可能存在某些问题,导致无法正确处理上传的文件。你可以尝试更换服务器,或者联系服务器的管理员,看看是否存在可以解决的问题。

  4. 文件权限问题:在上传文件前,检查你是否有足够的权限来读取这些文件。如果没有,那么可能会导致文件大小不正确的问题。

这些都是可能导致你问题的原因,你可以尝试根据这些信息进行进一步的排查。如果问题仍然存在,那么可能需要进行更深入的调查。

没有使用“rb”模式以二进制方式打开文件。因此,在读取文件大小时将其视为文本文件,导致文件大小不正确。

您可以尝试使用“rb”(read binary)模式打开要上传的文件,以确保正确读取文件的大小:

FILE* pSendFile = fopen(path,"rb");

另外,由于二进制文件可能包含二进制数据,因此建议使用CURLPROTO_SFTP选项来指定协议。

curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_SFTP);

文件上传要以二进制的方式打开

FILE * file = fopen(imagePath, "rb");

另外在发送的时候需要指定文件的大小 fsize,这样服务器端就知道需要接收多少字节了

curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, fsize);  

  • 以下回答由chatgpt基于相关博客总结生成:

    根据提供的参考资料中的代码,无法直接得知链接中使用的是哪个版本的 libcurl 库。但是根据参考资料中的介绍,libcurl 是一个高可移植性、功能丰富的通信库,可以支持所有的应用层协议,适配兼容性非常好,基于 C 接口可以很容易写出各种语言的封装。因此,可以通过升级或更改 libcurl 库版本,在保证基本功能的前提下尽可能减少发生异常或警告信息的概率。

    至于代码中的文件大小限制或其他限制,可以根据需求设置相应的参数。例如,可以使用 curl_easy_setopt 函数设置 CURLOPT_POSTFIELDSIZE_LARGE 选项,用于限制可以发送的最大文件大小。文件上传时的异常或警告信息可能与应用场景和具体实现有关,需要根据实际情况进一步分析调整。

    以下是一个设置 CURLOPT_POSTFIELDSIZE_LARGE 的示例代码:

    // 设置可以发送的最大文件大小
    const int64_t kMaxFileSize = 1024 * 1024 * 50;  // 50 MB
    
    // ...
    
    // 设置 CURLOPT_POSTFIELDSIZE_LARGE 选项
    if (file_size > kMaxFileSize) {
      curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE_LARGE, 0L);
      curl_easy_setopt(curl_, CURLOPT_FLAGS, (void*)(unsigned long)1);  // 设置标志位
    } else {
      curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)file_size);
    }
    
    // ...
    

    当需要上传的文件大小超过 kMaxFileSize 时,将 CURLOPT_POSTFIELDSIZE_LARGE 设置为 0,代表取消发送;同时设置一个标志位以便在回调函数中提示错误。否则,将文件大小设置为 CURLOPT_POSTFIELDSIZE_LARGE,可以正常上传文件。需要注意的是,libcurl 库在实际应用中,除了基本的 CURLOPT_POSTFIELDSIZE 和 CURLOPT_POSTFIELDSIZE_LARGE 选项,还提供了一些其他的控制文件上传的选项,如 CURLOPT_READFUNCTION 和 CURLOPT_READDATA 等,根据实际业务需求选择合适的选项。