Board logo

标题: 强劲的多线程下载器 purl.exe [打印本页]

作者: happy886rr    时间: 2017-8-25 22:10     标题: 强劲的多线程下载器 purl.exe

本帖最后由 happy886rr 于 2017-8-26 08:54 编辑
控制台下强劲的多线程下载器,快如闪电。支持purl.ini配置文件。批量下载各类url资源链。
用法:
purl -i[配置文件.ini] -l[输出日志] -n[线程数] -r[根目录]\n\
配置文件书写格式
#############################################################################
http://www.a.com/[:0].[:1]
#############################################################################
[:0]=01-99
#############################################################################
[:1]=jpg,gif,png,bmp
[:2]=
[:3]=
...
其中[:0]到[:9]为URL通配符,启用[:0]后具有多线程效益,启用[:9]具有尾加速功能。这10个通配符可以是数字范围如:[:0]=1-9;也可以是字符范围,如[:1]=a-z;还可以是字符串枚举,如:[:2]=jpg,mp3,txt,doc

为节省论坛空间,不提供任何附件下载,源码发行。
  1. /*
  2. THE THREAD DOWNLOAD TOOL, COPYRIGHT@2017~2019 BY HAPPY, VERSION 1.0
  3. PURL.EXE
  4. */
  5. #include   <stdio.h>
  6. #include  <stdlib.h>
  7. #include  <string.h>
  8. #include <windows.h>
  9. #include <process.h>
  10. #include  <direct.h>
  11. #include    <time.h>
  12. #include    <math.h>
  13. #include      <io.h>
  14. #pragma comment(lib, "Ws2_32.lib")
  15. #pragma comment (lib,"urlmon.lib")
  16. /*************宏量定义*************/
  17. #define SAFE_SIZE  512
  18. #define FILE_EXIST 0
  19. //定义配置文件
  20. #define PURL_INI "\
  21. #################################################################\n\
  22. http://\n\
  23. #################################################################\n\
  24. [:0]=\n\
  25. #################################################################\n\
  26. [:1]=\n\
  27. [:2]=\n\
  28. [:3]=\n\
  29. [:4]=\n\
  30. [:5]=\n\
  31. [:6]=\n\
  32. [:7]=\n\
  33. [:8]=\n\
  34. #################################################################\n\
  35. [:9]=\n\
  36. #################################################################\n"
  37. //定义帮助说明
  38. #define HELP_INFORMATION "\
  39. -----------------------------------------------------------------\n\
  40. purl -i[inifile] -l[outlog] -n[threadnum] -r[rootdir]\n\
  41. -----------------------------------------------------------------\n\
  42.      -h Show help information\n\
  43.      -i Set the purl inifile\n\
  44.      -l Set the log output directory\n\
  45.      -n Set the number of concurrent threads to download\n\
  46.      -r Set the download root directory\n\
  47. -----------------------------------------------------------------\n\
  48. version 1.0"
  49. /*************全局变量*************/
  50. static int M[10], N[10], Z[10];
  51. static int prointThread=0, nowsThread=0, trueDownload=0, totalCYC=1;
  52. static char murl[SAFE_SIZE], outlog[SAFE_SIZE], inifile[SAFE_SIZE]=".\\purl.ini", mpath[SAFE_SIZE]=".\\", settingini[10][SAFE_SIZE*2], *S[10][SAFE_SIZE];
  53. static BOOL renMARK[10];
  54. static BOOL urlMARK=FALSE;
  55. FILE* logfp;
  56. //进度条容器
  57. static const char* proGRESS="[                                                      ]\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
  58. /*************事件变量*************/
  59. //创建事件对象
  60. HANDLE ghDataEvent;
  61. /*************功能函数*************/
  62. //切分字串
  63. int ArgsSpliy(char* Str, int SN)
  64. {
  65. int i=0;
  66. char* pstr=strtok(Str, " \t\n,");
  67. while(pstr !=NULL){
  68. S[SN][i]=(char*)calloc(strlen(pstr)+1, sizeof(char));
  69. strcpy(S[SN][i++], pstr);
  70. pstr=strtok(NULL, " \t\n,");
  71. }
  72. return i;
  73. }
  74. //判断字母
  75. BOOL isLetter(char* p)
  76. {
  77. return (p && (('A'<=*p&&*p<='Z')||('a'<=*p&&*p<='z'))&&(*(p+1)=='\0'))?TRUE:FALSE;
  78. }
  79. //彩显函数
  80. int ColorString(HANDLE handle_out, char* pstrA, char* pstrB, int colorA, int colorB, int num)
  81. {
  82. SetConsoleTextAttribute(handle_out, colorA);  //项目色
  83. fprintf(stdout, pstrA);
  84. SetConsoleTextAttribute(handle_out, colorB);  //数据色
  85. (num<0)?fprintf(stdout, pstrB):fprintf(stdout, "%d\n", num);
  86. return 0;
  87. }
  88. //光标函数
  89. BOOL DispyCursor(int size,bool mode)
  90. {
  91. CONSOLE_CURSOR_INFO cinfo ={(DWORD)size, mode};
  92. return SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cinfo);
  93. }
  94. //域名IP解析
  95. int DownloadURLtoIP(HANDLE handle_out, const char* downloadURL)
  96. {
  97. WSADATA wsaData;  
  98. WSAStartup(MAKEWORD(2,2), &wsaData);
  99. char *pstr=(char*)downloadURL, *urlweb=(char*)calloc(SAFE_SIZE, sizeof(char)), *tstr=urlweb;
  100. while(*pstr!=':'){pstr++;}
  101. pstr+=3;
  102. while(*pstr!='/'&& *pstr!='\n' && *pstr!='\0'){
  103. *tstr++=*pstr++;
  104. }
  105. const char* pszUrl=(const char*)urlweb;
  106. if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)  
  107. {
  108. //fprintf(stdout, "Init socket faile\n");  
  109. return 1;  
  110. }
  111. struct hostent *pHost = gethostbyname(pszUrl);
  112. //释放空间
  113. free(urlweb);
  114. if (pHost == NULL)  
  115. {  
  116. WSACleanup();  
  117. //fprintf(stdout, "pHost == NULL \n");  
  118. return 1;  
  119. }
  120. //主机正式名称
  121. ColorString(handle_out, "[URL-HOST] ", (pHost)?pHost->h_name:"NULL", 4|8, 1|2|8, -1);
  122. fprintf(stdout, "\n");
  123. //主机别名,可以有多个
  124. int iIndex = 0;  
  125. while(pHost->h_aliases[iIndex])  
  126. {
  127. ColorString(handle_out, "[URLALIAS] ", pHost->h_aliases[iIndex], 4|8, 1|2|8, -1);
  128. fprintf(stdout, "\n");
  129. iIndex++;  
  130. }
  131. //地址字节数,IPV4是4,IPV6是6
  132. if(pHost->h_length==4)
  133. {
  134. ColorString(handle_out, "[IPV-TYPE] ", "IPV4\n", 4|8, 4|8, -1);
  135. }
  136. else if(pHost->h_length==6)
  137. {
  138. ColorString(handle_out, "[IPV-TYPE] ", "IPV6\n", 4|8, 4|8, -1);
  139. }
  140. iIndex = 0;
  141. while(pHost->h_addr_list[iIndex])  
  142. {
  143. ColorString(handle_out, "[IP-ADDRE] ", inet_ntoa(*(struct in_addr*)pHost->h_addr_list[iIndex]), 4|8, 4|2|8, -1);
  144. fprintf(stdout, "\n");
  145. iIndex++;  
  146. }   
  147. WSACleanup();
  148. return 0;
  149. }
  150. //开关解析
  151. int OPTIND=1, OPTOPT;
  152. char *OPTARG;
  153. int GetOpt(int nargc, char *nargv[], char *ostr)
  154. {
  155. static char* place="";
  156. static char* lastostr=(char *) 0;
  157. register char* oli;
  158. char* index();
  159. if(ostr!=lastostr){
  160. lastostr=ostr;
  161. place="";
  162. }
  163. if(!*place)
  164. {
  165. if(
  166. (OPTIND>=nargc)              ||
  167. (*(place=nargv[OPTIND])!='-')||
  168. (!*(++place))
  169. ){
  170. place="";
  171. return(EOF);
  172. }
  173. if (*place == '-' && place[1] == 0){
  174. ++OPTIND;
  175. return(EOF);
  176. }
  177. }
  178. if ((OPTOPT=(int)*place++)==(int)':' || !(oli=strchr(ostr, OPTOPT))){
  179. if(!*place){++OPTIND;}
  180. }
  181. if (oli != NULL && *(++oli) != ':'){
  182. OPTARG=NULL;
  183. if(!*place){++OPTIND;}
  184. }
  185. else{
  186. if(*place){
  187. OPTARG=place;
  188. }else if(nargc<=++OPTIND){
  189. place="";
  190. }else{
  191. OPTARG=nargv[OPTIND];
  192. }
  193. place="";
  194. ++OPTIND;
  195. }
  196. return(OPTOPT);
  197. }
  198. /*************获取配置*************/
  199. int ReadSetting(char* pfile)
  200. {
  201. //读取脚本文件
  202. FILE* fp;
  203. if( (fp=fopen(pfile, "r"))==NULL ){
  204. fprintf(stdout, "Reading settings failed!\n");
  205. exit(1);
  206. }
  207. int SN;
  208. //分配行容器
  209. char* LCache=(char*)calloc(1025, sizeof(char));
  210. //辅助行指针
  211. char* Line=NULL;
  212. while(!feof(fp)){
  213. memset(LCache, 0,  1024*sizeof(char));
  214. fgets(LCache, 1024, fp);
  215. //指针置换
  216. Line=LCache;
  217. //将尾部换行符注掉
  218. while(*Line!='\n'&& *Line!='\0'){Line++;}
  219. *Line='\0';
  220. Line=LCache;
  221. //过滤行TAB缩进或前空格
  222. while(*Line=='\t'|| *Line==' '){Line++;}
  223. //过滤注释符
  224. if(Line[0]=='#'||strlen(Line)<=5){
  225. continue;
  226. }
  227. //提取URL
  228. if(
  229. (!urlMARK)                    &&
  230. (Line[0]=='h' ||Line[0]=='H') &&
  231. (Line[1]=='t' ||Line[1]=='T') &&
  232. (Line[2]=='t' ||Line[2]=='T') &&
  233. (Line[3]=='p' ||Line[3]=='P') &&
  234. (
  235. Line[4]==':' ||
  236. (
  237. (Line[4]=='s'||Line[4]=='S') &&
  238. (Line[5]==':')
  239. )
  240. )
  241. ){
  242. if(strlen(Line)<10){
  243. fprintf(stdout, "Please fill the url!\n");
  244. exit(1);
  245. }
  246. strcpy(murl, Line);
  247. while(*Line !='\0'){
  248. if(*Line=='[' && *(Line+1)==':' && ('0'<=*(Line+2) && *(Line+2)<='9') && *(Line+3)==']'){
  249. renMARK[*(Line+2)-48]=TRUE;
  250. Line+=4;
  251. }else{
  252. Line++;
  253. }
  254. }
  255. urlMARK=TRUE;
  256. continue;
  257. }else if(
  258. (urlMARK)                     &&
  259. (Line[0]=='[' &&Line[1]==':') &&
  260. ('0'<=Line[2] &&Line[2]<='9') &&
  261. (Line[3]==']' &&Line[4]=='=')
  262. ){
  263. SN=Line[2]-48;
  264. if(!renMARK[SN]){continue;}
  265. strcpy(settingini[SN], Line);
  266. if(strchr(Line+5, ',')){
  267. M[SN]=0;
  268. N[SN]=ArgsSpliy(Line+5, SN)-1;
  269. }else if(renMARK[SN]){
  270. char *snumsrc=strtok(Line+5, " \t-"), *tmps=(snumsrc!=NULL)?strtok(NULL, " \t-"):NULL, *zp=snumsrc;
  271. if(isLetter(snumsrc) && isLetter(tmps)){
  272. int exnum1=*snumsrc, exnum2=*tmps;
  273. Z[SN]=-1;
  274. M[SN]=(exnum1 <= exnum2)?(N[SN]=exnum2, exnum1):(N[SN]=exnum1, exnum2);
  275. }else if(tmps!=NULL){
  276. if(*zp=='0'){
  277. while('0'<= *zp && *zp <='9'){
  278. Z[SN]++;
  279. zp++;
  280. }
  281. }
  282. M[SN]=atoi(snumsrc), N[SN]=atoi(tmps);
  283. if(M[SN]>N[SN]){
  284. int exnum=M[SN];
  285. M[SN]=N[SN], N[SN]=exnum;
  286. }
  287. }
  288. }
  289. }
  290. }
  291. fclose(fp);
  292. //统计总循环次数
  293. for(int i=0; i<10; i++){totalCYC *=N[i]-M[i]+1;}
  294. return 0;
  295. }
  296. /*************下载函数*************/
  297. UINT WINAPI FastDownload(void* ptr)
  298. {
  299. //分配URL字串
  300. char* ptftr=(char*)calloc(16, sizeof(char));
  301. char* aurl =(char*)calloc(SAFE_SIZE, sizeof(char));
  302. char* dest =(char*)calloc(SAFE_SIZE, sizeof(char));
  303. char* durl =(char*)calloc(SAFE_SIZE, sizeof(char));
  304. char* titl =(char*)calloc(SAFE_SIZE, sizeof(char));
  305. durl[0]='.', durl[1]='\\';
  306. //接受线程传参
  307. int nThreadID = *((int*)ptr);
  308. int snum      = *((int*)ptr+1);
  309. int lnum      = *((int*)ptr+2);
  310. SetEvent(ghDataEvent);
  311. nowsThread++;
  312. if(*outlog != 0){
  313. //fprintf(logfp, "\nThe %dth thread start.\n", nThreadID+1);
  314. }
  315. //创建循环变量数组
  316. int i[10]={0}, SN;
  317. //创建下载状态变量
  318. BOOL preMARK=FALSE, nowMARK=FALSE;
  319. //定义URL指针
  320. char *purl=NULL, *surl=NULL, *pdit=NULL;
  321. //启动十层循环
  322. for(i[0]=snum; i[0]<=lnum; i[0]++)
  323. for(i[1]=M[1]; i[1]<=N[1]; i[1]++)
  324. for(i[2]=M[2]; i[2]<=N[2]; i[2]++)
  325. for(i[3]=M[3]; i[3]<=N[3]; i[3]++)
  326. for(i[4]=M[4]; i[4]<=N[4]; i[4]++)
  327. for(i[5]=M[5]; i[5]<=N[5]; i[5]++)
  328. for(i[6]=M[6]; i[6]<=N[6]; i[6]++)
  329. for(i[7]=M[7]; i[7]<=N[7]; i[7]++)
  330. for(i[8]=M[8]; i[8]<=N[8]; i[8]++)
  331. for(i[9]=M[9]; i[9]<=N[9]; i[9]++){
  332.     surl=murl, purl=aurl;
  333. while(*surl !='\0'){
  334. //替换正则标签
  335. if(*surl=='[' && *(surl+1)==':' && '0'<=*(surl+2) && *(surl+2)<='9' && *(surl+3)==']' && renMARK[*(surl+2)-48]){
  336. SN=*(surl+2)-48;
  337. if(S[SN][0] !=NULL){
  338. pdit=S[SN][i[SN]];
  339. }else{
  340. if(Z[SN] >0){
  341. sprintf(ptftr, "%%0%dd", Z[SN]);
  342. sprintf(dest, ptftr, i[SN]);
  343. }else if(Z[SN]==-1){
  344. sprintf(dest, "%c",  (char)i[SN]);
  345. }else{
  346. sprintf(dest, "%d",  i[SN]);
  347. }
  348. pdit=dest;
  349. }
  350. while(*pdit !='\0'){
  351. *(purl++)=*(pdit++);
  352. }
  353. surl+=4;
  354. }else{
  355. *(purl++)=*(surl++);
  356. }
  357. }
  358. //置结束符
  359. *purl='\0';
  360. //显示当前下载的URL
  361. prointThread++;
  362. sprintf(titl, "[%03dT]-[%03dF] %s", nowsThread, trueDownload, aurl);
  363. SetConsoleTitleA(titl);
  364. //处理下载路径
  365. char* turl=strstr(aurl, "://")+3;
  366. char* sp=durl+2;
  367. //根据网址创建目录
  368. while(*turl != '\0'){
  369. switch(*turl)
  370. {
  371. case '/':
  372. *sp='\0';
  373. if(_access(durl, FILE_EXIST) != 0){
  374. _mkdir(durl);
  375. }
  376. *sp='\\';
  377. break;
  378. case ':':
  379. case '*':
  380. case '?':
  381. case '"':
  382. case '>':
  383. case '<':
  384. case '|':
  385. *sp='@';
  386. break;
  387. default:
  388. *sp=*turl;
  389. break;
  390. }
  391. //指针移位
  392. sp++, turl++;
  393. }
  394. //置结束符
  395. *sp='\0';
  396. //调用API下载
  397. URLDownloadToFileA(NULL, aurl, durl, 0, NULL);
  398. //下载状态
  399. nowMARK=(_access(durl, FILE_EXIST)==0)?TRUE:FALSE;
  400. //增速判断
  401. if(preMARK && !nowMARK && i[9]!=M[9]){
  402. break;
  403. }
  404. //显示下载成功的文件
  405. if(nowMARK){
  406. trueDownload++;
  407. if(*outlog != 0){fprintf(logfp, "[*]%s\n", aurl);}
  408. }
  409. //下载状态更新
  410. preMARK=nowMARK;
  411. }
  412. //释放数组内存
  413. free(aurl);
  414. free(durl);
  415. free(dest);
  416. free(titl);
  417. free(ptftr);
  418. //线程结束
  419. nowsThread--;
  420. if(*outlog != 0){
  421. //fprintf(logfp, "\nThe %dth thread end!\n\n", nThreadID+1);
  422. }
  423. return (UINT)0;
  424. }
  425. /*************MAIN函数*************/
  426. int main(int argc, char** argv)
  427. {
  428. int threadNUMS=100;
  429. char K, *outLOG=NULL;
  430. while((K=GetOpt(argc,argv,"hi:n:p:l:"))!=-1)
  431. {
  432. switch(K)
  433. {
  434. case 'h':
  435. case 'H':
  436. fprintf(stdout, HELP_INFORMATION);
  437. exit(0);
  438. case 'i':
  439. case 'I':
  440. if(OPTARG !=NULL){
  441. strcpy(inifile, OPTARG);
  442. }
  443. break;
  444. case 'l':
  445. case 'L':
  446. if(OPTARG !=NULL){
  447. strcpy(outlog, OPTARG);
  448. }
  449. break;
  450. case 'n':
  451. case 'N':
  452. if(OPTARG !=NULL){
  453. int exnum=atoi(OPTARG);
  454. threadNUMS=(0<exnum && exnum<SAFE_SIZE*4)?exnum:SAFE_SIZE*4;
  455. }
  456. break;
  457. case 'r':
  458. case 'R':
  459. if(OPTARG !=NULL){
  460. strcpy(mpath, OPTARG);
  461. }
  462. break;
  463. default:
  464. fprintf(stdout, "Unknown switch '%c'\n", K);
  465. exit(1);
  466. }
  467. }
  468. //判断配置文件是否存在
  469. if(access(inifile, FILE_EXIST)!=0){
  470. FILE* fp=fopen(inifile, "w");
  471. fprintf(fp, PURL_INI);
  472. fclose(fp);
  473. fprintf(stdout, "Please fill in the setting file\n");
  474. fprintf(stdout, HELP_INFORMATION);
  475. exit(1);
  476. }
  477. if(argc==1){
  478. //无参数则退出
  479. fprintf(stdout, HELP_INFORMATION);
  480. exit(0);
  481. }
  482. //判断根目录是否存在
  483. if(_access(mpath, FILE_EXIST)!=0){
  484. _mkdir(mpath);
  485. }
  486. if(_access(mpath, FILE_EXIST)==0){
  487. //切换至下载目录
  488. _chdir(mpath);
  489. }else{
  490. //无法创建根目录则退出
  491. fprintf(stdout, "Can not creat the root folder\n");
  492. exit(1);
  493. }
  494. //读取purl配置文件
  495. ReadSetting(inifile);
  496. if(! urlMARK){
  497. fprintf(stdout, "Please fill in the download url\n");
  498. exit(1);
  499. }
  500. //获取控制台输出句柄
  501. HANDLE handle_out=GetStdHandle(STD_OUTPUT_HANDLE);
  502. //线程传参数组
  503. int inum[3]={0};
  504. //判断是否使用多线程正则符[:0]
  505. if(! renMARK[0]){
  506. threadNUMS=1;
  507. }
  508. //线程数
  509. int nThreadCount=N[0]-M[0];
  510. if(nThreadCount<=0 && threadNUMS!=1){
  511. fprintf(stdout, "\nThe '[:0]' don't get incremental value\n");
  512. exit(1);
  513. }
  514. //创建时间结构体
  515. time_t startTIME, endTIME;
  516. struct tm* timeinfo;
  517.         time(&startTIME);
  518.         timeinfo=localtime(&startTIME);
  519. //计算线程分组数
  520. int rThreadAdd   =(int)ceil((nThreadCount + 1)*1.0/threadNUMS);
  521. int rThreadRange =(int)ceil((nThreadCount + 1)*1.0/(rThreadAdd?rThreadAdd:1.0));
  522. //是否开启日志输出
  523. if(*outlog != 0){
  524. logfp=fopen(outlog, "w");
  525. if(logfp == NULL){
  526. fprintf(stdout, "Open log failed\n");
  527. exit(1);
  528. }else{
  529. fprintf(logfp,
  530. "================================================================\n"
  531. "The purl log file, Time: %s"
  532. "================================================================\n\n"
  533. ,asctime(timeinfo)
  534. );
  535. fprintf(logfp, "[Threads num]\n%d\n\n", rThreadRange);
  536. fprintf(logfp, "[Root path]\n%s\n\n", mpath);
  537. fprintf(logfp, "[The URL regular]\n%s\n\n", murl);
  538. fprintf(logfp, "[Setting ini]\n");
  539. for(int i=0; i<=9; i++){
  540. if(settingini[i][0]!=0){
  541. fprintf(logfp, "%s\n", settingini[i]);
  542. }
  543. }
  544. fprintf(logfp, "\n[Start the download time]\n%s\n", asctime(timeinfo));
  545. fprintf(logfp, "[Successfully downloaded URL]\n");
  546. }
  547. }
  548. //隐藏光标
  549. DispyCursor((DWORD)25, FALSE);
  550. //显示目标网站IP
  551. DownloadURLtoIP(handle_out, murl);
  552. //分配线程句柄数组
  553. HANDLE* phaThread =(HANDLE*)calloc(rThreadRange, sizeof(HANDLE));
  554. //创建事件对象
  555. ghDataEvent =CreateEventA(NULL, FALSE, FALSE, NULL);
  556. //错误号
  557. int nErr=0;
  558. for(int i=0; i<rThreadRange; i++){
  559. inum[0]=i, inum[1]=M[0]+i*rThreadAdd, inum[2]=M[0]+i*rThreadAdd+rThreadAdd-1;
  560. if(inum[2]>N[0]){inum[2]=N[0];}
  561. phaThread[i]=(HANDLE)_beginthreadex(NULL, 0, FastDownload, &inum, 2048, NULL);
  562. if(phaThread[i]==0){
  563.              nErr=GetLastError();
  564.              if(nErr==0x08){
  565.        printf("\nOpen thread failed, lack of storage space!\n");
  566. }else{
  567. printf("\nOpen thread failed, error number%d\n", nErr);
  568. }
  569. break;
  570. }
  571. WaitForSingleObject(ghDataEvent, INFINITE);
  572. }
  573. //色彩代码 紫色1|4|8,红色4|8,绿色2|8,兰色1|2|8,黄色2|4|8,白色1|2|4|8;
  574. //显示最大线程
  575. ColorString(handle_out, "[MAX-THRE] ", "", 4|8, 4|8, rThreadRange);
  576. //显示开始时间
  577. ColorString(handle_out, "[STA-TIME] ", asctime(timeinfo), 4|8, 1|4|8, -1);
  578. //绘制进度框
  579. ColorString(handle_out, "[DOWNLOAD] ", (char*)proGRESS, 4|8, 2|4|8, -1);
  580. //绘制进度条
  581. int spi=0;
  582. do{
  583. //进度百分数
  584. int i=(totalCYC==0)?100:(prointThread*100/totalCYC), j=i/2;
  585. if(spi==j){
  586. //缓解CPU占用
  587. Sleep(30);
  588. continue;
  589. }
  590. //显示递增进度
  591. while(spi<j){
  592. fputc('=', stdout);
  593. spi++;
  594. }
  595. //显示进度百分比
  596. fprintf(stdout, "%3d%%\b\b\b\b", i);
  597. //线程退出器
  598. if(prointThread==totalCYC){
  599. break;
  600. }
  601. }while(nowsThread);
  602. //补全百分百进度
  603. if(prointThread==totalCYC){
  604. while(spi<50){
  605. fputc('=', stdout);
  606. spi++;
  607. }
  608. fprintf(stdout, "100%%");
  609. }
  610. fprintf(stdout, "\n");
  611. //显示结束时间
  612. time(&endTIME);
  613. timeinfo=localtime(&endTIME);
  614. ColorString(handle_out, "[END-TIME] ", asctime(timeinfo), 4|8, 1|4|8, -1);
  615. //显示花费时间
  616. ColorString(handle_out, "[USE-TIME] ", "", 4|8, 1|2|8, -1);
  617. fprintf(stdout, "Takes %gs\n", difftime(endTIME, startTIME));
  618. //颜色归位
  619. SetConsoleTextAttribute(handle_out, 1|2|4);//白色
  620. //关闭日志读写
  621. if(*outlog != 0){
  622. fprintf(logfp, "\n[End the download time]\n%s\n", asctime(timeinfo));
  623. fprintf(logfp, "[Download time-spending]\n%g seconds\n\n", difftime(endTIME, startTIME));
  624. fprintf(logfp, "[Percent of completion]\n%d%%\n\n", (prointThread==totalCYC)?100:spi*2);
  625. fprintf(logfp, "[Successfully downloaded files]\n%d", trueDownload);
  626. fclose(logfp);
  627. }
  628. return 0;
  629. }
复制代码

作者: freesoft00    时间: 2017-8-26 01:13

是我用错了吗?怎么不行。

https://download.mozilla.org/?product=firefox-55.0.3-SSL&os=win&lang=zh-CN
http://ftp.mozilla.org/pub/firefox/releases/55.0.3/win32/zh-CN/Firefox%20Setup%2055.0.3.exe
https://ipmsg.org/archive/ipmsg470src.zip


把这三个网址分别添加到purl.ini中,也不行。弹出错误。
作者: happy886rr    时间: 2017-8-26 08:26

本帖最后由 happy886rr 于 2017-8-26 09:07 编辑

回复 2# freesoft00
代码已经修复,这是多线程批量下载器,只支持批量地址下载,比如www.a01.com, www.a02.com, www.a03.com就是批量的网址,而不是说单一下载某个文件。
单独下载某个文件请使用pget。
purl的目的是针对有规律的数字递增网址,批量多线程下载,而且必须是几千、几万的批量网址才可以成功下载。线程过少的话,主程序很快就跑完了,子线程也就结束了。我把下载量调到5000,你的文件都成功下载了[:0]=0-5000
purl是针对繁重的批量下载任务定制的,个别几个小文件的下载多线程会得不偿失,小文件请使用pget。
作者: freesoft00    时间: 2017-8-26 11:46

回复 3# happy886rr


    哦,知道了。用途不一样呀。
作者: llh931886    时间: 2017-9-14 14:39

支持  ssh 链接的 sftp  下载吗?
作者: CrLf    时间: 2017-10-10 00:37

请教下要怎么编译?
gcc和vs均未通过
作者: 523066680    时间: 2017-10-10 09:49

本帖最后由 523066680 于 2017-10-10 10:02 编辑

回复 6# CrLf


    试了 MinGW GCC, 稍微改一下可以

添加 <stdbool.h>
注释掉两个 lib 的引入(改为手动)
  1. #include <stdbool.h>
  2. // #pragma comment(lib, "ws2_32.lib")
  3. // #pragma comment (lib,"urlmon.lib")
复制代码
gcc purl.c -lws2_32 -lurlmon
作者: happy886rr    时间: 2017-10-10 13:39

本帖最后由 happy886rr 于 2017-10-10 14:10 编辑

回复 6# CrLf
大师,好久不见。(后缀一定要改为cpp)
编译现在都已经实现一键了,请参看我之前的帖子http://www.bathome.net/thread-44180-1-1.html
下载那个精简的vc++2010编译器(仅22M大小),把.cpp文件直接拖拽到VC.CMD批处理脚本上,就会自动生成exe。
别看体积小,编译功能与原版VS几乎没有差别。
   
另外我还发布过手机版的gcc编译器,可以实现代码直接编译为 安卓上可运行的二进制文件。从而实现 win、linux、安卓 各平台通吃。
作者: netdzb    时间: 2019-6-28 13:11

回复 8# happy886rr

手机版本的编译器在哪里?




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2