c - libcurl,处理分块数据
问题描述
我在 C 中使用 libcurl 来获取目录中的文件列表:
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_URL, path);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
res = curl_easy_perform(curl);
在回调中,我正在解析输出并处理文件:
static size_t my_fwrite(void * buffer, size_t size, size_t nmemb, void * root)
{
ftp_user_data * data = (ftp_user_data *)root;
char * rec = bxi_malloc(size * nmemb + 1);
bxi_memcpy(rec, buffer, size * nmemb);
printf("### %u (%u*%u)\n", (u32)(size*nmemb), (u32)size, (u32)nmemb);
lines_process(rec, data);
bxi_free(rec);
return size * nmemb;
}
但我有一个问题。如果目录足够大,答案会分块返回:
### 2865 (1*2865)
##
drwxr-xr-x 2 film tk 4096 Jun 6 10:03 .
drwxr-xr-x 114 film tk 53248 Jun 21 19:02 ..
-rw-r--r-- 4 film tk 19944333271 Jun 6 04:01 00f94595-a72c-44d7-8d7a-990c04a96f90
-rw-r--r-- 3 film tk 3439134 Jun 6 01:01 049307a7-b335-4981-a77c-735628473343
-rw-r--r-- 4 film tk 138285646 Jun 6 01:20 075a6aa4-8eab-43cc-9262-04f19ce11c6a
<...>
-rw-r--r-- 4 film tk 2712631246 Jun 6 00:41 61043b6f-6897-499a-8ca3-8c3d2401af10
-rw-r--r-- 4 film tk 2459646286 Jun 6 01:14 6afd69e4-b098-453a-ae4f-790e3f08fff0
-rw-r--r-- 4 film tk 2401778628 Jun 6 01:17 75ade815-1138-4db7-b096-49f945996e8f
-rw-r--r-- 4 film tk 32681128626 Jun 6 03:47 77fa0b2e-7188-4b05-9cd0-db054282885b
-rw-r--r-- 4 film tk 6
### 2866 (1*2866)
##
0794406 Jun 6 01:01 78567514-d7be-4190-8951-6455f43c7bc5
-rw-r--r-- 4 film tk 2381291004 Jun 6 01:23 789bdabc-d893-4853-9fae-75ff9b3e9d95
-rw-r--r-- 4 film tk 863532650 Jun 6 00:51 7e58294b-4ce0-4a21-8829-aa7b3c0abedc
-rw-r--r-- 4 film tk 27817391742 Jun 6 02:57 81d72c9f-5d4b-4d54-8cb1-a108dac46ff2
-rw-r--r-- 4 film tk 21342057477 Jun 6 04:35 83e64160-03a6-400d-924a-d1848d6b85b8
<...>
-rw-r--r-- 3 film tk 16603 Jun 6 01:23 PKL_992597cf-0c66-4f57-ba34-71706ccd7e53.xml
-rw-r--r-- 3 film tk 16599 Jun 6 01:23 PKL_b32fca6b-5f36-40fb-a64f-3d110edd1b74.xml
当然,这会破坏 lines_process 函数中的解析算法。
如何要求服务器或 libcurl 一次性向我发送数据?还是有另一种方法可以找出答案是否被分块?
非常感谢提前。
解决方案
找到了解决方案:
curl_easy_perform
由于用户函数的回调将在返回控制之前调用几次,因此可以将缓冲区的指针传输到my_fwrite ,然后在此处重新分配缓冲区,附加新数据,并仅在curl_easy_perform
返回后处理它控制:
curl_easy_perform started
my_fwrite(enter 0, appended 2000)
my_fwrite(enter 2000, appended 2000)
my_fwrite(enter 4000, appended 2000)
curl_easy_perform exited
postprocess the allocated buffer.
非常感谢 David Collins 提供的另一个解决方案。不幸的是,我无法应用它,因为我使用的服务器忽略了设置(NIH 的事情)。
UPD,代码:
回调数据结构:
typedef struct
{
char * path;
CML_Node * root;
char * lines;
} ftp_user_data;
回调函数:
static size_t my_fwrite(void * buffer, size_t size, size_t nmemb, void * root)
{
ftp_user_data * data = (ftp_user_data *)root;
u32 oldlen = bxi_strlen(data->lines);
data->lines = bxi_realloc(data->lines, oldlen + size * nmemb + 1);
bxi_memcpy(data->lines + oldlen, buffer, size * nmemb);
data->lines[oldlen + size * nmemb] = '\0';
printf("### %u (%u*%u)\n", (u32)(size*nmemb), (u32)size, (u32)nmemb);
return size * nmemb;
}
curl_send 函数,设置的选项和回调
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_URL, path);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); // < setting callback
curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
res = curl_easy_perform(curl); // < calling the curl
if (CURLE_OK != res)
fprintf(stderr, "Error during request: %s (%d) for path %s\n",
curl_easy_strerror(res), res, path);
curl_easy_cleanup(curl); // < cleaning the curl
printf("Exited curl\n");
lines_process(data); // < processing stored data
bxi_free(data->lines);
因此,经过小小的回答,我得到:
### 100 (1 * 100) // < Got only 100 bytes in data->lines now
Exited curl
在得到大答案后,我得到:
### 2048 (1*2048) // < Got 2048 bytes appended to data->lines
### 2048 (1*2048) // < Now it's 2048 + 2048 = 4096 bytes
### 305 (1*305) // < And the last 305 get appended => strlen(data->lines) == 4401
Exited curl // < now I have 4401 byte in data->lines and can totally parse it
推荐阅读
- sql - 现在在 Postgresql 中 - 仅显示日期
- node.js - Node.js 的新手。从其他文件调用函数,但节点正在打印整个文件内容
- python - /admin/criminals 'gender' 处的 MultiValueDictKeyError
- python - 是否可以在没有互联网连接的情况下安装 pygame?
- javascript - 可能的未处理承诺拒绝(id:3):TypeError:无法读取 null 的属性“草稿” TypeError:无法读取 null 的属性“草稿”
- android - 如何为 ionic 1 应用程序生成 64 位 apk
- android - 在drawable中制作一个布局,它有3个相同颜色的边框,一个是不同的
- android - 如何使用 View.layout() 方法更改视图大小?
- flutter - Flutter:如何在没有构建目录的情况下备份 Flutter 项目?
- ios - 保留应用程序执行期间生成的随机数,直到应用程序退出 Swift