《第六节 ipfs add file进度条实现》

golang版本进度条演示:

[root@node1 build]# ipfs add main.cc 
added QmZgunUwQgnQ4T5NmZYhTLECi1srQYXfSkELhaY5NoGkem main.cc
 927 B / 927 B [======================================================================================================================================] 100.00%[root@node1 build]#

[root@node1 build]# ipfs add /root/git.tar.bz2 
added QmfWdhVNERNKL2XJeRLfgmsXvYTH27m6bLVNXnpt7WPJwh git.tar.bz2
 133.82 MiB / 133.82 MiB [============================================================================================================================] 100.00%
 [root@node1 build]# ipfs add test 
 1.57 GiB / 2.00 GiB [===============================================================================================>-------------------------]  78.58% 00m06s
added QmTbKT35oQzKgR34LUHaPdtrFrphjxiQJLrz6QMyU4kQNC test
 2.00 GiB / 2.00 GiB [================================================================================================================================] 100.00%[root@node1 build]# 

实现进度条:

格式:

最左边开始的数是当前写入的大小/文件总大小,单位根据文件总大小不同分别为:B、MiB、GiB
紧接着,是一个以’[’、’=’、 ‘>’、’-’、’]'为显示字符的进度条,实时显示文件写入仓库的(状态条)百分比例。
再往右,是文件已写入的(数字格式)百分比。

特点:

  • 字节为单位时,没有小数位
  • MiB或GiB位单位时,精确到小数点后两位数值
  • 当文件超过1G时,最右边不仅显示百分百,还显示预估的剩余时间,以01m06s这样的格式
  • 进度条的容量不是100个’=’,而是加上其它字符,可以填满整个一行。

设计方法:

首先,可以通过ioctl获取终端的行和列,此处我们只取列即可。
最右边的字符宽度是可以确定的,整个列数也是可以确定的,最左边虽然是动态的(数值变化),但是可以在sprintf打印入Buffer时,获取到实际宽度。因此,左、中、右的字符宽度都可以计算出来。 字符个数也是可以确定的。那么剩下就是计算数值。
数值很好计算,文件总大小是固定的,写入多少文件也是可以读取到的,中间的进度条,按照百分比,乘以进度条满格时总的字符数量,即可打印出一个完整的进度条。

c++ 代码实现:

bool add_file(const char * filepath)
{
				if (false == is_file_exist(filepath)) {
					cout << "please source file exist!" << endl;
					return false;
				}

				int64_t total_size = file_size(filepath);
				if (-1 == total_size) {
					return false;
				}
				size_t slices_cnt = total_size / block_unit;
				size_t free = total_size % block_unit;
				size_t all_slices_count = slices_cnt;
				if (free) {
					all_slices_count += 1;
				}
				//生成links文件名,json文件
				string list_name = get_sha1_value(filepath);

				//打开源文件
				int fd = open(filepath, O_RDONLY);
				if (-1 == fd) {
					perror("open links file error");
				}

				// 进度条
				const char *lable = "|/-\\";
				int64_t w_bytes = 0;				
				char buffer[512] = {0};
				char bar[512] = {0};
				int64_t percent = 0;
				fflush(stdout);
				struct winsize win_size, kk;
				auto get_win_size = [& win_size] (void) {					
					ioctl(STDIN_FILENO,TIOCGWINSZ,&win_size);					
					return true;
				};
				get_win_size();
				//cout << " 写文件切片到ipfs对应仓库,生成links文件(objects链表,json格式)" << endl;

				bool flag_run = true;
				size_t object_cursor = 0, list_index = 0;

				cout << "added " << list_name << " " << basename(filepath) << endl;
				unsigned char * buf = new unsigned char[block_unit]();
				while (flag_run) {
					//...
					while (flag_run) {
						size_t ret = read_file(fd, buf, block_unit);
						if (ret <= 0) {
							flag_run = false;
							//cout << "????????filepath=" << filepath << "size" << ret << endl;
							break;
						}
						sha1 = get_sha1_value(buf, ret);
						// ...
						
						//写block到ipfs仓库
						string object_path = lookup_object_directory(sha1) + "/" + sha1;
						int fd_obj = open_file(object_path.c_str(), 666);
						if (fd_obj == -1) {
							perror("open block file failed!");
							flag_run = false;
							cout << "object_path : " << object_path << endl;
						}
						write_file(fd_obj, buf, ret);
						close(fd_obj);
						//cout << "write " << ret << "byte data to" << object_path << endl;
						w_bytes += ret;

						object_cursor++;
						if (! (object_cursor % 0xff)) {						
							break;
						}
					} 
					
					//...
					list_index++;

					// 进度条控制
					{
						int64_t fenmu_zhengshu, fenmu_xiaoshu;
						int64_t fenzi_zhengshu, fenzi_xiaoshu;
						const char * p_unit;

						percent = w_bytes * 100 / total_size;
						percent %= 101;
						memset(bar, '-', 100);
						memset(bar, '=', percent);
						//memset(bar + percent, '-', percent);
						bar[100] = '\0';
						
						if (total_size >= 1024 * 1024 *1024) {
							p_unit = "GiB";
							fenzi_zhengshu = w_bytes / 1024 / 1024 / 1024;
							fenzi_xiaoshu = w_bytes % (1024 * 1024 * 1024) / (1024 * 1024) / 10;
							fenmu_zhengshu = total_size / 1024 / 1024 / 1024;
							fenmu_xiaoshu = total_size % (1024 * 1024 * 1024) / (1024 * 1024) / 10;

							int ret = sprintf(buffer, " %ld.%02ld %s / %ld.%02ld %s ", 
								fenzi_zhengshu, fenzi_xiaoshu, p_unit,
								fenmu_zhengshu, fenmu_xiaoshu, p_unit);
							int per = win_size.ws_col - ret - 10;
							bar[per] = '\0';
							memset(bar, '-', per);
							memset(bar, '=', percent * per / 100);
							sprintf(buffer + ret, "[%-*s] %3ld%%[%c]\r",
								per, bar, percent, lable[percent%4]);							
						}
						else if (total_size >= 1024 * 1024) {
							p_unit = "MiB";

							fenzi_zhengshu = w_bytes / 1024 / 1024;
							fenzi_xiaoshu = w_bytes % (1024 * 1024) / 1024 / 10;
							fenzi_xiaoshu /= 1024;

							fenmu_zhengshu = total_size / 1024 / 1024;
							fenmu_xiaoshu = total_size % (1024 * 1024 ) / 1024 / 10;
							fenmu_xiaoshu /= 1024;


							int ret = sprintf(buffer, " %ld.%02ld %s / %ld.%02ld %s ", 
								fenzi_zhengshu, fenzi_xiaoshu, p_unit, fenmu_zhengshu, fenmu_xiaoshu, p_unit);
							int per = win_size.ws_col - ret - 10;
							bar[per] = '\0';
							memset(bar, '-', per);
							memset(bar, '=', percent * per / 100);
							sprintf(buffer + ret, "[%-*s] %3ld%%[%c]\r",
								per, bar, percent, lable[percent%4]);
							
						}
						else {
							p_unit = " B";
							fenzi_zhengshu = w_bytes;
							fenmu_zhengshu = total_size;

							int ret1 = sprintf(buffer, " %ld %s / %ld %s ", 
								fenzi_zhengshu, p_unit, fenmu_zhengshu, p_unit);
							int per = win_size.ws_col - ret1 - 10;							
							bar[per] = '\0';
							memset(bar, '-', per);
							memset(bar, '=', percent * per / 100);						
							sprintf(buffer + ret1,  "[%-*s] %3ld%%[%c]\r",
								per, bar, percent, lable[percent%4]);
						}
					
						printf("%s", buffer);
						fflush(stdout);
					}
				}
				cout << endl;
				fflush(stdout);
				//cout << "w_bytes: " << w_bytes << endl;
				// 写文件到仓库目录
				//...
				delete buf;
				close(fd);
				return true;
			}

c++版本进度条效果:

[root@node1 build]# ./bin/ipfs --add main.cc 

added d1978dd8e880118c7177b26e2dc381517b85abe0  main.cc
 927  B / 927  B [====================================================================================================================================] 100%[|]
[root@node1 build]# 
[root@node1 build]# ./bin/ipfs --add /root/git.tar.bz2 

added bc41f0e189b5453a6ef1a6c64826fca0a3872835  git.tar.bz2
 133.00 MiB / 133.00 MiB [============================================================================================================================] 100%[|]
[root@node1 build]# ./bin/ipfs --add test 

added 91d50642dd930e9542c39d36f0516d45f4e1af0d  test
 2.00 GiB / 2.00 GiB [================================================================================================================================] 100%[|]
[root@node1 build]#

注意:
golang版本的哈希值是用sha256()生成的,其中Qm,Q代表是字符串类型为id,m代表id是使用base64编码。 既然做的不是与golang社区版本兼容的,即可不用插入Qm,看项目开发进度添加其它头即可,比如某知名p2p下载软件公司的存储项目,就是扩展了ipfs的编码格式。

ipfs白皮书定义的数据编码格式为:

multibase自描述基编码
multibase 代表的是一种编码格式, 方便把数据编码成不同的格式, 比如这里定义了2进制、8进制、10进制、16进制、也有我们熟悉的 base58btc 和 base64 编码。

支持的编码格式如下:

Multibase Table v1.0.0-RC (semver)

encoding      codes   name
identity      0x00    8-bit binary (encoder and decoder keeps data unmodified)
base1         1       unary tends to be 11111
base2         0       binary has 1 and 0
base8         7       highest char in octal
base10        9       highest char in decimal
base16        F, f    highest char in hex
base32        B, b    rfc4648 - no padding - highest letter
base32pad     C, c    rfc4648 - with padding
base32hex     V, v    rfc4648 - no padding - highest char
base32hexpad  T, t    rfc4648 - with padding
base32z       h       z-base-32 - used by Tahoe-LAFS - highest letter
base58flickr  Z       highest char
base58btc     z       highest char
base64        m       rfc4648 - no padding
base64pad     M       rfc4648 - with padding - MIME encoding
base64url     u       rfc4648 - no padding
base64urlpad  U       rfc4648 - with padding
发布了61 篇原创文章 · 获赞 63 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/jacky128256/article/details/101689477