0%

最近学了CMakeList,将所有学到的知识弄到了一个文件中

阅读全文 »

迟到的2023总结,拖了好久,年也过完了,有时间才来写点,再拖下去就要忘记了。23年算是个非常有意义的一年吧。

阅读全文 »


title: “Docker入门”
author:
- imshixin
keywords: [Docker]
abstract: “docker入门”

[toc]

Docker安装

Docker仅在linux内核3.08及以上版本运行,使用uname -a检查当前linux系统内核版本

ubuntu安装教程可参考这篇文章

centos7可参考这篇文章

使用下面这个命令检查是否安装成果

1
sudo docker info

替换默认镜像源

1
echo "{"registry-mirrors":["https://docker.mirrors.ustc.edu.cn"]}" >> /etc/docker/daemon.json

将该命令执行可以更换docker镜像源,提高pull速度

Docker 镜像操作

搜索镜像

1
sudo docker search [image]

添加--limit n限制显示条目为n条

比如输入sudo docker search ubuntu

1
2
3
4
5
6
[root@localhost ~]# docker search ubuntu
#名称([用户名/]仓库名) 描述 星数(好评数) 是否官方提供 是否自动构建
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating sys… 13629 [OK]
dorowu/ubuntu-desktop-lxde-vnc Docker image to provide HTML5 VNC interface … 605 [OK]
.......

查看镜像的不同TAG

打开Docker Hub,搜索想查找的仓库,点开Tag页面便可看到该仓库源的所有TAG

我知道的目前只有这样子了

下载镜像

1
docker pull [OPTIONS] NAME[:TAG|@DIGEST]

参数:

  • -a 下载该仓库的所有镜像(原文:Download all tagged images in the repository)
  • -q 静默下载

例如拉取ubuntu:16.10,:后面的内容代表版本,也称为标签,不写的话默认会是latest,代表最新版本

1
sudo docker pull ubuntu:16.10

查看下载的镜像

1
sudo docker images [OPTIONS] [REPOSITORY[:TAG]]

使用-q参数让该命令只输出镜像id

删除镜像

1
docker rmi [OPTIONS] IMAGE [IMAGE...]

使用-f强制删除镜像

若想要删除所有镜像,可使用

1
sudo docker rmi `docker images -q`

Docker容器使用

启动一个容器

使用如下命令运行一个容器

1
sudo docker run [options] [image:tag] [command]

image[:tag]代表想要运行的镜像名 command代表启动容器后要运行的命令

若本地没有所需镜像,docker会自动从docker hub上拉取

常用参数有

  • -t 为该容器分配一个伪终端(tty),与-i搭配使用

  • -i 保持该容器的标准输入stdin打开,与-t搭配使用

  • -d 使该容器在后台运行,并返回一个容器id

  • –name 为容器分配一个名称,不指定本参数docker将会随机生成一个

  • -p 指定端口转发

    • -p 80 将容器的80端口随机绑定(映射)到主机端口
    • -p 8080:80 将容器的80端口映射到主机的8080端口
    • -p ip:hostPort 将容器的端口绑定到主机指定的ip和一个随机端口
    • -p ip:hostPort:conPort 将容器conPort绑定的主机的ip:hostPort
  • -P 将容器内部开放的所有端口随机分配到主机端口

    内部开放指构建时Dockerfile文件中EXPOSE的所有端口

启动一个Ubuntu16.10容器命名为hello并进入

1
2
3
[root@localhost ~]# docker run -it --name hello ubuntu:16.10 /bin/bash
root@c8e790d88ca0:/#

可以看到主机名变成了容器idc8e790d88ca0

执行命令后进入容器终端,exit退出终端后容器也会随之停止

启动一个nginx容器开放80端口并后台运行

1
sudo docker run -d --name static_web  -p 80 nginx /bin/sh -c 'nginx daemon off;'

让容器自动重启

通过在启动容器时添加--restart参数使容器停止时自动重启,--restart=always会让容器停止时始终自动重启,--restart=on-failure:5可让容器退出码非0时重启至多5次

重启并进入容器

容器执行完命令后,将会自动停止,如果我们想再次启动,可以使用下面的命令重启:

1
sudo docker start [OPTIONS] CONTAINER [CONTAINER...]

重启时的容器会再次执行docker run中使用的命令,对hello容器而言就是/bin/bash

若想要重启后进入容器,可添加-a参数进入容器的命令提示符

附加到容器

容器重启后,并不会直接进入容器,需要执行额外命令进入容器

1
sudo docker attach [OPTIONS] CONTAINER

同样的,在退出容器shell后,容器将会停止

如何进入容器终端并退出容器后不让容器停止呢

执行容器命令

我们可以使用exec命令让指定容器执行命令:

1
sudo docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

该命令与docker run具有类似用法,使用docker exec -it CONTAINER /bin/bash进入容器命令提示符,也可添加-d参数来后台执行命令

通过该命令进入容器的shell退出后,容器并不会停止,因此,更推荐用这个命令进入容器

打印容器的输出

若想要查看容器输出了什么东西,或者容器异常停止,想要查看报错信息:

1
sudo docker logs [OPTIONS] CONTAINER

参数:

  • -f 持续性的输出容器内容,类似tail -f
  • -n 仅输出最后n行内容,类似tail命令
  • -t 显示时间戳

查看容器内的进程

可以通过sudo docker exec -it CONTAINER /bin/bash进入容器后使用top之类的程序查看容器进程,也可以:

1
sudo docker top CONTAINER

打印容器信息

获取容器的更多配置信息:

1
sudo docker inspect [OPTIONS] NAME|ID [NAME|ID...]

Docker容器管理

查看正在运行的容器

执行以下命令显示正在运行的命令

1
sudo docker ps [OPTIONS]

参数:

  • -a 显示所有容器,包括已停止的容器
  • -l 仅显示最近创建的容器
  • -q 仅输出容器的id
  • -s 显示容器文件大小
1
2
3
4
5
[root@localhost ~]# docker ps
#容器id 使用的镜像 启动命令 创建时间 当前状态 映射端口 名字
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c8e790d88ca0 ubuntu:16.10 "/bin/bash" 3 hours ago Up 24 seconds hello

停止正在运行的容器

1
docker stop [OPTIONS] CONTAINER [CONTAINER...]

参数:-t 发送停止命令后等待的最大秒数,默认为10秒

删除已停止的容器

想要删除容器时:

1
docker rm [OPTIONS] CONTAINER [CONTAINER...]

参数:

  • -f 强制删除一个正在运行的容器
  • -l 移除特殊链接
  • -v 移除任何相关联的卷

删除所有容器:

1
sudo docker rm `docker ps -aq`

DockerHub以及镜像构建

Docker Hub:https://hub.docker.com/

注册docker hub 后,使用如下命令登录

1
sudo docker login

构建并上传镜像

当我们对容器做出修改,想要打包上传修改好的镜像时,可以使用(不推荐)

1
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

参数:

  • -a 作者
  • -m 修改信息
  • -p [true|false] 上传时暂定容器(默认为true)

例如,用sudo docker commit hello yuy/hello将hello容器上传到yuy用户下的hello仓库中,且当前TAG为latest

用Dockerfile构建镜像

新建一个目录,记为工作目录,进去新建一个文件,名为Dockerfile

1
2
3
[root@localhost doc]# mkdir static__web
[root@localhost doc]# cd static__web/
[root@localhost static__web]# touch Dockerfile

编辑这个文件

1
2
3
4
5
6
FROM ubuntu:16.10
MAINTAINER imshixin "imsixn@163.com"
RUN apt-get update
RUN apt-get install -y nginx
RUN echo "HI,Iam in your container"> /usr/share/nginx/html/index.html
EXPOSE 80

各命令解释,Docker大致按如下流程执行

FROM 指定一个基础镜像,docker 生成一个此镜像的容器

MAINTAINER 此镜像的拥有者以及邮箱

RUN 在上一步生成的容器中执行RUN后面命令,并生成一个镜像,用该镜像运行新的容器,指令将会用/bin/sh -c包裹,使用RUN ["apt-get","install","-y","nginx"]将不会用shell包裹,因此RUN有两种写法

  • RUN COMMAND
  • RUN [COMMAND,...]

EXPOSE 期望暴露的端口,需要在docker run -p时指定要暴露的端口才会真正暴露,docker run -P将会把dockerfile中所有期望暴露的端口随机绑定到主机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@localhost static__web]# docker build -t imshixin/static__web .
Sending build context to Docker daemon 2.048kB
Step 1/6 : FROM ubuntu:14.04
---> 13b66b487594
Step 2/6 : MAINTAINER imshixin "imsixn@163.com"
---> Running in 82f37e087a04
Removing intermediate container 82f37e087a04
---> 06a2474f3b21
Step 3/6 : RUN apt-get update
---> Running in 347a2af628a6
..................
Removing intermediate container 347a2af628a6
---> b57319d185a8
Step 4/6 : RUN apt-get install -yq nginx
---> Running in c32f24d86396
................
Removing intermediate container c32f24d86396
---> 1f4158f33caa
Step 5/6 : RUN echo "HI..." >>/usr/share/nginx/html/index.html
---> Running in 18fa23d03804
Removing intermediate container 18fa23d03804
---> 07f321aed70e
Step 6/6 : EXPOSE 80
---> Running in 2b189d5fef76
Removing intermediate container 2b189d5fef76
---> 0ad1c8959552
Successfully built 0ad1c8959552
Successfully tagged imshixin/static__web:latest

Mysql安装

参考这个https://www.runoob.com/mysql/mysql-install.html
安装完成后会有一个root自动生成的密码,复制下来

Mysqld管理

Windows下启动mysqld

1
2

net start mysqld

Linux下启动MySQL服务

检查MySQL服务器是否启动

1
2

ps -ed |grep mysqld

启动服务:

1
2
3

cd /usr/bin
./mysqld_safe &

mysql 管理

登录mysql

在已添加环境目录条件下,直接打开命令行窗口

1
2

mysql -u root -p

输入安装时生成的密码,第一次使用需要修改root密码

1
2

alter user 'root'@'localhost' identified by '新密码';

添加用户

在root用户下,添加用户的方法
一种是权限账号分别赋予的方式

1
2
3
4
5

grant usage on [db].[table] to '[username]'@'[host]' identified by '[password]' with grant option;
grant select,update on *.* to '[username]'@'[host]';
grant insert on *.* to '[username]'@'[host]';
flush privileges;

另一种就是将两个步骤结合:

1
2
3

grant [privileges] on [db].[table] to '[username]'@'[host]' identified by '[password]';
flush privileges;

说明:

  1. db: 赋予指定的数据库权限,*代表所有库
  2. table: 赋予指定的数据表权限,*代表所有表
  3. username:用户名
  4. host: 登录主机,%代表任意(192.168.1.%代表192.168.1.0-192.168.1.255,其他类推)
  5. password: 密码
  6. privileges:权限,多个用,隔开,可选如下
    • select
    • insert
    • update
    • delete
    • create
    • …….

注意:在注意需要执行 FLUSH PRIVILEGES 语句。 这个命令执行后会重新载入授权表。

如果不使用该命令,重启mysql服务器前无法使用新账号登录
####

其他命令

查看所有用户:select User,Host from mysql.user;

1
2
3
4
5
6
7
8
9
10
11
12

mysql> select User,Host from mysql.user;
+---------------+-----------+
| User | Host |
+---------------+-----------+
| imsixn | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
| shixin | localhost |
+---------------+-----------+
5 rows in set (0.00 sec)

选择数据库:use dbname;

1
2
3

mysql> use shixindb;
Database changed

查看当前使用的数据库:select database();

1
2
3
4
5
6
7
8

mysql> select database();
+------------+
| database() |
+------------+
| shixindb |
+------------+
1 row in set (0.00 sec)

显示所有数据库:show databases;

1
2
3
4
5
6
7
8
9
10

mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
....省略一部分
+--------------------+
5 rows in set (0.00 sec)

显示指定数据库中的所有表:show tables;

使用前需要用use指定数据库

1
2
3
4
5
6
7
8
9

mysql> show tables;
+--------------------+
| Tables_in_shixindb |
+--------------------+
| demo1 |
| emptb |
+--------------------+
2 rows in set (0.00 sec)

显示数据表结构:show columns from 数据表

选择数据表时可以用数据库.数据表,另外也可以用desc 数据表

1
2
3
4
5
6
7
8
9
10
11

mysql>desc shixindb.demo1;
...省略
mysql> show columns from shixindb.demo1;
+-----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+----------------+
| sx_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
...省略
+-----------+------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

mysql语法

创建数据库:create database 数据库名;

create database {if not exist} [dbname] {default character set [charset] collate [collate]}

  • if not exist:不存在该库时创建该库
  • dbname: 数据库名
  • default char…:设置默认编码集和检验方式
1
2
3

mysql> create database demo;
Query OK, 1 row affected (0.00 sec)

删除数据库:drop database 数据库名;

1
2
3

mysql> drop database demo;
Query OK, 0 rows affected (0.00 sec)

创建数据表:create table 表名

1
2

create table [tablename] (column_name column_type ,...)engine=InnoDB default charset=utf8

说明:

  • tablename:表名
  • cloumn_name:列名
  • column_type: 值类型
  • engine:数据库储存引擎,可省略
  • charset:编码集,可省略;
1
2
3
4
5
6
7
8
9
10
11
12
mysql> create table demoo(
-> stu_id int(11) not null auto_increment,
-> stu_name varchar(40) not null,
-> primary key (stu_id));
Query OK, 0 rows affected (0.03 sec)
mysql> show tables;
+--------------------+
| Tables_in_shixindb |
+--------------------+
| demoo |
+--------------------+
1 rows in set (0.00 sec)

primary key 指定主键

not null 指定该列所有值非空

auto_increment指定该值自动增加

删除数据表:drop table 表名;

删除数据表有两种方式

  • drop table 表名

    完全删除表,表的数据和表结构都将删除

  • truncate table 表名

    删除表中欧过的所有数据,自增的主键也会重新开始

delete from 表名也可以删除表中所有数据,但是它不会清楚计数,添加新行时,自增主键不会重新开始计数

插入数据:insert

insert into [tbname] (column1,column2,...) values (v1,v2,...);

自增主键可以省略

1
2
3

mysql> insert into demoo (stu_name) values ('李三');
Query OK, 1 row affected (0.01 sec)

如果所有的列都要添加数据可以不规定列进行添加数据(主键用0或者null代替):

1
2
3

mysql> insert into demoo values (null,'张四');
Query OK, 1 row affected (0.00 sec)

然后我们有了两个数据

1
2
3
4
5
6
7
8
9

mysql> select * from demoo;
+--------+----------+
| stu_id | stu_name |
+--------+----------+
| 1 | 李三 |
| 2 | 张四 |
+--------+----------+
2 rows in set (0.00 sec)

查询数据:select * from 表名;

1
2
3
4
5

SELECT column_name,column_name
FROM table_name
[WHERE Clause]
[LIMIT N][ OFFSET M] [GROUP BY O][having G][order by Q]
  • SELECT 命令可以读取一条或者多条记录。
  • 使用星号(*)来代替其他字段,SELECT语句会返回表的所有字段数据
  • 使用 WHERE 语句来包含任何条件。可省略
  • 使用 LIMIT 属性来设定返回的记录数。可省略
  • 通过OFFSET指定SELECT语句开始查询的数据偏移量。默认情况下偏移量为0。可省略
  • 通过group by 进行分组
  • having用于对where和group by查询出来的分组经行过滤,查出满足条件的分组结果。它是一个过滤声明,是在查询返回结果集以后对查询结果进行的过滤操作。
  • order by 进行排序
1
2
3
4
5
6
7
8

mysql> select stu_id,stu_name from demoo where stu_id=1 limit 1 offset 0;
+--------+----------+
| stu_id | stu_name |
+--------+----------+
| 1 | 李三 |
+--------+----------+
1 row in set (0.01 sec)
where子句

可以用=,>,<,>=,<=,!=或<>分别代表等于,大于,小于,大于等于,小于等于,不等:

1
2
3
4
5
6
7
8

mysql> select * from demoo where stu_id >1;
+--------+----------+
| stu_id | stu_name |
+--------+----------+
| 2 | 张四 |
+--------+----------+
1 row in set (0.00 sec)

and or拼接多个条件:

1
2
3
4
5
6
7
8

mysql> select * from demoo where stu_id >1 or stu_id != 1;
+--------+----------+
| stu_id | stu_name |
+--------+----------+
| 2 | 张四 |
+--------+----------+
1 row in set (0.00 sec)

更新数据:update tbname set field1=value1...;

1
2
3

UPDATE table_name SET field1=new-value1, field2=new-value2
[WHERE Clause]

不加where的话,表中所有的数据都将被替换

将某一值改回默认值:update tbname set field=default where ...

1
2
3
4
5
6
7
8
9
10
11
12

mysql> update demoo set stu_name='李四' where stu_id=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from demoo;
+--------+----------+
| stu_id | stu_name |
+--------+----------+
| 1 | 李三 |
| 2 | 李四 |
+--------+----------+
2 rows in set (0.00 sec)

删除某行数据:delete from tbname [where];

不写where条件的话,将会删除所有数据

删除某一项后,主键计数不会改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

mysql> delete from demoo where stu_id=2;
Query OK, 1 row affected (0.00 sec)

mysql> insert into demoo values(null,'王二');
Query OK, 1 row affected (0.00 sec)

mysql> select * from demoo;
+--------+----------+
| stu_id | stu_name |
+--------+----------+
| 1 | 李三 |
| 3 | 王二 |
+--------+----------+
2 rows in set (0.00 sec)

LIKE 子句

举例:

  • show variables like 'character%':

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    mysql> show variables like 'character%';
    +--------------------------+------------------------------------------------------+
    | Variable_name | Value |
    +--------------------------+------------------------------------------------------+
    | character_set_client | utf8 |
    | character_set_connection | utf8 |
    ...
    +--------------------------+------------------------------------------------------+
    8 rows in set, 1 warning (0.00 sec)
  • select * from demoo where stu_name like '李%':

%类似于通配符*,表示任意 0 个或多个字符。可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示。

_表示任意单个字符。匹配单个任意字符,它常用来限制表达式的字符长度语句。

[]表示括号内所列字符中的一个(类似正则表达式)。指定一个字符、字符串或范围,要求所匹配对象为它们中的任一个。

[^] 表示不在括号所列之内的单个字符。其取值和 [] 相同,但它要求所匹配对象为指定字符以外的任一个字符。

查询内容包含通配符时,由于通配符的缘故,导致我们查询特殊字符 “%”、“_”、“[” 的语句无法正常实现,而把特殊字符用 “[ ]” 括起便可正常查询。

按字符结合顺序讲,[]的优先级大于*

所以int *p[]等于int *(p[])

(int *)(p[]) 就是一个指针数组,就是一个数组,里面存放的是指针

int (*p)[]表示p是一个指针,指向一个有n个int值的数组

引用一下runoob的话

指针数组

int *a[3]:为什么这里是指针数组,[] 的优先级高于 * ,所以这是一个数组,而 * 修饰数组,所以是指针数组,数组的元素是整型的指针。

示例:

1
2
3
4
5
6
7
8
9
int main() {   
char *str[3];
str[0] = "abc";
str[1] = "efg";
str[2] = "hij";
for (int i = 0; i < 3; ++i) {
printf("%s\n", str[i]);
}
}

结果:

1
2
3
abc 
efg
hij

数组指针

int (*a)[3]:同样的方式,首先括号的优先级最高,所以 *a 是指针,而 [] 修饰 *a ,所以是数组指针,一个指向 3 个元素的一维数组指针。

示例:

1
2
3
4
5
6
7
8
9
10
typedef int arr[3]; 
int main() {
arr b = {1, 2, 3};
int (*a)[3] = &b;
arr *c = a;
for (int i = 0; i < 3; ++i) {
printf("%d\n", (*a)[i]);

}
}

结果:

1
2
3
1 
2
3

突然找到一篇比较好理解的文章,保存在这里

https://www.cnblogs.com/llanse-xianchengduo/p/10960431.html

学smail去反编译分析代码?(别干坏事)

语法

基本数据类型

类型关键字 对应Java中的类型说明
V void,只能用于返回类型
Z boolean
B byte
S short
C char
I int
J long (64 bits)
F float
D double (64 bits)

注意了,布尔值对应的字母为Z,long对应的字母为J,其他的都是首字母大写

对象

Object类型,即引用类型的对象,在引用时,使用L开头,后面紧接着的是完整的包名,比如:java.lang.String对应的Smali语法则是 Ljava/lang/String

数组

数组定义比较有意思,一维数组在类型的左边加一个方括号,比如:[I等同于Java的 int[],每多一维就加一个方括号,[[I就等同于Java的int[][],最多可以设置255维

方法声明和调用

官方Wiki中给出的Smali引用方法的模板如下:
Lpackage/name/ObjectName;->MethodName(III)Z
第一部分 Lpackage/name/ObjectName;用于声明具体的类型,以便JVM寻找

第二部分 MethodName(III)Z,其中MethodName为具体的方法名,()中的字符,表示了参数数量和类型,即3个int型参数,Z为返回值的类型,即返回Boolean类型

由于方法的参数列表没有使用逗号这样的分隔符进行划分,所以只能从左到右,根据类型定义来区分参数个数,这一点需要比较仔细来观察

如果需要调用构造方法,则MethodName为:<init>

寄存器声明

在Smali中,如果需要存储变量,必须先声明足够数量的寄存器,1个寄存器可以存储32位长度的类型,比如Int,而两个寄存器可以存储64位长度类型的数据,比如Long或Double, String类型实际上是一个对象,只需要一个寄存器

声明可使用的寄存器数量的方式为:.registers N,N代表需要的寄存器的总个数

.registers 3表示声明3个寄存器

还有一个关键字 .locals,它用于声明非参数的寄存器个数(包含在registers声明的个数当中),也叫做本地寄存器,只在一个方法内有效,但不常用,一般使用registers即可

寄存器有两种命名方式,V命名方式和P命名方法。P命名方式中的第一个寄存器就是方法中的第一个参数寄存器,在非static方法中有个this指针需要一个寄存器,一般为p0,则p1为第一个参数,依次类推,v0,v1,…为自己定义的本地寄存器

1
2
3
4
5
6
.method static test(I)V
.registers 1 # 声明总共需要使用1个寄存器

const-string v0, "LOG" # 将v0寄存器赋值为字符串常量"LOG"
return-void
.end method

再举例,如果一个Java方法声明如下:myMethod(int p1, float p2, boolean p3)Z

那么对应的Smali则为:method LMyObject;->myMethod(IJZ)V
此时,寄存器的对应情况如下:

寄存器名称 对应的引用
p0 this
p1 int型的p1参数
p2, p3 float型的p2参数
p4 boolean型的p3参数

那么最少需要的寄存器个数则为:5

指令集

1. 赋值

指令 说明
move v1,v2 将v2中的值移入到v1寄存器中(4位,支持int型)
move/from16 v1,v2 将16位的v2寄存器中的值移入到8位的v1寄存器中
move/16 v1,v2 将16位的v2寄存器中的值移入到16位的v1寄存器中
move-wide v1,v2 将寄存器对(一组,用于支持双字型)v2中的值移入到v1寄存器对中(4位,猜测支持float、double型)
move-wide/from16 v1,v2 将16位的v2寄存器对(一组)中的值移入到8位的v1寄存器中
move-wide/16 v1,v2 将16位的v2寄存器对(一组)中的值移入到16位的v1寄存器中
move-object v1,v2 将v2中的对象指针移入到v1寄存器中
move-object/from16 v1,v2 将16位的v2寄存器中的对象指针移入到v1(8位)寄存器中
move-object/16 v1,v2 将16位的v2寄存器中的对象指针移入到v1(16位)寄存器中
move-result v1 将这个指令的上一条指令计算结果(方法的话就是返回值),移入到v1寄存器中(需要配合invoke-static、invoke-virtual等指令使用)
move-result-object v1 将上条计算结果的对象指针移入v1寄存器
move-result-wide v1 将上条计算结果(双字)的对象指针移入v1寄存器
move-exception v1 将异常移入v1寄存器,用于捕获try-catch语句中的异常

2.返回值

指令 说明
return-void 返回void,即直接返回
return v1 返回v1寄存器中的值
return-object v1 返回v1寄存器中的对象指针
return-wide v1 返回双字型结果给v1寄存器

3.常量操作

指令 说明
const(/4、/16、/hight16) v1 xxx 将常量xxx赋值给v1寄存器,/后的类型,需要根据xxx的长度选择
const-wide(/16、/32、/hight16) v1 xxx 将双字型常量xxx赋值给v1寄存器,/后的类型,需要根据xxx的长度选择
const-string(/jumbo) v1 “aaa” 将字符串常量”aaa”赋给v1寄存器,过长时需要加上jumbo
const-class v1 La/b/TargetClass 将Class常量a.b.TargetClass赋值给v1,等价于a.b.TargetClass.class

4. 方法调用

指令 说明
invoke-virtual 用于调用一般的,非private、非static、非final、非构造函数的方法,它的第一个参数往往会传p0,也就是this指针
invoke-super 用于调用父类中的方法,其他和invoke-virtual保持一致
invoke-direct 用于调用private修饰的方法,或者构造方法
invoke-static 用于调用静态方法,比如一些工具类
invoke-interface 用于调用interface中的方法

5.if语句

模板是 if-[test] v0,v1 [condition],test如下,condition为条件满足后的语句,一般会是跳转,另外需要注意的是,Java判断和smail判断一般是相反的

if-le v0, v1, :cond_7翻译过来就是 if(v0<=v1):{:cond_7}

if-ez v0 :cond_4翻译过来是 if(v0==0){:cond_4}

指令 说明
if-eq v1,v2 判断两个寄存器中的值是否相等
if-ne v1,v2 判断两个寄存器中的值是否不相等
if-lt v1,v2 判断v1寄存器中的值是否小于v2寄存器中的值(lt == less than)
if-ge v1,v2 判断v1寄存器中的值是否大于或等于v2寄存器中的值(ge == great than or equals)
if-gt v1,v2 判断v1寄存器中的值是否大于v2寄存器中的值(gt == great than)
if-le v1,v2 判断v1寄存器中的值是否小于或等于v2寄存器中的值(le == less than or equals)

if-ez v1 表示 if(v1==0),其他的 nez,ltz,gtz,lez等等都是与零比较(z= zero)

6.取值赋值

属性操作的分为:取值(get)和赋值(put)

目标类型分为:数组(array)、实例(instance)和静态(static)三种,对应的缩写前缀就是a、i、s

长度类型分为:默认(什么都不写)、wide(宽,64位)object(对象)booleanbytecharshort(后面几种就不解释了,和Java一致)

指令格式:[指令名] [源寄存器], [目标字段所在对象寄存器], [字段指针] 例如 int mIntA = 100 :

1
2
const/4 v0, 0x64
iput v0, p0, Lcom/coderyuan/smali/MainActivity;->mIntA:I

以下是一些指令

指令 说明
iget 取值,用于操作int这种的值类型
iget-wide 取值,用于操作wide型字段
iget-object 取值,用于操作对象引用
iget-boolean 取值,用于操作布尔类型
iget-byte 取值,用于操作字节类型
iget-char 取值,用于操作字符类型
iget-short 取值,用于操作short类型
iput 赋值,用于操作int这种的值类型
iput-wide 赋值,用于操作wide型字段
iput-object 赋值,用于操作对象引用
iput-boolean 赋值,用于操作布尔类型
iput-byte 赋值,用于操作字节类型
iput-char 赋值,用于操作字符类型
iput-short 赋值,用于操作short类型

例如

1
2
3
4
5
6
7
8
9
10
11
private String mStringA;
private int mIntA;
private Activity mActivityA;

public void fieldTest() {
mStringA = "Put String to mStringA";
mIntA = 100;
mActivityA = this;

int len = mStringA.length();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# instance fields
.field private mActivityA:Landroid/app/Activity;

.field private mIntA:I

.field private mStringA:Ljava/lang/String;

# virtual methods
.method public fieldTest()V
.registers 2

.line 55
const-string v0, "Put String to mStringA"

iput-object v0, p0, Lcom/coderyuan/smali/MainActivity;->mStringA:Ljava/lang/String;

.line 56
const/16 v0, 0x64

iput v0, p0, Lcom/coderyuan/smali/MainActivity;->mIntA:I

.line 57
iput-object p0, p0, Lcom/coderyuan/smali/MainActivity;->mActivityA:Landroid/app/Activity;

.line 59
iget-object v0, p0, Lcom/coderyuan/smali/MainActivity;->mStringA:Ljava/lang/String;

invoke-virtual {v0}, Ljava/lang/String;->length()I

move-result v0

.line 60
.local v0, "len":I
return-void
.end method

引用自这里

小图标显示问题

链接上一篇Zeal文档下载

自己下载的文档默认是没有小图标的

由于 zeal 的搜索功能是全局搜索,不同文档的相同功能名称在搜索下无法分辨(虽说可以加前缀),给文档添加小图标还是有必要的

在上篇文章中的 JSON 中,我提到了 icon 和 icon2x ,在这里便可以用上

下载 zeal.json>,把 zeal.json 放到 docsets 目录下,并在该目录下新建文件 zeal.py 写入如下内容

保存后执行,显示这个即可

此外,CSS 文档还有个坑

就像这样

解决办法:

找到 zeal安装目录\docsets\CSS.docset\Contents\Resources\Documents\developer.mozilla.org\static\build\js

删除 react-main.xxxxxxx.js(xxxx 是一串数字),??

Zeal 安装使用

1.介绍

Zeal 是一款离线文档浏览器,其灵感来自 OS X 平台上的 Dash,目前支持 Window 和 Liunx。基于 QT5。

  1. 支持呼出热键。只要按下组合箭 ALT+Space 即可在任何地方显示面板,不用时可以用热键隐藏的系统托盘。
  2. 可同时搜索多个文档
  3. 不依赖网络
  4. GPL 协议开放源码
  5. Dash 中的文档都可以在 Zeal 中使用

1.安装

>>>官网下载链接

Zeal 支持 Windows,Mac,Linux 三系统(啊,来自 Linux 系统的福音)

2.使用

首次打开 zeal,软件没有任何文档,需要自己去下载

菜单栏 >Tools>Docsets... 再点击 Available,显示如下(啥都没有等一会,再没有就点 Refresh 继续等)

双击你想要的文档或点击下方的 Download 即可下载

但是,问题来了,下载贼慢不说,下到一半网络链接超时又重新开始下载!!

文档下载

文章内版本更新于 2020 年 8 月 5 日

以下是每个文档的下载地址,复制链接到下载器下载好,下载好后将压缩包里的 XXX.docsets 解压到安装目录下的 docsets 文件夹里

查看详细

| 文档名 | 版本 | 下载链接 | 文档大小
| —- | —- | —- |
| ActionScript | 27 | 点击下载 | 73.64MB |
| Akka | 0 | 点击下载 | 26.64MB |
| Android | 0 | 点击下载 | 933.59MB |
| Angular | 0 | 点击下载 | 28.30MB |
| AngularJS | 0 | 点击下载 | 2.96MB |
| Ansible | 0 | 点击下载 | 35.28MB |
| Apache HTTP Server | 0 | 点击下载 | 2.81MB |
| Appcelerator Titanium | 0 | 点击下载 | 60.11MB |
| AppleScript | 4 | 点击下载 | 47.82MB |
| Arduino | 0 | 点击下载 | 135.30MB |
| AWS JavaScript | 0 | 点击下载 | 11.51MB |
| BackboneJS | 0 | 点击下载 | 5.86MB |
| Bash | 6 | 点击下载 | 0.58MB |
| Boost | 0 | 点击下载 | 167.71MB |
| Bootstrap 2 | 3 | 点击下载 | 3.04MB |
| Bootstrap 3 | 0 | 点击下载 | 2.69MB |
| Bootstrap 4 | 0 | 点击下载 | 1.81MB |
| Bourbon | 0 | 点击下载 | 0.04MB |
| C | 57 | 点击下载 | 118.49MB |
| C++ | 63 | 点击下载 | 120.54MB |
| CakePHP | 0 | 点击下载 | 15.15MB |
| Cappuccino | 0 | 点击下载 | 16.88MB |
| Chai | 0 | 点击下载 | 0.47MB |
| Chef | 0 | 点击下载 | 13.06MB |
| Clojure | 13 | 点击下载 | 3.05MB |
| CMake | 0 | 点击下载 | 6.17MB |
| Cocos2D | 0 | 点击下载 | 1.32MB |
| Cocos2D-X | 0 | 点击下载 | 11.00MB |
| Cocos3D | 0 | 点击下载 | 3.39MB |
| CodeIgniter | 0 | 点击下载 | 8.31MB |
| CoffeeScript | 0 | 点击下载 | 2.66MB |
| ColdFusion | 3 | 点击下载 | 107.50MB |
| Common Lisp | 2 | 点击下载 | 4.31MB |
| Compass | 0 | 点击下载 | 0.60MB |
| Cordova | 0 | 点击下载 | 5.80MB |
| Corona | 0 | 点击下载 | 4.87MB |
| CouchDB | 0 | 点击下载 | 9.08MB |
| Craft | 0 | 点击下载 | 13.74MB |
| CSS | 96 | 点击下载 | 58.43MB |
| D3JS | 0 | 点击下载 | 21.70MB |
| Dart | 0 | 点击下载 | 15.16MB |
| Django | 0 | 点击下载 | 8.82MB |
| Docker | 0 | 点击下载 | 41.96MB |
| Doctrine | 0 | 点击下载 | 0.91MB |
| Dojo | 2 | 点击下载 | 18.84MB |
| Drupal 7 | 0 | 点击下载 | 172.10MB |
| Drupal 8 | 0 | 点击下载 | 647.11MB |
| ElasticSearch | 0 | 点击下载 | 44.73MB |
| Elixir | 0 | 点击下载 | 2.90MB |
| Emacs Lisp | 13 | 点击下载 | 2.62MB |
| EmberJS | 0 | 点击下载 | 39.36MB |
| Emmet | 3 | 点击下载 | 0.05MB |
| Erlang | 0 | 点击下载 | 36.08MB |
| Express | 2 | 点击下载 | 6.39MB |
| ExpressionEngine | 0 | 点击下载 | 11.36MB |
| ExtJS | 0 | 点击下载 | 160.78MB |
| Flask | 0 | 点击下载 | 1.45MB |
| Font Awesome | 0 | 点击下载 | 5.15MB |
| Foundation | 2 | 点击下载 | 6.00MB |
| GLib | 0 | 点击下载 | 0.98MB |
| Go | 0 | 点击下载 | 19.66MB |
| Gradle DSL | 0 | 点击下载 | 31.93MB |
| Gradle Java API | 0 | 点击下载 | 8.59MB |
| Gradle User Guide | 0 | 点击下载 | 31.92MB |
| Grails | 0 | 点击下载 | 8.77MB |
| Groovy | 0 | 点击下载 | 12.57MB |
| Groovy JDK | 0 | 点击下载 | 1.14MB |
| Grunt | 0 | 点击下载 | 1.08MB |
| Gulp | 0 | 点击下载 | 0.30MB |
| Haml | 2 | 点击下载 | 0.33MB |
| Handlebars | 0 | 点击下载 | 2.31MB |
| Haskell | 0 | 点击下载 | 15.45MB |
| HTML | 84 | 点击下载 | 77.42MB |
| Ionic | 0 | 点击下载 | 30.03MB |
| Jasmine | 0 | 点击下载 | 0.16MB |
| Java EE6 | 2 | 点击下载 | 9.27MB |
| Java EE7 | 3 | 点击下载 | 16.06MB |
| Java EE8 | 1 | 点击下载 | 17.18MB |
| Java SE10 | 3 | 点击下载 | 80.31MB |
| Java SE11 | 5 | 点击下载 | 57.94MB |
| Java SE12 | 2 | 点击下载 | 59.62MB |
| Java SE6 | 6 | 点击下载 | 43.17MB |
| Java SE7 | 11 | 点击下载 | 45.40MB |
| Java SE8 | 29 | 点击下载 | 52.45MB |
| Java SE9 | 3 | 点击下载 | 82.73MB |
| JavaFX | 18 | 点击下载 | 13.03MB |
| JavaScript | 87 | 点击下载 | 338.17MB |
| Jekyll | 0 | 点击下载 | 1.07MB |
| Jinja | 0 | 点击下载 | 0.80MB |
| Joomla | 0 | 点击下载 | 4.87MB |
| jQuery | 0 | 点击下载 | 24.35MB |
| jQuery Mobile | 0 | 点击下载 | 4.28MB |
| jQuery UI | 0 | 点击下载 | 41.79MB |
| Julia | 0 | 点击下载 | 4.07MB |
| KnockoutJS | 0 | 点击下载 | 0.65MB |
| Kobold2D | 0 | 点击下载 | 3.62MB |
| Laravel | 0 | 点击下载 | 8.02MB |
| LaTeX | 12 | 点击下载 | 1.33MB |
| Less | 0 | 点击下载 | 0.73MB |
| Lo-Dash | 0 | 点击下载 | 0.38MB |
| Lua 5.1 | 4 | 点击下载 | 0.33MB |
| Lua 5.2 | 4 | 点击下载 | 0.29MB |
| Lua 5.3 | 4 | 点击下载 | 0.21MB |
| MarionetteJS | 0 | 点击下载 | 0.52MB |
| Markdown | 2 | 点击下载 | 0.01MB |
| MatPlotLib | 0 | 点击下载 | 145.97MB |
| Meteor | 0 | 点击下载 | 4.57MB |
| Mocha | 0 | 点击下载 | 1.36MB |
| MomentJS | 0 | 点击下载 | 2.85MB |
| MongoDB | 0 | 点击下载 | 40.87MB |
| Mongoose | 0 | 点击下载 | 10.62MB |
| Mono | 6 | 点击下载 | 1846.38MB |
| MooTools | 0 | 点击下载 | 1.43MB |
| MySQL | 21 | 点击下载 | 13.53MB |
| Neat | 0 | 点击下载 | 0.26MB |
| NET Framework | 0 | 点击下载 | 455.09MB |
| Nginx | 0 | 点击下载 | 0.68MB |
| NodeJS | 0 | 点击下载 | 5.33MB |
| NumPy | 0 | 点击下载 | 11.95MB |
| OCaml | 0 | 点击下载 | 1.72MB |
| OpenCV | 0 | 点击下载 | 76.77MB |
| OpenGL 2 | 2 | 点击下载 | 1.00MB |
| OpenGL 3 | 2 | 点击下载 | 0.58MB |
| OpenGL 4 | 7 | 点击下载 | 1.45MB |
| Pandas | 0 | 点击下载 | 87.99MB |
| Perl | 0 | 点击下载 | 7.76MB |
| Phalcon | 0 | 点击下载 | 13.14MB |
| PhoneGap | 0 | 点击下载 | 56.11MB |
| PHP | 85 | 点击下载 | 67.56MB |
| PHPUnit | 0 | 点击下载 | 2.19MB |
| Play Java | 0 | 点击下载 | 2.29MB |
| Play Scala | 0 | 点击下载 | 9.07MB |
| Polymer.dart | 0 | 点击下载 | 1.15MB |
| PostgreSQL | 0 | 点击下载 | 3.77MB |
| Processing | 0 | 点击下载 | 4.26MB |
| PrototypeJS | 0 | 点击下载 | 1.87MB |
| Pug | 0 | 点击下载 | 1.70MB |
| Puppet | 0 | 点击下载 | 7.96MB |
| Python 2 | 0 | 点击下载 | 10.60MB |
| Python 3 | 0 | 点击下载 | 13.62MB |
| Qt 4 | 0 | 点击下载 | 64.73MB |
| Qt 5 | 0 | 点击下载 | 148.47MB |
| R | 0 | 点击下载 | 29.98MB |
| Racket | 0 | 点击下载 | 146.14MB |
| React | 0 | 点击下载 | 3.64MB |
| Redis | 0 | 点击下载 | 2.18MB |
| RequireJS | 0 | 点击下载 | 0.45MB |
| Ruby | 7 | 点击下载 | 58.37MB |
| Ruby 2 | 0 | 点击下载 | 45.91MB |
| Ruby on Rails 3 | 0 | 点击下载 | 6.90MB |
| Ruby on Rails 4 | 0 | 点击下载 | 5.94MB |
| Ruby on Rails 5 | 2 | 点击下载 | 7.93MB |
| Ruby on Rails 6 | 0 | 点击下载 | 32.74MB |
| RubyMotion | 3 | 点击下载 | 5.48MB |
| Rust | 0 | 点击下载 | 42.93MB |
| SailsJS | 0 | 点击下载 | 7.56MB |
| SaltStack | 0 | 点击下载 | 19.38MB |
| Sass | 0 | 点击下载 | 3.81MB |
| Scala | 0 | 点击下载 | 39.96MB |
| SciPy | 0 | 点击下载 | 21.89MB |
| Semantic UI | 0 | 点击下载 | 9.64MB |
| Sencha Touch | 0 | 点击下载 | 18.29MB |
| Sinon | 0 | 点击下载 | 0.21MB |
| Smarty | 0 | 点击下载 | 0.42MB |
| Sparrow | 0 | 点击下载 | 0.90MB |
| Spring Framework | 0 | 点击下载 | 35.43MB |
| SQLAlchemy | 0 | 点击下载 | 3.92MB |
| SQLite | 0 | 点击下载 | 9.31MB |
| Statamic | 0 | 点击下载 | 10.42MB |
| Stylus | 0 | 点击下载 | 0.59MB |
| Susy | 0 | 点击下载 | 0.48MB |
| SVG | 72 | 点击下载 | 21.03MB |
| Swift | 0 | 点击下载 | 5.82MB |
| Symfony | 0 | 点击下载 | 14.33MB |
| Tcl | 0 | 点击下载 | 1.71MB |
| Tornado | 0 | 点击下载 | 7.37MB |
| Twig | 0 | 点击下载 | 0.74MB |
| Twisted | 0 | 点击下载 | 15.44MB |
| TypeScript | 2 | 点击下载 | 4.90MB |
| TYPO3 | 0 | 点击下载 | 50.83MB |
| UnderscoreJS | 0 | 点击下载 | 0.54MB |
| Unity 3D | 0 | 点击下载 | 251.59MB |
| Vagrant | 0 | 点击下载 | 2.41MB |
| Vim | 0 | 点击下载 | 3.22MB |
| VMware vSphere | 0 | 点击下载 | 16.92MB |
| VueJS | 0 | 点击下载 | 5.59MB |
| WordPress | 77 | 点击下载 | 290.09MB |
| Xamarin | 3 | 点击下载 | 1103.36MB |
| Xojo | 0 | 点击下载 | 144.90MB |
| XSLT | 48 | 点击下载 | 5.98MB |
| Yii | 0 | 点击下载 | 15.52MB |
| YUI | 0 | 点击下载 | 14.24MB |
| Zend Framework 1 | 2 | 点击下载 | 26.40MB |
| Zend Framework 2 | 0 | 点击下载 | 18.53MB |
| Zend Framework 3 | 0 | 点击下载 | 20.60MB |
| ZeptoJS | 0 | 点击下载 | 0.32MB |

3.解析过程(可以不看)

通过 fiddler 抓包获得了 zeal 请求的文档列表数据(只列举两个)

http://api.zealdocs.org/v1/docsets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[{
"sourceId": "com.kapeli",
"name": "ActionScript",
"title": "ActionScript",
"versions": ["3"],
"revision": "27",
"icon": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABwElEQVR42pyTv07bUBTGf8dOAg1xSqmSAaSCMhGEHJkFCcTABKi4khkQL8AD8AY8AhMDQ4UYGJh4gbAhMTlAVXaQYEBQSqwEJXJzOrgyiTAt6pnu+XO/e77z3SOqSkVE+Q87U5VURUS/JiQrDw+kBgdj/8JxeDo97a0RUSMJ2ZieRiyrJybz84ldJALkFhYwTbMn9sHzkLcAGEB+ZeVFoeU4UCq9oYOpKYbKZQA6jQbtqysABnI5sq77b4Ah1yWdyQBwf3DA9eZmnHu/tvbiQq8vgqyuxu7t1hY/9vfpNJsAfHQcdHT0dQCzXObTxAQA7ctLns7PodUiODkBINPXx7vFxdcB8ktL8fluby+e+u3OzrNCngciCQDpNHheNLwgINjexgIEqB8e0mk0ACjMzSFdasQA5vg4pdlZAJqPj5wND/NtZgYtFKDVon50BEB/Nkuui4bBn1e6JRoYGeHL8TGfq1Wy6+sRjd3dOJ9y3WcaNqhvWXrj+5pkN76vNdBaPq+/gkBVVcMw1FqxqDZEuyAbGxRtO/GvF22b+tgYPw2D+2o1omuahMvLkfKqyqSImn9Z2zagQLpraCHwXVV+DwDt+Z4JbwqWpAAAAABJRU5ErkJggg==",
"icon2x": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADFElEQVRYhcWXy0sbURTGf6MJ+EJQKD5CjQh2YRQkalDQTTAQfKzciAjirrbxr/AvKNLSnVl0IYKiG8EX4kYXulAIRArJwtdCUHGRZDTD3C7GPOaRmNiafnAId+abc7773ZMzjNQD9gRMS/AF6KU0OBHwoxJ+2RIw/bWtbeHz8HBTWXNzSaqrNzfun7u7C9+jUXDBcdLvTwqHQwgoTTgcIun3J11wjOvlQsmKZ4lwgSgD4Pq6JNbr8FKzrPSV9XibgM1Na2PX1orP5Sr27NrbhVBVYQlFEcLpLDhXpgeKQSAAkmR9r7wc5ube0YGaGiEeH613n8LdnRCVle/kwMwM1Nbm59TXw9TUOzggSUKEw/l3n8LpacEOFC7A5yuseApDQ8UdgfpazM+jqiqqqiKEyEQopF+nIhBAFHACkgtECIgBOXobWlvh7AzKMi0jSRLEYtDXB8fHUF2tf0ZRwOWC62vLvBVAJ1mDSAYSL7+mmJ1FlmXkeDwdiVgMORhEvrhAXlrS3ZPjceTnZ+SZmXReY5gcyPk2qKqCoyNz9wsBPh9SJAJtbbC3Z54P9/fQ3w/PzyYXml4csKUuJAyE9ANjY2CzQTyuJxweQiSi8aJR2NmBwUE9p6ICRkZgfV2fMwtpAXIuARMT5uIAwaCeGwyC223mTUykBVghpwBAS9jYaBZwdaU5kC346AjOz6GlRc91OqGzE0IhvWCjAOMRADA6imS1+5UVrQeyIQTS8rL2rjBifPx1ASYHPnyAri6IxbS/XFppAra3szLY0s0nHRzA5KTWuNlwu6GuDh4eTNpyC/B6kZ6ezLvZ3tZEANjtsLiozYBskVaueb2wumpqROsjsNvB4zHvXgjY2sqse3q0wvG4nmeFgQHY2ABFKeAIciUOh+H2NrP2eHS7zSvCZoPubjg50V+2FNDba514fz/DaWjQwmh3PhEej0lAehJ+M6o14BWDC+cqCgDzGCahbEF6q4hixOYfRH+ZvFABJ1fQ/RFsv/+xgFzcT8AVKMApHTAbgMsLSJbqs+wSkgG47IBZ6X9/nv8B4pwbn9mt7LIAAAAASUVORK5CYII=",
"extra": {
"indexFilePath": "package-detail.html"
}
}{
"sourceId": "com.kapeli",
"name": "Apache_HTTP_Server",
"title": "Apache HTTP Server",
"versions": ["2.4.43", "2.4.41", "2.4.39", "2.4.38", "2.4.37", "2.4.35", "2.4.34", "2.4.33", "2.4.29", "2.4.28", "2.4.27", "2.4.25", "2.4.23", "2.4.20", "2.4.18", "2.4.17", "2.4.16", "2.4.12", "2.4.10", "2.4.9", "2.2.27", "2.0.65"],
"revision": "0",
"icon": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACtklEQVQ4EY2SXUgUURTHz52d2XXXwfVj1dbVVTfzq6wehLIv9UmyKBAsDXzoIaiHCvMl+rCrvRQkBL2EYCxJDxlFHy+Z0Cq6iSuZJNmaqWQ4meLu2G7azszOdGd1ysWEznA4c8+c3/zPvecC/IcpAMhVhmmttAO2bvI0OC4OXsiZRlpyo4jLymjc3S2p3101kEUbttUbE4QTmaUBCz/PgG5DEIByYYzKnc4wqTG3HTx9OSnG4bQAfwDF0yZBlmGRo2b/2UEHVOuOwSMVhFtQXJt+suqGKdlu9418hLQZj8g6gnKiI2Dg+F89f/aldbIGZu9Vnm215O2onfUtwydnr2Sa8+lM2TbGzEkQDC3ChDj5NKoDDa4BSDtc29hltG4uHO4fDUP/V2TPZVFmaTaaGh1d8LtnXEugH2+GkRZKU8Zkz2rbFQDWQ3VNLjneXth3p0+M6f+myymIo2yUgqzBEOwv2ZXkT1NGmuHlJQWf8msdqJFMC8B5pKGXSs7Z52l7I9qteibFagAlwIdNkvjDuCTF8WZqtofxHW/74HKropEfYDJj3I2luyV1jYnb9zQNPHsr2nQKk6pDkLUzGYxbrPCw/fH9m3M9t4lGkPg48YjRGDClwvUARbGO/Cve95/BFhLohEwDCDwf+D7M04ifV9hN5iGYg3cqpV4sohzpmL6GATDxosrzV0UBMfohLpSewaLc3QX6wSnvl6rO1jMwDQuEG1NAIaD6rMAkBzTCWG6GlL1xbFK1f4KD/AzWYDEimHQPSn5K6CI1HuLCKhxRVUHNIveAtRWfm3IPcD9Dy899DBPrXZLDr7mxJ69g+oUKNgEih4VkDYqK1y3leS2pFYE6Qz6ZYLSpe43OrF9RDEUfXQyHHrSHvJ0KOVBVccX/HtR6bE2m2phrI8v41ZSqqPmaqo1ffwPQhgcNITazvAAAAABJRU5ErkJggg==",
"icon2x": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAFkElEQVR42rxWa2wUVRg989z3tttut6UPClqQQqO1oIIVsAiJwo9Cgk0gGuOjGo0REzU+Y0KA6A8jMZpGJWmRQAgJmqDSEK0IhlrAloJtpTT0RVnKttvd6Wz3Obsz3tmdLQuClNL2Jl/uvZude853zvfdGQozP6gfny66N03PvMkz1DPUTAL/smneagNLb9EZlHXm+/wQ2yxgZwCYPry+5EWrRXpOZ1TKzfMDsCzygTFJ006Abtg8/yUjR3/EsLECPp2CPi8C1qIgKvBQ5IT400GA+sSxZvWyVc7PdWBLqDAPhpMBWUJ0VCEzASbbsJuHX5IvTiUBapvjiSVGittptKWXh9hioKeDZCxBiUYSGRNgdVbIHAsBwag8OCUE3s4st2ez5q0Gg/G17IpHkbWsDGLfEHxtQ7DL7jgglGsEVBWi/hjEsNR5twRoIvdGA83uyigtseY+VYGAEERz7e8IDLhgZCxQQgqyZE8cVNFCJSMFw+gYUJomTeCNjKVZhVx6HZF7XcGGJ8Hn5KDzaDucp7oIsAITAzIDAdkCj88Aa0yEThESRIgkQUV27WjpOzYZAtTWrFUPWRndQcfSxQWq5K4eN8599hM4SSLACoxsAlwlos56hgUbtYEXbIBXRpc4gjbBUw90jVGTkLzaYjR/rWZtmFOI5oOn4O50EtAEmEHLnFX8CIREyPECuH4Mx/y/bh8+voUs+++EAL3dsfqVzAx7TeGmSowFgaa9J0BHpPFM4wRI9lYTh+Kqx8Cn6XF69yFc6O89umf0bM1lSSQeQCJBigJXSIwydwLuyM2vKarejMEeD07uawQvywm/CWgiEt7rEUP4n15YTDosqFwB1h+dW+ThHzDT/MHOiLuLnDdCYoxEjL2TzO95vgqtP5/DpdZeTWplXPKkBddsUBA42Qa4vZj3SAm6T7fn5nNWnQY+7svtLKDesy9flm+2N6rgHSf60N/aHQcxMdS45KkWqAVoIHueThweJSq1uIbRHHC+Xye01moEYkmA/1Wg2rbYQS6YA2p/D13xE/CL8cPNLHMNkOxZRDAsem5acOrol4S9BPwHsvSnZn87AmwRn/lFZmlJPpWdh5av6kk7xWBlufFMk5kXVS4HZzfjWM0Bf4v30q464Ux9ClCEhJuEi0RQvRNTQW5VhNQH9hVrHZmOHXkb1qLpu+NQImOwcTwpNCpRcNplo65jPZeROduBuSvK+Eibc+kixt7eGLzUoIEOa7IHbsz+lgqo0tsZY7zXO+rPISS6CbiOSJ/0XbnOAj2ZhSMnMTI7C6FgaCygSH1aq0VuV+E3I8AUcrZ3MhbOzwuGaLg6u4nsDKxcwneenCn4RuC5id/iQF97rffMW72St/1GqSdMoMpakmOiuZdnVZSjZX8jWCaMDM467vecxx+ELi8dR2v2D+0b/fvds6HBAe1RtbJFTXav2gATIXBjDbDPppd+m1t2f1kgQOPy+fPI4o2wcPT4ZQPnELIXzkZafrYpozdQPCqHa51RUZV8SPN7lER4otdrqgLUq7aHFxgotmpW+RL8tbsh7rmNYxMXS0rV9x06joteAT453JzNmnwauDKZt2oqAbaQS/vYUbYIQtdVBEMe5Out8ayTNxtDVO7yCBgM+nt/8/d82uDv/kOTe/KfUcnFektxwUrTnA4alOVWf45B8Q9IwqGdI01fal4n2ys6WQJJBZhSfc4LKrgKskc4+3pKcSWHorWVV5Nc1PbK3SiQJKCz0rpqdeGUxO8J+J8agPwfEYCQFrGp+J5UCdAf2lduZCg6L6LEXIfHLnxDfhvUXpcKpnmQdxY4I81VqpvmoHNbZ9jdo/k67eBJAjpCYA2Rvu6A2H6E7IWpkneiXWAlMUvL+CoJ30xlnyTAQf2KShRcaCazV8e/AgwAzFxBrzZw9DMAAAAASUVORK5CYII="
}]

上面的数据,有用的有:

  • name:文档名(请求 url 用)
  • title:文档名(文件夹名称用)
  • revision:文档版本(应该吧)
  • icon 和 icon2x:文档名字前面的小图标的 base64 编码

此外,还有下载文档的链接地址

我下载的是 Android 这个文档

可以看到下载 Android 文档是这样的过程

  1. 请求 https://go.zealdocs.org/d/com.kapeli/Android/latest 得到右下角的重定向链接
  2. 请求 https://singapore.kapeli.com/feeds/Android.tgz 便可得到文档

那么,AngularJS 的文档地址为 https://singapore.kapeli.com/feeds/AngularJS.tgz

一次性使用

可以在使用pip的时候加参数: -i https://pypi.tuna.tsinghua.edu.cn/simple

例如:pip install SomePackage -i https://pypi.tuna.tsinghua.edu.cn/simple
这样就会从清华这边的镜像去安装SomePackage库。

永久修改,一劳永逸:

  • linux下,修改 ~/.pip/pip.conf (没有就创建一个), 修改 index-url 为国内镜像地址,内容如下:
1
2
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
  • windows下,直接在user目录中创建一个pip目录,如:C:\Users\xx\pip,新建文件pip.ini,内容如下
1
2
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple

原文链接:https://blog.csdn.net/qq_14994573/article/details/80934201