兼容

这是一场不停的追逐!


  • Home

  • About

  • Tags

  • Archives

Java端小图平铺合并成一个大图的代码

Posted on 2017-02-10

平铺合并

pc版本测试成功

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* 将一个小图从左到右, 从上到下 连续的合并为一个大图
* @param srcPng 需要合成的小图片路径及名称
* @param outPng 合成结果的路径及名称
* @param width 结果图片的宽
* @param height 结果图片的高
*/
private static void overlapSmall(String srcPng, String outPng, int width, int height) {
try {
File srcFile = new File(srcPng);
Image bg_src = javax.imageio.ImageIO.read(srcFile);

int src_width = bg_src.getWidth(null);
int src_height = bg_src.getHeight(null);
BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Graphics2D g2d = tag.createGraphics();

int row = 0;
int column = 0;
if(0 == width%src_width){
column = width/src_width;
}else{
column = width/src_width + 1;
}
if(0 == height%src_height){
row = height/src_height;
}else{
row = height/src_height + 1;
}

//g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0f)); // 透明度设置
int x = 0;
int y = 0;
for(int i = 0; i < column; ++i){
y = 0;
for (int j = 0; j < row; ++j) {
g2d.drawImage(bg_src, x, y, src_width, src_height, null);
y += src_width;
}
x += src_height;
}
//g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); // 透明度设置 结束

FileOutputStream out = new FileOutputStream(outPng);
ImageIO.write(tag, "png", out);// 写图片
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}

android 平台测试成功

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
36
37
38
39
40
41
42
43
44
45
private static Bitmap overlapSmallToBitmap(Context context, int srcPng, int width, int height) {
Bitmap bitmap = null;
try {
InputStream is = context.getResources().openRawResource(srcPng);
Bitmap bg_src = BitmapFactory.decodeStream(is);

int src_width = bg_src.getWidth();
int src_height = bg_src.getHeight();

bitmap = Bitmap.createBitmap(width, height, bg_src.getConfig());
Canvas canvas = new Canvas(bitmap);
// Paint paint = new Paint();
// paint.setColor(Color.BLACK);
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));

int row = 0;
int column = 0;
if(0 == width%src_width){
column = width/src_width;
}else{
column = width/src_width + 1;
}
if(0 == height%src_height){
row = height/src_height;
}else{
row = height/src_height + 1;
}

int x = 0;
int y = 0;
for(int i = 0; i < column; ++i){
y = 0;
for (int j = 0; j < row; ++j) {
canvas.drawBitmap(bg_src, x, y, null);
y += src_width;
}

x += src_height;
}
} catch (Exception e) {
e.printStackTrace();
}

return (bitmap);
}

sqlite常用函数

Posted on 2017-01-13

sqlite 日期&时间

日期和时期函数

序号 函数 实例
1 date(timestring, modifier, modifier) 以YYYY-MM-DD格式返回日期
2 time(timestring, modifier, modifier) 以HH:MM:SS格式返回时间
3 datetime(timestring, modifier, modifier) 以YYYY-MM-DD HH:MM:SS格式返回
4 julianday(timestring, modifier, modifier) 返回从格林尼治时间的公元前4714年11月24日正午的天数
5 strftime(format, timestring, modifier, modifier) 根据format指定格式返回时间

timestring : 时间字符串

序号 时间字符串 实例
1 YYYY-MM-DD 2010-12-30
2 YYYY-MM-DD HH:MM 2010-12-30 12:10
3 YYYY-MM-DD HH:MM:SS.SSSS 2010-12-30 12:10:04.100
4 MM-DD-YYYY HH:MM 30012-2010 12:10
5 HH:MM 12:10
6 YYYY-MM-DDTHH:MM 2010-12-30 12:10
7 HH:MM:SS 12:10:01
8 YYYYMMDD HHMMSS 20101230 121001
9 now 2017-1-13

注: 可以用T作为时间和日期的分隔符.

modifier : 修饰符

时间字符串后边可跟着零个或多个修饰符, 这将改变上述五个函数返回的日期和时间. 修饰符从左到右使用.
可在sqlite中使用的修饰符, 如下:

  1. NNN days;
  2. NNN hours;
  3. NNN minutes;
  4. NNN.NNNN seconds;
  5. NNN months;
  6. NNN years;
  7. start of month;
  8. start of year;
  9. start of day;
  10. weekday N;
  11. unixepoch;
  12. localtime;
  13. utc;

格式化: 用于strftime

替换 描述
%d 一月中的第几天, 01-31
%f 带小数部分的秒, ss.sss
%H 小时, 00-23
%j 一年中的第几天, 001-366
%J 儒略日数, DDDD.DDDD
%m 月, 00-12
%M 分, 00-59
%s 从1970-01-01算起的秒数
%S 秒, 00-59
%w 一周中的第几天, 0-6,(0 is sunday, 周日)
%W 一年中的第几周
%Y 年, YYYY
%% %

实例

1
2
3
4
5
6
7
8
select date('now');
select date('now', 'start of month', '+1 month', '-1 day');
select datetime(1092941466, 'unixepoch', 'localtime');
select julianday('now') -julianday('1776-07-04');
select strftime('%s', 'now') -strftime('%s', '2004-01-01 02:34:56');
select date('now', 'start of year', '+9 months', 'weekday 2');
select time('12:00', 'localtime');
select time('12:00', 'utc');

sqlite 常用函数

函数列表

  1. sqlite count 函数 : count 聚集函数是用来计算一个数据库表中的行数。
  2. sqlite max 函数 : max 聚合函数允许我们选择某列的最大值。
  3. sqlite min 函数 : min 聚合函数允许我们选择某列的最小值。
  4. sqlite avg 函数 : avg 聚合函数计算某列的平均值。
  5. sqlite sum 函数 : sum 聚合函数允许为一个数值列计算总和。
  6. sqlite random 函数 : random 函数返回一个介于 -9223372036854775808 和 +9223372036854775807 之间的伪随机整数。
  7. sqlite abs 函数 : abs 函数返回数值参数的绝对值。
  8. sqlite upper 函数 : upper 函数把字符串转换为大写字母。
  9. sqlite lower 函数 : lower 函数把字符串转换为小写字母。
  10. sqlite length 函数 : length 函数返回字符串的长度。
  11. sqlite sqlite_version 函数 : sqlite_version 函数返回 sqlite 库的版本。

实例

1
2
3
4
5
6
7
8
9
10
11
select count(*) from company;
select max(salary) from company;
select min(salary) from company;
select avg(salary) from company;
select sum(salary) from company;
select random() as Random;
select abs(5), abs(-15), abs(NULL), abs(0), abs("ABC");
select upper(name) from company;
select lower(name) from company;
select name, length(name) from company;
select sqlite_version() as "SQLite Version";

sqlite高级-2

Posted on 2017-01-12

sqlite alter 命令

alter table命令不通过执行一个完整的转储和数据的重载来修改已有的表.
alter table语句来重命名表, 还可以在已有的表中添加额外的列.
sqlite中, 除了重命名表和添加列外, 不支持其他操作

语法

1
2
3
4
5
-- 重命名表
alter table datebase_name.table_name rename to new_table_name;

-- 添加新列
alter table datebase_name.table_name add column column_def...;

实例

1
2
3
alter table company rename to old_company;

alter table old_company add column sex char(1);

sqlite truncate table

sqlite 中, 并没有truncate table命令,可以使用sqlte的delete命令删除表中已有的数据.
但是如果删除整个表,建议使用drop table命令.

语法

1
2
3
delete from table_name;

drop table table_name;

实例

1
delete from company;

sqlite 视图(view)

  1. 视图(view)是通过相关的名称存储在数据库中的一个sqlite语句;
  2. 视图(view)是一个以预定义的sqlite查询形式存在的表的组合;
  3. 视图(view)可以包含一个表的所有行或从一个或多个表选定行;
  4. 视图是一种虚表, 允许用户实现以下几点:
    • 用户或用户组查找结构数据的方式更自然或直观
    • 限制数据访问, 用户只能看到有限的数据, 而不是完整的表
    • 汇总各种表中的数据, 用户生成报告
  5. 视图是只读的, 无法进行delete, insert或update操作, 但是可以创建触发器.

创建视图

1
2
3
create [temp | temporary] view view_name as select column1, column2...
from table_name where [condition];
-- 如果使用temp 或temporary, 则将在临时数据库中创建视图.

实例

1
2
3
4
create view company company_view as select id, name, age from company;

-- 查询视图, 和查询表类似
select * from company_view;

删除视图

1
2
3
4
drop view view_name;

-- 实例
drop view company_view;

sqlite 事务(Transaction)

  1. 事务是一个对数据库执行工作单元. 事务是以逻辑顺序完成的工作单位或序列, 可以是由用户手动操作完成,
    也可以是由某种数据库程序自动完成.
  2. 事务是一个或多个更改数据库的扩展. 例如, 如果您正在创建一个记录或更新或删除, 那您正在改表执行事务.
  3. todo

事务的属性

  1. 原子性(atomicity): 确保工作单位内的所有操作都成功完成, 否则, 事务会在出现故障时终止,
    之前的操作也会回滚到之前的状态.
  2. 一致性(consistency): 确保数据库在成功提交的事务上正确的改变状态.
  3. 隔离性(isolation) : 使事务操作相互独立和透明.
  4. 持久性(durability) : 确保已提交事务的结果或效果在系统发生故障的情况下仍然存在.

事务控制

  1. begin 或 begin transaction : 开始处理事务.
  2. commit : 保存修改, 或者可以使用end transaction.
  3. rollback: 撤销未保存到数据库的事务, commit后就无法撤销了.

实例

1
2
3
4
5
6
7
8
9
10
-- 假设有age为25的记录
begin;
delete from company where age=25;
rollback;
-- 查看记录仍然存在

begin;
delete from company where age=25;
commit;
-- 查看已经删除, 并且rollback已经无用

sqlite子查询

  1. 子查询或内部查询或嵌套查询是在另一个sqlite查询内嵌入在where子句中的查询, 使用子查询返回的数据将被
    用于在主查询中作为条件, 以进一步限制要检索的数据.
  2. 子查询与select, insert, update, delete一起使用, 伴随运算符等.
  3. 遵循的规则:
    • 子查询必须用括号括起来
    • 子查询在select子句中只能有一列. 除非在主查询中有多列, 与子查询的所选列进行比较.
    • order by 不能用于子查询中, 虽然主查询可以使用order by; 可以使用group by, 功能与order by相同.
    • 子查询返回多于一行, 只能与多值运算符一起使用, 如IN运算符.
    • between运算符不能与子查询一起使用, 但是, between可在子查询内使用.

select语句中的子查询使用

1
2
3
4
5
6
7
8
9
select column_name [, column_name] from table1 [,table2]
where column_name operator (select column_name[,...] from table1 [,...] [where]);

-- example
select * from company where id in(select id from company where salary>45000);

select * from department where id in(select id from company where salary>45000);

select * from company where id in(select id from department);

insert语句中的子查询使用

1
2
3
4
5
insert into table_name[(column1, column2)] select [* | column1[,column2]]
from table1 [, table2] [where value operator];

-- 假设company_bkp的结构与company表类似
insert into company_bkp select * from company where id in(select id from company);

update语句中的子查询使用

1
2
3
4
5
update table set column_name = new_value
[ where operator [ value ] (select column_name from table_name) [ where) ]

update company set salary = salary * 0.50
where age in (select age from company_bkp where age >= 27 );

delete语句中的子查询使用

1
2
3
4
5
delete from table_name
[ where operator [ value ] (select column_name from table_name) [ where) ]

delete from company
where age in (select age from company_bkp where age > 27 );

sqlite autoincrement(自动递增)

  1. sqlite 的 autoincrement 是一个关键字,用于表中的字段值自动递增。
  2. 可以在创建表时在特定的列名称上使用 autoincrement 关键字实现该字段值的自动增加。
  3. 关键字 AUTOINCREMENT 只能用于整型(INTEGER)字段
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
36
37
38
39
40
-- 语法
create table table_name(
column1 integer autoincrement,
column2 datatype,
column3 datatype,
.....
columnN datatype,
);

-- 实例
create table company(
id integer primary key autoincrement,
name text not null,
age int not null,
address char(50),
salary real
);
insert into company (name,age,address,salary)
values ( 'paul', 32, 'california', 20000.00 );

insert into company (name,age,address,salary)
values ('allen', 25, 'texas', 15000.00 );

insert into company (name,age,address,salary)
values ('teddy', 23, 'norway', 20000.00 );

insert into company (name,age,address,salary)
values ( 'mark', 25, 'rich-mond ', 65000.00 );

insert into company (name,age,address,salary)
values ( 'david', 27, 'texas', 85000.00 );

insert into company (name,age,address,salary)
values ( 'kim', 22, 'south-hall', 45000.00 );

insert into company (name,age,address,salary)
values ( 'james', 24, 'houston', 10000.00 );

-- 查询:.header on, .mode column
select * from company;

sqlite Explain

TODO:

sqlite vacuum

TODO:

sqlite高级-1

Posted on 2017-01-12

sqlite pragma

以后追加

sqlite 约束

NOT NULL 约束

默认情况下, 列可以保存为NULL值; 如果不想, 则设置为NOT NULL;NULL和没有数据是不一样的, 代表未知的数据,
如下:

1
2
3
4
5
6
7
8
create table employee(
id int primary key not null
name text not null
age int not null
address char(50)
salary real
);
-- id, name, age不接受null值;

default 约束

在insert时没有提供特定的值时, 提供一个默认值, 如下:

1
2
3
4
5
6
7
create table employee(
id int primary key not null
name text not null
age int not null
address char(50)
salary real default 40000
);

unique 约束

防止一个特定的列出现列个记录相同的值, 如下:

1
2
3
4
5
6
7
8
create table employee(
id int primary key not null
name text not null unique
age int not null
address char(50)
salary real
);
-- 防止雇佣相同名称的人

primary key 约束

  1. 约束唯一标识数据库表中的每个记录. 在一个表中可以有多个unique列, 但是只能有一个主键.
  2. 通过主键来引用表中的行. 可将主键设为其他表的外键, 来创建表的关系.
  3. 在sqlite中, 主键可以为NULL, 与其他数据库不同的地方.
  4. 如果一个表在任何字段上定义了一个主键, 那么该字段就不能有俩个记录相同的值;

check 约束

启用输入一条记录要检查值的条件. 如果为false, 则不能创建.

1
2
3
4
5
6
create table company3(
id int primary key not null,
name text not null,
age int not null,
salary real check(salary>0)
);

删除约束

  1. sqlite支持alter table的有限子集.
  2. 在sqlite中, alter table命令允许用户重命名表, 或向现有表中添加一个新的列.
  3. 重命名列, 删除一列, 或从一个表中添加或删除约束列都是不可能的.

sqlite joins

joins子句用于结合俩个或多个数据库中表的记录.
假设我们已经有表company, department, 往department中插入如下记录:

1
2
3
insert into department values(1, 'IT Billing', 1);
insert into department values(2, 'Engineering', 2);
insert into department values(3, 'Finance', 7);

交叉连接

把第一个表的每一行与第二个表的每一行进行匹配. 如果第一表有n行x列, 第二个表有m行y列, 则会产生n*m行
x+y列的结果表, 如下;

select * from company cross join department;

内连接

根据连接条件结合俩个表. 查询会把table1中的每一行与table2中的每一行进行比较, 如果满足连接条件,
就会进行合并. 内连接是默认连接, inner可以省略. 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
select ... from table1 [inner] join table2 on condition_expression
-- 为了避免冗余, 并保持较短的措辞, 可以使用using表达式
select ... from table1 [inner] join table2 using(column1 ...)
-- 自然连接(natural join) 类似于join ... using , 只是它自会自动测试存在俩个表中每一列的值之间相等值.
select ... from table1 natural join table2;

--例子
select * from company inner join department on company.id=department.id;
-- 上面产生的效果类似于如下产生的效果:
select * from company natural join department;
-- using: id 俩个表都有, 所以正确, 连接后id列合并
select * from company inner join department using(id);
-- error: 由于name, dept不是俩个表共有的.
select * from company inner join department using(id, name, dept);
select * from company inner join department using(name, dept);

外连接

  1. 外连接是内连接的扩展, sqlite支持SQL标准left, right, full三种的左外连接(left outer join).
  2. 基本同上
1
2
3
4
5
6
7
8
9
10
11
select ... from table1 left outer join table2 on condition_expression
-- 为了避免冗余, 并保持较短的措辞, 可以使用using表达式
select ... from table1 left outer join table2 using(column1 ...)

--例子
select * from company left outer join department on company.id=department.id;
-- using: id 俩个表都有, 所以正确, 连接后id列合并
select * from company left outer join department using(id);
-- error: 由于name, dept不是俩个表共有的.
select * from company left outer join department using(id, name, dept);
select * from company left outer join department using(name, dept);

sqlite unions子句

UNION子句/运算符用于合并俩个或多个select语句的结果, 不返回任何重复的行.
为了使用UNION, 每个select被选择的列数必须是相同的, 相同数目的列表达式, 相同的数据类型,
并确保他们有相同的顺序, 但他们不必有相同的长度.

1
2
3
4
5
6
7
8
-- 语法
select column1 [,column2] from table1 [,table2] [where condition] union select column1 [,column2]
from table1 [,table2] [where condition]

-- 实例
select emp_id, name, dept from company inner join department on company.id = department.emp_id
union
select emp_id, name, dept from company left outer join department on company.id = department.emp_id;

union all子句

同上, 但是会返回重复的行

1
2
3
4
5
6
7
8
9
-- 语法
select column1 [,column2] from table1 [,table2] [where condition]
union all
select column1 [,column2] from table1 [,table2] [where condition]

-- 实例
select emp_id, name, dept from company inner join department on company.id = department.emp_id
union all
select emp_id, name, dept from company left outer join department on company.id = department.emp_id;

sqlite null 值

sqlite的null是用来表示一个缺失值的项. 表中的一个NULL值是在字段中显示为空白的一个值.
带有null值的字段是一个不带有值的字段. null值和零值或包含空格的字段是不同的.

语法, 实例

参照创建表

is not null运算符

1
select * from company where salary is not null;

sqlite 别名

可以暂时把表或列重命名为另一个名字, 就是别名. 使用表别名是指在一个特定的sqlite语句中重命名表.
重命名是临时的改变, 数据库中实机的表是不会改变的. 列别名同表别名.

语法

1
2
3
4
-- 表别名
select column1, column2, ... from table_name as alias_name where [condition]
-- 列别名
select column1 as alias_name from table_name where [condition]

实例

1
2
3
4
5
6
-- 表别名
select c.id, c.name, c.age, d.dept from company as c, department as d where c.id=d.emp_id;

-- 列别名
select c.id as company_id, c.name as company_name, c.age, d.dept from company as c,
department as d where c.id = d.emp_id;

sqlite 触发器(trigger)

触发器是数据库的回调函数, 它会在指定的数据库事件发生时自动执行或调用. 以下是相关要点:

  1. 指定在特定的数据库表发生delete, insert, 或update时触发, 或在一个或多个指定表的列发生更新是触发;
  2. 只支持for each row触发器, 没有for each statement触发器, 因此for each row是可选的.
  3. when 子句与触发器动作可能访问使用表单new.column-name 和 old.column-name的引用插入,
    删除或更新的行元素, 其中column-name是从与触发器关联的表的列的名称.
  4. 如果提供when子句, 则只针对when子句为真的指定行执行sql语句. 否则, 为所有行执行.
  5. defore 或 after 关键字决定何时执行触发器动作. 决定是在关联行的插入, 修改或删除之前或之后执行.
  6. 当触发器关联的表删除时, 自动删除触发器.
  7. 要修改的表必须存在与同一数据库中, 作为触发器被附加的表或视图, 且必须只使用tabname,
    而不是database.tablename.
  8. 一个特殊的sql函数raise() 用于触发器程序内抛出异常.

语法

1
2
3
4
5
6
7
8
9
10
-- 创建触发器
create trigger trigger_name [before | after] event_name on table_name
begin
-- trigger 逻辑代码
end;

create trigger trigger_name [before | after ] update of column_name on table_name
begin
-- 触发器逻辑代码
end;

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 为company表的每一个记录保持审计试验
-- 创建一个audit表
create table audit(emp_id int not null, entry_date text not null);

-- 创建一个触发器
create trigger audit_log after insert on company
begin
insert into audit(emp_id, entry_date) values(new.id, datetime('now'));
end;

-- 往company中插入一条记录
insert into company(id, name, age, address, salary) values(11, 'feng', 28, 6722);

-- 执行上步后, 也会在audit中插入一个记录
select * from audit;

列出触发器和删除触发器

1
2
3
4
-- 列出
select name from sqlite_master where type='trigger';
-- 删除
drop trigger trigger_name

sqlite 索引(index)

  1. 索引是一种特殊的查找表, 数据库搜索引擎用来加快数据检索;
  2. 索引有助于加快select查询和where子句, 但是会减慢update和insert语句时的数据输入;
  3. 索引可以创建和删除, 不会影响源数据;
  4. 使用create index创建索引, 允许命名索引, 指定表及要索引的一列或多列, 并指示索引是升序还是降序;
  5. 索引也可以是唯一的, 与unique约束类似, 在列上或列组合上防止重复条目;

创建索引(create index)

  1. 如果查询一般使用一个列, 则使用单列索引;
  2. 如果使用多列, 则使用组合索引;

单列索引

只基于表的一个列上创建的索引.
create index index_name on table_name(column_name);

唯一索引

唯一索引不允许任何重复的值插入到表中
create unique index index_name on table_name(column_name);

组合索引

基于表的俩个或多个列上创建的索引
create index index_name on table_name(column1, column2);

隐式索引

创建表时, 由数据库服务器自动创建的索引. 索引自动创建为主键约束和唯一约束.

删除索引

drop index index_name

以下情况避免使用索引

  1. 不应该使用在较小的表上;
  2. 不应该使用在有频繁的大批量的更新或插入操作的表上;
  3. 不应该使用在含有大量的null值的列上;
  4. 不应该使用在频繁操作的列上;

实例

1
2
3
4
5
6
7
create index salary_index on company(salary);

-- 查看所有索引
.indices company

-- 列出数据所有的索引
select * from sqlite_master where type='index';

sqlite indexed by

“indexed by index_name” 子句规定必须需要命名的索引来查找前面表中值. 如果不存在或不能用于查询,
语句失败. “not indexed” 子句规定当访问前面的表时, 没有使用索引. 然而, 即使指定了”not indexed”,
integer primary key仍然可以用于查找条目.

语法

1
2
select|delete|update column1, column2 indexed by (index_name)
table_name where (condition);

实例

1
2
3
4
-- 假设有表
create index age_index on company(age);
-- 使用
select * from company indexed by age_index where age>30;

sqlite基础

Posted on 2017-01-06

sqlite 命令

DDL 数据定义语言

  1. create 创建一个表,一个表的视图, 或数据库中的其他对象
  2. alter 修改数据库中的某个已有的数据库对象, 比如一个表
  3. drop 删除表或视图, 或其他对象

DML 数据操作语言

  1. insert 创建一条记录
  2. update 修改记录
  3. delete 删除记录

DQL 数据查询语言

select 检索记录

点命令

  1. .help 查看帮助
  2. .backup 可以备份
  3. .tables 查看数据库里面的表
  4. .schema tab_name : 查看表结构
  5. …其他

sqlite语法

  1. 不区分大小写, 但有些命令大小写敏感,如GLOB 和glob;
  2. 注释: – 注释 或 / 注释 /

sqlite 数据类型

存储类型

  1. NULL : NULL值;
  2. integer : 带符号的整数, 根据大小存储在1,2,3,4,6或8字节中;
  3. real : 8字节的IEEE浮点数字;
  4. text : 文本字符串;
  5. blob : 根据输入存储;

亲和类型

当数据插入时, 该字段的数据会优先采用亲缘类型作为该值的存储方式

  1. text : 数值型数据在被插入前, 需要先被转换为文本格式, 之后再插入到目标字段中;
  2. numeric : 当文本数据被插入到到此字段时, 如果转换操作不会导致数据信息丢失以及完全可逆, 则转换为real
    或integer类型的数据, 如果失败,则以text存储;如'3000.00'的浮点数, 也会存储未real或integer;
    
  3. integer : 同上, 差别在于转换操作;
  4. real : 同numeric, 差别在于不会转换’3000.00’的形式;
  5. none : 不做转换;

亲和类型及类型名称

  1. int,integer,tinyint,smallint,mediumint,bigint,unsigned big int, int2, int8 : integer;
  2. character(20), varchar(255), varying, character(255), nchar(55), native character(70),
    nvarchar(100), text, clob: text;
  3. blob, no datatype specified: none;
  4. real, double, double precision, float: real;
  5. numeric, decimal(10,5), boolean(0, 1) date, datetime: numeric;

sqlite 使用

创建表

1
2
3
4
5
6
7
8
-- 例子
create table company(
id int primary key not null,
name text not null,
age int not null,
address char(50),
salary real
);

删除表

1
drop table name;

插入数据

  1. insert into table_name (column1, column2, column3, …) values(value1, value2, value3, …)
  2. insert into table_name values (value1, value2,value3, ..) : 为所有列添加值,且顺序按定义的来
1
2
3
4
5
6
7
8
9
10
11
12
-- 第一种插入
-- 对于非空项必须插入
insert into company (id, name, age, address, salary) values(1, 'paul', 32, 'california', 20000.0);
insert into company (id, name, age, address, salary) values(2, 'allen', 22, 'texas', 20000.0);
insert into company (id, name, age, address, salary) values(3, 'teddy', 42, 'norway', 15000.0);
insert into company (id, name, age, address, salary) values(4, 'mark', 38, 'rich-mond', 65000.0);
insert into company (id, name, age, address, salary) values(5, 'david', 42, 'texas', 85000.0);
insert into company (id, name, age, address, salary) values(6, 'kim', 42, 'south-hall', 40000.0);
insert into company (id, name, age) values(8, 'wade', 33)

-- 第二种插入
insert into company values (7, 'james', 33, 'houston', 10000.0);

select 语句, 显示表中数据

查看表中信息

  1. 有选择的查看: select column1, column2, columnN from table_name;
  2. 查看所有数据: select * from table_name;
  3. 为友好的查看数据, 可以使用:
    • .header on
    • .mode column
    • .width 10,20,10

查看数据库的表

1
2
3
4
5
-- 查看数据库中创建的表
select tbl_name from sqlite_master where type='table';

-- 列出表中的完整信息
select sql from sqlite_master where type='table' and tbl_name='company';

算术运算符

+ - * / %

比较运算符

  1. == = != <> : 是否相等或不等的;
  2. > < >= <= !< !> :大小比较;

逻辑运算符

  1. AND : 多个条件并存;
  2. BETWEEN : 给定一个范围;
  3. EXISTS : 在满足一定条件的指定表中搜索行的存在;
  4. IN : 指定值与一系列指定列表的值进行比较;
  5. NOT IN : 与IN相反;
  6. LIKE : 用于把某个值与使用通配符运算符的近似值进行比较;
  7. GLOB : 与LIKE类似,但是大小写敏感;
  8. NOT : 逻辑运算符的对立面, 如NOT EXISTS, NOT BETWEEN, NOT IN等;
  9. OR : 或;
  10. IS NULL : 与NULL值进行比较的结果;
  11. IS : 与 = 运算符类似;
  12. IS NOT : 与 != 类似;
  13. || : 连接俩个不同的字符串, 得到一个新的字符串;

位运算符

& | ~ >> << : 与c语言中类似

1
2
3
4
5
6
7
8
select * from company where age >= 25 AND salary >= 65000;
select * from company where age >= 25 OR salary >= 65000;
select * from company where salary IS NOT NULL;
select * from company where name LIKE 'ki%';
select * from company where name LIKE 'ki*';
select * from company where age IN(32, 40);
select * from company where age NOT IN(32, 40);
select * from company where age BETWEEN 25 AND 27;

sqlite 表达式

1
2
3
4
5
6
7
-- 布尔表达式
select * from company where salary=10000;
-- 数值表达式
select (3+5) as addition;
select count(*) as "records" from company;
-- 日期表达式
select current_timestamp;

update语句

用于修改表中的已有的记录, 可以使用带有where子句的update查询来更新选定行, 否则都会更新

1
2
3
4
-- 更新一条记录
update company set address='zhengning' where id=6;
-- 更新所有记录
update company set address='gansu', salary=33333;

delete语句

用于删除表中已有的记录, 可以使用带有where子句的delete查询来删除记录, 否则会全部删除

1
2
3
4
-- 删除一条记录
delete from company where id=6;
-- 删除所有记录
delete from company;

like 子句

用来匹配通配符指定模式的文本值. 如果搜索表达式与模式表达式匹配,返回真; 通配符如下:

  • 百分号(%) : 代表0个, 1个或多个数字或字符;
  • 下划线(_) : 代表一个单一的数字或字符;
1
2
3
4
5
6
7
-- 通用式
select * from table_name where column like ['xxxx%' or '%xxxx%' or 'xxxx_' or '_xxxx' or '_xxxx_']
-- 一些例子
-- 查找以200开头的任意值
select * from company where salary like '200%'
-- 查找第二位为2, 且以3结尾的任意值
select * from company where salary like '_2%3'

glob 子句

用来匹配通配符指定模式的文本值. 与like不同的是, GLOB 是大小写敏感的; 通配符如下:

  • 星号(*) : 代表0个, 1个或多个字符或数字;
  • 问好(?) : 一个单一的数字或字符;
  • 例子同上;

limit 子句

基本语法

1
2
3
4
-- 基本的
select column1, column2, columnN from tab_name limit [no of rows];
-- 返回从下一行开始直到给定的offset为止的所有行
select column1, column2, columnN from tab_name limit [no of rows] offset [row num];

实例

1
2
select * from company limit 6;
select * from company limit 3 offset 2;

order by 子句

select column-list from table_name [where condition] [order by column1, column2, ] [asc(升)|desc(降)]

实例:

1
2
3
4
5
6
-- 按薪水升序排列
select * from company order by salary asc;
-- 按薪水降序排列
select * from company order by salary desc;
-- name, 薪水
select * from company order by name, salary asc;

group by 子句

select column-list from table where [conditions] group by column1,columnN order by column1,columnN

实例:

1
2
3
4
5
6
7
-- 如果想了解客户的工资总额
select into company values(9, 'teddy', 42, 'ggg', 90000);
-- 添加一条记录就可以看的更透彻
select * name,sum(salary) from company group by name;

-- 与order by一起使用
select name,sum(salary) from company group by name order by name desc;

having 子句

1
2
允许指定条件来过滤将出现在最终结果中的分组结果. where子句在所选列上设置条件, 而having子句则在由
group by子句创建的分组上设置条件.

语法

在select中的位置: select from where group by having order by, 必须在group by之后, order by之前.

实例

1
2
3
4
-- 显示名称计数小于2的所有记录
select * from company group by name having count(name)<2;
insert into company values(10, 'wade', 34, 'waiami', 33333);
-- 添加上条记录后再观察效果

distinct 子句

1
2
3
distinct关键字和select一起使用, 来消除所有重复的记录, 并只获取唯一一次记录. 有可能出现一种情况,
在一个表中有多个重复的记录. 当提取这样的记录时, distinct关键字就显得有意义, 它只获取唯一一次记录,
而不是重复获取.

语法

select distinct column1,column2,columnN from table_name where [condition]

例子

1
2
3
4
-- 返回的记录中有重复的
select name from company;
-- 返回不重复的记录
select distinct name from company;

NDK常用备份

Posted on 2017-01-05

目的

主要是在使用JNI的时候, 经常有些基本内容要去网上找, 有时比较繁琐, 故在此记录

一些重要的网址

关于JNI官方中文规范的一系列讲解

Java, jni 与 c++ 数据类型对照图

基本数据类型:

Java类型 Jni类型 c++类型 描述
boolean jboolean unsigned char 无符号8位整数
byte jbyte signed char 有符号8位整数
char jchar unsigned short 无符号16位整数
short jshort signed short 有符号16位整数
int jint signed int 有符号32位整数
long jlong long long 有符号64位整数
float jfloat float 有符号32位浮点数
double jdouble double 有符号64位浮点数

对象类型:

Java类型 Jni类型 描述
Object jobject 任意Java对象
Class jclass Class 对象,Java类
String jstring 字符串对象

类型对应的签名:

native接口命名规则

对于传统的JNI编程来说,JNI方法跟Java类方法的名称之间有一定的对应关系,要遵循一定的命名规则,如下:

  1. 前缀: Java_
  2. 类的全限定名,用下划线_进行分隔, 如: com_lms_jni_JniTest
  3. 方法名一般以小写开头, 一般函数名中间不使用下划线_, 如果使用下划线的话则可能需要使用动态注册方法,如:getTestString
  4. jni函数指定第一个参数: JNIEnv *
  5. jni函数指定第二个参数: jobject
  6. 实际Java参数: jstring, jint ….
  7. 返回值的参数 : jstring, jint…. 所以对于在Java类 com.dasea.jni.JniDemo中的一个方法:

    1
    2
    public native String addTail(int, String tail, int);
    public native String addTailOne(int, String tail, int[] arr);

    其对应的jni层的native函数声明如下:

    1
    2
    3
    4
    5
    jstring Java_com_dasea_jni_JniDemo_addTail(JNIEnv* env, jobject obj, jint, jstring, jint);
    // 函数签名: (ILjava/util/String;I)Ljava/util/String;

    jstring Java_com_dasea_jni_JniDemo_addTail(JNIEnv* env, jobject obj, jint, jstring, jintArray);
    // 函数签名: (ILjava/util/String;[I)Ljava/util/String;

base64 编解码

Posted on 2016-12-20

base64 基本知识

base64是将二进制数据转换为64个可打印字符的转换方式.

base64 编码

将三字节转为四字节, 如下:

如果不是三的整数倍, 则补0; 根据补的0的个数, 需要在结果字符串的最后面添加'='

实现如下:

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string base64_encode(uint8_t* in, uint32_t inLen) {
uint8_t arrayIn[3] = {0};
uint8_t arrayOut[4] = {0};

// 判断是否是
uint32_t round = (uint32_t)(inLen / 3);
uint32_t i = 0;
uint32_t j = 0;
std::vector<uint8_t> outRet;
while (i++ < round) {
arrayIn[0] = in[j++];
arrayIn[1] = in[j++];
arrayIn[2] = in[j++];

arrayOut[0] = ((arrayIn[0] & 0xfc) >> 2);
arrayOut[1] = ((arrayIn[0] & 0x03) << 4) + ((arrayIn[1] & 0xf0) >> 4);
arrayOut[2] = ((arrayIn[1] & 0x0f) << 2) + ((arrayIn[2] & 0xc0) >> 6);
arrayOut[3] = (arrayIn[2] & 0x3f);

outRet.push_back(base64_chars[arrayOut[0]]);
outRet.push_back(base64_chars[arrayOut[1]]);
outRet.push_back(base64_chars[arrayOut[2]]);
outRet.push_back(base64_chars[arrayOut[3]]);
}

// 如果不是三的倍数的话
// 处理余下的内容, 如果添加的话, 需要=号
round = (uint32_t)(inLen % 3);
if (1 == round) {
arrayIn[0] = in[inLen - 1];
arrayIn[1] = '\0';

arrayOut[0] = ((arrayIn[0] & 0xfc) >> 2);
arrayOut[1] = ((arrayIn[0] & 0x03) << 4) + ((arrayIn[1] & 0xf0) >> 4);

outRet.push_back(base64_chars[arrayOut[0]]);
outRet.push_back(base64_chars[arrayOut[1]]);
// outRet.push_back('=');
// outRet.push_back('=');
} else if (2 == round) {
arrayIn[0] = in[inLen - 2];
arrayIn[1] = in[inLen - 1];
arrayIn[2] = '\0';

arrayOut[0] = ((arrayIn[0] & 0xfc) >> 2);
arrayOut[1] = ((arrayIn[0] & 0x03) << 4) + ((arrayIn[1] & 0xf0) >> 4);
arrayOut[2] = ((arrayIn[1] & 0x0f) << 2) + ((arrayIn[2] & 0xc0) >> 6);

outRet.push_back(base64_chars[arrayOut[0]]);
outRet.push_back(base64_chars[arrayOut[1]]);
outRet.push_back(base64_chars[arrayOut[2]]);
// outRet.push_back('=');
}

// vec 转 string
std::string out(outRet.begin(), outRet.end());
return (out);
}

base64 解码

将四个字节转换为三个字节, 上面的逆过程.

实现如下:

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
uint8_t* base64_decode(std::string& in, uint32_t& outLen) {
uint8_t arrayIn[4] = {0};
uint8_t arrayOut[3] = {0};

uint32_t round = (uint32_t)(in.size() / 4);
uint32_t i = 0;
uint32_t j = 0;
std::vector<uint8_t> vecRet;
while (i++ < round) {
arrayIn[0] = static_cast<uint8_t>(base64_chars.find(in[j++]));
arrayIn[1] = static_cast<uint8_t>(base64_chars.find(in[j++]));
arrayIn[2] = static_cast<uint8_t>(base64_chars.find(in[j++]));
arrayIn[3] = static_cast<uint8_t>(base64_chars.find(in[j++]));

// 转换
arrayOut[0] = (arrayIn[0] << 2) + ((arrayIn[1] & 0x30) >> 4);
arrayOut[1] = ((arrayIn[1] & 0x0f) << 4) + ((arrayIn[2] & 0x3c) >> 2);
arrayOut[2] = ((arrayIn[2] & 0x03) << 6) + arrayIn[3];

// 三个数已知
vecRet.push_back(arrayOut[0]);
vecRet.push_back(arrayOut[1]);
vecRet.push_back(arrayOut[2]);
}

// 如果不是4的整数倍, 则其他的单独进行
round = (uint32_t)(in.size() % 4);
if (2 == round) {
// 可转换为一个字符
arrayIn[0] = static_cast<uint8_t>(base64_chars.find(in[in.size() - 2]));
arrayIn[1] = static_cast<uint8_t>(base64_chars.find(in[in.size() - 1]));

arrayOut[0] = (arrayIn[0] << 2) + ((arrayIn[1] & 0x30) >> 4);
vecRet.push_back(arrayOut[0]);
} else if (3 == round) {
// 可转换为2个字符
arrayIn[0] = static_cast<uint8_t>(base64_chars.find(in[in.size() - 3]));
arrayIn[1] = static_cast<uint8_t>(base64_chars.find(in[in.size() - 2]));
arrayIn[2] = static_cast<uint8_t>(base64_chars.find(in[in.size() - 1]));

arrayOut[0] = (arrayIn[0] << 2) + ((arrayIn[1] & 0x30) >> 4);
arrayOut[1] = ((arrayIn[1] & 0x0f) << 4) + ((arrayIn[2] & 0x3c) >> 2);
vecRet.push_back(arrayOut[0]);
vecRet.push_back(arrayOut[1]);
}

outLen = vecRet.size();
uint8_t* ret = new uint8_t[outLen];
for (i = 0; i < outLen; ++i) {
ret[i] = vecRet[i];
}

return (ret);
}

bash, zsh学习记录

Posted on 2016-12-13

基本的

返回值

每个命令都有一个返回值(返回状态或者退出状态)。命令执行成功的返回值总是0(零值),执行失败的命令,返回一个非0值(错误码)。错误码必须是一个1到255之间的整数。

在编写脚本时,另一个很有用的命令是exit。这个命令被用来终止当前的执行,并把返回值交给shell。当exit不带任何参数时,它会终止当前脚本的执行并返回在它之前最后一个执行的命令的返回值。

一个程序运行结束后,shell将其返回值赋值给$?环境变量。因此$?变量通常被用来检测一个脚本执行成功与否。

与使用exit来结束一个脚本的执行类似,我们可以使用return命令来结束一个函数的执行并将返回值返回给调用者。当然,也可以在函数内部用exit,这 _不但_ 会中止函数的继续执行,_而且_ 会终止整个程序的执行。

注释

脚本中可以包含 _注释_。注释是特殊的语句,会被shell解释器忽略。它们以#开头,到行尾结束。

1
2
3
#!/bin/bash
# This script will print your username.
whoami

变量

Bash中没有数据类型。变量只能包含数字或者由一个或多个字符组成的字符串
你可以创建三种变量:局部变量,环境变量以及作为 位置参数 的变量。

局部变量

局部变量 是仅在某个脚本内部有效的变量。它们不能被其他的程序和脚本访问。

局部变量可以用=声明(作为一种约定,变量名、=、变量的值之间 不应该 有空格),
其值可以用$访问到。举个例子:

1
2
3
username="denysdovhan"  # 声明变量
echo $username # 输出变量的值
unset username # 删除变量

也可以用local关键字声明属于某个函数的局部变量,这样声明的变量会在函数结束时消失。

1
local local_var="I'm a local value"

环境变量

环境变量 是对当前shell会话内所有的程序或脚本都可见的变量.
创建它们跟创建局部变量类似,但使用的是export关键字。

1
export GLOBAL_VAR="I'm a global variable"

bash中有 非常多 的环境变量。你会非常频繁地遇到它们,这里有一张速查表,记录了在实践中最常见的环境变量。

Variable Description
$HOME 当前用户的用户目录
$PATH 用分号分隔的目录列表,shell会到这些目录中查找命令
$PWD 当前工作目录
$RANDOM 0到32767之间的整数
$UID 数值类型,当前用户的用户ID
$PS1 主要系统输入提示符
$PS2 次要系统输入提示符

查看更多

位置参数

位置参数 是在调用一个函数并传给它参数时创建的变量。下表列出了在函数中,位置参数变量和一些其它的特殊变量以及它们的意义。

Parameter Description
$0 脚本名称
$1 … $9 第1个到第9个参数列表
${10} … ${N} 第10个到N个参数列表
$* or $@ 除了$0外的所有位置参数
$# 不包括$0在内的位置参数的个数
$FUNCNAME 函数名称(仅在函数内部有值)

在下面的例子中,位置参数为:$0='./script.sh',$1='foo',$2='bar':

./script.sh foo bar

变量可以有 _默认_ 值。我们可以用如下语法来指定默认值:

1
2
3
4
5
 # 如果变量为空,赋给他们默认值
: ${VAR:='default'}
: ${$1:='first'}
# 或者
FOO=${FOO:-'default'}

Shell扩展

_扩展_ 发生在一行命令被分成一个个的 记号(tokens) 之后。换言之,扩展是一种执行数学运算的机制,还可以用来保存命令的执行结果,等等。

shell扩展的更多细节。

大括号扩展

大括号扩展让生成任意的字符串成为可能。它跟 文件名扩展 很类似,举个例子:

1
echo beg{i,a,u}n # begin began begun

大括号扩展还可以用来创建一个可被循环迭代的区间。

1
2
echo {0..5} # 0 1 2 3 4 5
echo {00..8..2} # 00 02 04 06 08

命令置换

命令置换允许我们对一个命令求值,并将其值置换到另一个命令或者变量赋值表达式中。当一个命令被

```或`$()`包围时,命令置换将会执行。举个例子:
1
2
3
4
5
6
7

```bash
now=`date +%T`
# or
now=$(date +%T)

echo $now # 19:08:26

算数扩展

在bash中,执行算数运算是非常方便的。算数表达式必须包在$(( ))中。算数扩展的格式为:

1
2
result=$(( ((10 + 5*3) - 7) / 2 ))
echo $result # 9

在算数表达式中,使用变量无需带上$前缀:

1
2
3
4
5
x=4
y=7
echo $(( x + y )) # 11
echo $(( ++x + y++ )) # 12
echo $(( x + y )) # 13

单引号和双引号

单引号和双引号之间有很重要的区别。在双引号中,变量引用或者命令置换是会被展开的.
在单引号中是不会的。双引号中, 对于变量可以扩展, 但是不用于扩展通配符; 单引号都
展开,举个例子:

1
2
echo "Your home: $HOME" # Your home: /Users/<username>
echo 'Your home: $HOME' # Your home: $HOME

当局部变量和环境变量包含空格时,它们在引号中的扩展要格外注意。随便举个例子,假如我们用echo来输出用户的输入:

1
2
3
INPUT="A string  with   strange    whitespace."
echo $INPUT # A string with strange whitespace.
echo "$INPUT" # A string with strange whitespace.

调用第一个echo时给了它5个单独的参数 —— $INPUT被分成了单独的词,echo在每个词之间打印了一个空格。第二种情况,调用echo时只给了它一个参数(整个$INPUT的值,包括其中的空格)。

来看一个更严肃的例子:

1
2
3
FILE="Favorite Things.txt"
cat $FILE # 尝试输出两个文件: `Favorite` 和 `Things.txt`
cat "$FILE" # 输出一个文件: `Favorite Things.txt`

尽管这个问题可以通过把FILE重命名成Favorite-Things.txt来解决,但是,假如这个值来自某个环境变量,来自一个位置参数,或者来自其它命令(find, cat, 等等)呢。因此,如果输入 可能 包含空格,务必要用引号把表达式包起来。

数组

跟其它程序设计语言一样,bash中的数组变量给了你引用多个值的能力。在bash中,数组下标也是从0开始,也就是说,第一个元素的下标是0。

跟数组打交道时,要注意一个特殊的环境变量IFS。IFS,全称 Input Field Separator,保存了数组中元素的分隔符。它的默认值是一个空格IFS=' '。

数组声明

在bash中,可以通过简单地给数组变量的某个下标赋值来创建一个数组:

1
2
3
fruits[0]=Apple
fruits[1]=Pear
fruits[2]=Plum

数组变量也可以通过复合赋值的方式来创建,比如:

1
fruits=(Apple Pear Plum)

数组扩展

单个数组元素的扩展跟普通变量的扩展类似:

1
echo ${fruits[1]} # Pear

整个数组可以通过把数字下标换成*或@来扩展:

1
2
echo ${fruits[*]} # Apple Pear Plum
echo ${fruits[@]} # Apple Pear Plum

上面两行有很重要(也很微妙)的区别,假设某数组元素中包含空格:

1
2
3
fruits[0]=Apple
fruits[1]="Desert fig"
fruits[2]=Plum

为了将数组中每个元素单独一行输出,我们用内建的printf命令:

1
2
3
4
5
printf "+ %s\n" ${fruits[*]}
# + Apple
# + Desert
# + fig
# + Plum

为什么Desert和fig各占了一行?尝试用引号包起来:

1
2
printf "+ %s\n" "${fruits[*]}"
# + Apple Desert fig Plum

现在所有的元素都跑去了一行 —— 这不是我们想要的!为了解决这个痛点,${fruits[@]}闪亮登场:

1
2
3
4
printf "+ %s\n" "${fruits[@]}"
# + Apple
# + Desert fig
# + Plum

在引号内,${fruits[@]}将数组中的每个元素扩展为一个单独的参数;数组元素中的空格得以保留。

数组切片

除此之外,可以通过 _切片_ 运算符来取出数组中的某一片元素:

1
echo ${fruits[@]:0:2} # Apple Desert fig

在上面的例子中,${fruits[@]}扩展为整个数组,:0:2取出了数组中从0开始,长度为2的元素。

向数组中添加元素

向数组中添加元素也非常简单。复合赋值在这里显得格外有用。我们可以这样做:

1
2
fruits=(Orange "${fruits[@]}" Banana Cherry)
echo ${fruits[@]} # Orange Apple Desert fig Plum Banana Cherry

上面的例子中,${fruits[@]}扩展为整个数组,并被置换到复合赋值语句中,接着,对数组fruits的赋值覆盖了它原来的值。

从数组中删除元素

用unset命令来从数组中删除一个元素:

1
2
unset fruits[0]
echo ${fruits[@]} # Apple Desert fig Plum Banana Cherry

流,管道以及序列

Bash有很强大的工具来处理程序之间的协同工作。使用流,我们能将一个程序的输出发送到另一个程序或文件,因此,我们能方便地记录日志或做一些其它我们想做的事。

管道给了我们创建传送带的机会,控制程序的执行成为可能。

学习如何使用这些强大的、高级的工具是非常非常重要的。

流

Bash接收输入,并以字符序列或 字符流 的形式产生输出。这些流能被重定向到文件或另一个流中。

有三个文件描述符:

代码 描述符 描述
0 stdin 标准输入
1 stdout 标准输出
2 stderr 标准错误输出

重定向让我们可以控制一个命令的输入来自哪里,输出结果到什么地方。这些运算符在控制流的重定向时会被用到:

Operator Description
> 重定向输出
&> 重定向输出和错误输出
&>> 以附加的形式重定向输出和错误输出
< 重定向输入
<< Here文档 语法
<<< Here字符串

以下是一些使用重定向的例子:

1
2
3
4
5
6
7
8
9
10
11
# ls的结果将会被写到list.txt中
ls -l > list.txt

# 将输出附加到list.txt中
ls -a >> list.txt

# 所有的错误信息会被写到errors.txt中
grep da * 2> errors.txt

# 从errors.txt中读取输入
less < errors.txt

管道

我们不仅能将流重定向到文件中,还能重定向到其它程序中。管道 允许我们把一个程序的输出当做另一个程序的输入。

在下面的例子中,command1把它的输出发送给了command2,然后输出被传递到command3:

command1 | command2 | command3

这样的结构被称作 管道。

在实际操作中,这可以用来在多个程序间依次处理数据。在下面的例子中,ls -l的输出被发送给了grep,来打印出扩展名是.md的文件,它的输出最终发送给了less:

ls -l | grep .md$ | less

管道的返回值通常是管道中最后一个命令的返回值。shell会等到管道中所有的命令都结束后,才会返回一个值。如果你想让管道中任意一个命令失败后,管道就宣告失败,那么需要用下面的命令设置pipefail选项:

set -o pipefail

命令序列

命令序列是由;,&,&&或者||运算符分隔的一个或多个管道序列。

如果一个命令以&结尾,shell将会在一个子shell中异步执行这个命令。换句话说,这个命令将会在后台执行。

以;分隔的命令将会依次执行:一个接着一个。shell会等待直到每个命令执行完。

1
2
3
4
5
6
# command2 会在 command1 之后执行
command1 ; command2

# 等同于这种写法
command1
command2

以&&和||分隔的命令分别叫做 _与_ 和 _或_ 序列。

与序列 看起来是这样的:

1
2
# 当且仅当command1执行成功(返回0值)时,command2才会执行
command1 && command2

或序列 是下面这种形式:

1
2
# 当且仅当command1执行失败(返回错误码)时,command2才会执行
command1 || command2

_与_ 或 _或_ 序列的返回值是序列中最后一个执行的命令的返回值。

条件语句

跟其它程序设计语言一样,Bash中的条件语句让我们可以决定一个操作是否被执行。结果取决于一个包在[[ ]]里的表达式。

条件表达式可以包含&&和||运算符,分别对应 _与_ 和 _或_ 。除此之外还有很多有用的表达式。

共有两个不同的条件表达式:if和case。

基元和组合表达式

由[[ ]](sh中是[ ])包起来的表达式被称作 检测命令 或 基元。这些表达式帮助我们检测一个条件的结果。在下面的表里,为了兼容sh,我们用的是[ ]。这里可以找到有关bash中单双中括号区别的答案。

跟文件系统相关:

基元 含义
[ -e FILE ] 如果FILE存在 (exists),为真
[ -f FILE ] 如果FILE存在且为一个普通文件(file),为真
[ -d FILE ] 如果FILE存在且为一个目录(directory),为真
[ -s FILE ] 如果FILE存在且非空(size 大于0),为真
[ -r FILE ] 如果FILE存在且有读权限(readable),为真
[ -w FILE ] 如果FILE存在且有写权限(writable),为真
[ -x FILE ] 如果FILE存在且有可执行权限(executable),为真
[ -L FILE ] 如果FILE存在且为一个符号链接(link),为真
[ FILE1 -nt FILE2 ] FILE1比FILE2新(newer than)
[ FILE1 -ot FILE2 ] FILE1比FILE2旧(older than)

跟字符串相关:

基元 含义
[ -z STR ] STR为空(长度为0,zero)
[ -n STR ] STR非空(长度非0,non-zero)
[ STR1 == STR2 ] STR1和STR2相等
[ STR1 != STR2 ] STR1和STR2不等

算数二元运算符:

基元 含义
[ ARG1 -eq ARG2 ] ARG1和ARG2相等(equal)
[ ARG1 -ne ARG2 ] ARG1和ARG2不等(not equal)
[ ARG1 -lt ARG2 ] ARG1小于ARG2(less than)
[ ARG1 -le ARG2 ] ARG1小于等于ARG2(less than or equal)
[ ARG1 -gt ARG2 ] ARG1大于ARG2(greater than)
[ ARG1 -ge ARG2 ] ARG1大于等于ARG2(greater than or equal)

条件语句可以跟 组合表达式 配合使用:

Operation Effect
[ ! EXPR ] 如果EXPR为假,为真
[ (EXPR) ] 返回EXPR的值
[ EXPR1 -a EXPR2 ] 逻辑 _与_, 如果EXPR1和(and)EXPR2都为真,为真
[ EXPR1 -o EXPR2 ] 逻辑 _或_, 如果EXPR1或(or)EXPR2为真,为真

当然,还有很多有用的基元,在Bash的man页面能很容易找到它们。

使用if

if在使用上跟其它语言相同。如果中括号里的表达式为真,那么then和fi之间的代码会被执行。fi标志着条件代码块的结束。

1
2
3
4
5
6
7
# 写成一行
if [[ 1 -eq 1 ]]; then echo "true"; fi

# 写成多行
if [[ 1 -eq 1 ]]; then
echo "true"
fi

同样,我们可以使用if..else语句,例如:

1
2
3
4
5
6
7
8
9
# 写成一行
if [[ 2 -ne 1 ]]; then echo "true"; else echo "false"; fi

# 写成多行
if [[ 2 -ne 1 ]]; then
echo "true"
else
echo "false"
fi

有些时候,if..else不能满足我们的要求。别忘了if..elif..else,使用起来也很方便。

看下面的例子:

1
2
3
4
5
6
7
if [[ `uname` == "Adam" ]]; then
echo "Do not eat an apple!"
elif [[ `uname` == "Eva" ]]; then
echo "Do not take an apple!"
else
echo "Apples are delicious!"
fi

使用case

如果你需要面对很多情况,分别要采取不同的措施,那么使用case会比嵌套的if更有用。使用case来解决复杂的条件判断,看起来像下面这样:

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
case "$extension" in
"jpg"|"jpeg")
echo "It's image with jpeg extension."
;;
"png")
echo "It's image with png extension."
;;
"gif")
echo "Oh, it's a giphy!"
;;
*)
echo "Woops! It's not image!"
;;
esac
`sh中的循环也是只要控制条件为真就一直迭代执行的代码块。

Bash中有四种循环:`for`,`while`,`until`和`select`。

## `for`循环

`for`与它在C语言中的姊妹非常像。看起来是这样:

```bash
for arg in elem1 elem2 ... elemN
do
# 语句
done

在每次循环的过程中,arg依次被赋值为从elem1到elemN。这些值还可以是通配符或者大括号扩展。

当然,我们还可以把for循环写在一行,但这要求do之前要有一个分号,就像下面这样:

1
for i in {1..5}; do echo $i; done

还有,如果你觉得for..in..do对你来说有点奇怪,那么你也可以像C语言那样使用for,比如:

1
2
3
for (( i = 0; i < 10; i++ )); do
echo $i
done

当我们想对一个目录下的所有文件做同样的操作时,for就很方便了。举个例子,如果我们想把所有的.bash文件移动到script文件夹中,并给它们可执行权限,我们的脚本可以这样写:

1
2
3
4
5
6
#!/bin/bash

for FILE in $HOME/*.bash; do
mv "$FILE" "${HOME}/scripts"
chmod +x "${HOME}/scripts/${FILE}"
done

while循环

while循环检测一个条件,只要这个条件为 _真_,就执行一段命令。被检测的条件跟if..then中使用的基元并无二异。因此一个while循环看起来会是这样:

1
2
3
4
while [[ condition ]]
do
# 语句
done

跟for循环一样,如果我们把do和被检测的条件写到一行,那么必须要在do之前加一个分号。

比如下面这个例子:

1
2
3
4
5
6
7
8
#!/bin/bash

# 0到9之间每个数的平方
x=0
while [[ $x -lt 10 ]]; do # x小于10
echo $(( x * x ))
x=$(( x + 1 )) # x加1
done

until循环

until循环跟while循环正好相反。它跟while一样也需要检测一个测试条件,但不同的是,只要该条件为 _假_ 就一直执行循环:

1
2
3
until [[ condition ]]; do
# 语句
done

select循环

select循环帮助我们组织一个用户菜单。它的语法几乎跟for循环一致:

1
2
3
4
select answer in elem1 elem2 ... elemN
do
# 语句
done

select会打印elem1..elemN以及它们的序列号到屏幕上,之后会提示用户输入。通常看到的是$?(PS3变量)。用户的选择结果会被保存到answer中。如果answer是一个在1..N之间的数字,那么语句会被执行,紧接着会进行下一次迭代 —— 如果不想这样的话我们可以使用break语句。

一个可能的实例可能会是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash

PS3="Choose the package manager: "
select ITEM in bower npm gem pip
do
echo -n "Enter the package name: " && read PACKAGE
case $ITEM in
bower) bower install $PACKAGE ;;
npm) npm install $PACKAGE ;;
gem) gem install $PACKAGE ;;
pip) pip install $PACKAGE ;;
esac
break # 避免无限循环
done

这个例子,先询问用户他想使用什么包管理器。接着,又询问了想安装什么包,最后执行安装操作。

运行这个脚本,会得到如下输出:

1
2
3
4
5
6
7
8
$ ./my_script
1) bower
2) npm
3) gem
4) pip
Choose the package manager: 2
Enter the package name: bash-handbook
<installing bash-handbook>

循环控制

我们会遇到想提前结束一个循环或跳过某次循环执行的情况。这些可以使用shell内建的break和continue语句来实现。它们可以在任何循环中使用。

break语句用来提前结束当前循环。我们之前已经见过它了。

continue语句用来跳过某次迭代。我们可以这么来用它:

1
2
3
4
for (( i = 0; i < 10; i++ )); do
if [[ $(( i % 2 )) -eq 0 ]]; then continue; fi
echo $i
done

运行上面的例子,会打印出所有0到9之间的奇数。

函数

在脚本中,我们可以定义并调用函数。跟其它程序设计语言类似,函数是一个代码块,但有所不同。

bash中,函数是一个命令序列,这个命令序列组织在某个名字下面,即 函数名 。调用函数跟其它语言一样,写下函数名字,函数就会被 _调用_ 。

我们可以这样声明函数:

1
2
3
4
5
my_func () {
# 语句
}

my_func # 调用 my_func

我们必须在调用前声明函数。

函数可以接收参数并返回结果 —— 返回值。参数,在函数内部,跟非交互式下的脚本参数处理方式相同 —— 使用位置参数。返回值可以使用return命令 _返回_ 。

下面这个函数接收一个名字参数,返回0,表示成功执行。

1
2
3
4
5
6
7
8
9
10
11
12
# 带参数的函数
greeting () {
if [[ -n $1 ]]; then
echo "Hello, $1!"
else
echo "Hello, unknown!"
fi
return 0
}

greeting Denys # Hello, Denys!
greeting # Hello, unknown!

我们之前已经介绍过返回值。不带任何参数的return会返回最后一个执行的命令的返回值。上面的例子,return 0会返回一个成功表示执行的值,0。

Debugging

shell提供了用于debugging脚本的工具。如果我们想以debug模式运行某脚本,可以在其shebang中使用一个特殊的选项:

1
#!/bin/bash options

options是一些可以改变shell行为的选项。下表是一些可能对你有用的选项:

Short Name Description
-f noglob 禁止文件名展开(globbing)
-i interactive 让脚本以 _交互_ 模式运行
-n noexec 读取命令,但不执行(语法检查)
-t — 执行完第一条命令后退出
-v verbose 在执行每条命令前,向stderr输出该命令
-x xtrace 在执行每条命令前,向stderr输出该命令以及该命令的扩展参数

举个例子,如果我们在脚本中指定了-x例如:

1
2
3
4
5
#!/bin/bash -x

for (( i = 0; i < 3; i++ )); do
echo $i
done

这会向stdout打印出变量的值和一些其它有用的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ./my_script
+ (( i = 0 ))
+ (( i < 3 ))
+ echo 0
0
+ (( i++ ))
+ (( i < 3 ))
+ echo 1
1
+ (( i++ ))
+ (( i < 3 ))
+ echo 2
2
+ (( i++ ))
+ (( i < 3 ))

有时我们需要debug脚本的一部分。这种情况下,使用set命令会很方便。这个命令可以启用或禁用选项。使用-启用选项,+禁用选项:

1
2
3
4
5
6
7
#!/bin/bash

echo "xtrace is turned off"
set -x
echo "xtrace is enabled"
set +x
echo "xtrace is turned off again"

更多资料

  • Bash的man页面。在Bash可以运行的众多环境中,通过运行man bash可以借助帮助系统man来显示Bash的帮助信息。
  • “Bourne-Again SHell manual”

收集一些vba的脚本

Posted on 2016-10-21

分离工作簿

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Sub SaveWorkSheetToBook()
Dim mbook As Workbook
Set mbook = ActiveWorkbook
Dim path As String
path = mbook.FullName
MsgBox path

Dim pos%
pos = InStrRev(path, "\")
path = Left(path, pos)
MsgBox path

Dim i%
For i = 1 To mbook.Worksheets.Count
' MsgBox mbook.Worksheets(i).Name
mbook.Worksheets(i).Copy
ActiveWorkbook.SaveAs Filename:=path & mbook.Worksheets(i).Name & ".xlsx"
ActiveWindow.Close
Next i
End Sub

原码,反码,补码, 大小端

Posted on 2016-09-23

原码, 反码, 补码 详解

机器数与真值

  1. 机器数

    • 一个数在计算机中的二进制表示形式, 叫做这个数的机器数;
    • 机器数是带符号的, 使用最高位为符号位, 正数为0, 负数为1;
    • 如: +3:0000 0011; -3:1000 0011; 这里的二进制就是机器数;
  2. 真值

    • 因为第一位为符号位, 所以机器数的形式值就不等于真正的数值;
    • 如:1000 0011, 其最高位1代表负, 其真正数值是-3而不是形式值131;
    • 将符号位的机器数对应的真正的数值称为机器数的真值;
    • 如: 0000 0001的真值是: +1; 1000 0001的真值是: -1;

==原码, 反码, 补码的基础概念和计算方法==

  1. 原码

    • 原码就是符号位加上真值的绝对值
    • 第一位为符号位,所以8位二进制的范围为: [1111 111, 0111 111]; [-127, 127]
    • 上面的范围缺-128? 后面解释.
    • 最符合人脑的方式;
  2. 反码

    • 正数的反码是其本身;
    • 负数的反码是在其反码的基础上, 符号位不变, 其余位取反:如

      • [+1] = [0000 0001]原 = [0000 0001]反
      • [-1] = [1000 0001]原 = [1111 1110]反
    • 如果一个反码表示负数, 人脑无法直接观看;

  3. 补码

    • 正数的补码是其本身;
    • 负数是其反码+1, 如下:

      • [+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]补
      • [-1] = [1000 0001]原 = [1111 1110]反 = [1111 1111]补

        使用原码,反码,补码的原因

  4. 对于正数都是一样的,所以忽略;

  5. 对于负数,不同, 为什么会存在呢?

    • 对于人脑, 可以知道第一位是符号位, 在计算的时候会根据符号位,选择对真值区域的加减;
    • 对于计算机,加减乘除已经是最基础的运算, 要设计的尽量简单, 计算机辨别”符号位”显然会让基础电路 变的复杂, 于是人们开始考虑让符号位也参与运算的方法;
    • 根据运算规则, 1-1 = 1 + (-1) = 0; 如果机器只有加法没有减法, 计算机运算的设计就更简单了;
    • 人们继续探索将符号位参与运算, 并且只保留加法的方法:

      • 1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [1000 0010]原 = -2 如果用原码表示,让符号位参与运算, 显然对于减法来说, 结果不正确, 这也就是计算机中不使用 原码表示一个数, 为了解决原码做减法的问题, 出现了反码;
      • 1 - 1 = 1 + (-1) = [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0 发现使用反码计算减法, 结果的真值部分是正确的, 但是确出现了-0, 而且-0是没有用, 并且会有 [0000 0000]原 和 [1000 0000]原 俩个编码表示0; 于是出现了补码, 解决了0的符号问题, 以及俩个编码的问题,
      • 1-1 = 1 + (-1) = [0000 0001]补+[1111 1111]补 = [0000 0000]补 = 0 (-1)+(-127) = [1111 1111]补 + [1000 0001]补 = [1000 0000]补 = -128; -1-127的结果是-128, 在用补码运算的结果中, [1000 0000]补 就是-128, 实际就是-0的补码, 所以-128并没有原码和反码表示.
    • 使用补码, 不仅仅修复了0的符号以及存在俩个编码的问题, 而且还能够多表示一个最低数, 这就是为什么8位二进制, 使用原码或反码表示的范围是[-127, 127], 而使用补码表示的范围是[-128, 127];

    • 机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围: [-2^31, 2^31 -1], 因为第一位表示符号位,使用补码表示时可以多保存一个最小值;

原码,反码, 补码 再深入

参考网址:博客园已转载

大端小端

  • 小端: 低位字节存放在内存的低地址端, 高位字节存放在内存的高地址端;
  • 大端: 高位字节存放在内存的低地址端, 低位字节存放在内存的低地址端;
  • 网络字节序: 大端模式;
1
2
3
4
5
6
7
8
9
10
11
如:
十进制: 10 000
二进制: 100111 00010000
十六进制: 0x27 0x10

大端机制存储:
00100111 00010000
0x27 0x10
小端机制存储:
00010000 001000111
0x10 0x27
1
2
3
4
5
6
7
8
9
10
11
// 算法
union {
unsigned int a;
unsigned char b;
}c;
c.a = 1;
if (1 == c.b) {
printf("小端序");
} else {
printf("大端序");
}
1234…6

DaSea

Fucking Code!

51 posts
25 tags
GitHub
© 2018 DaSea
Powered by Hexo v3.7.1
|
Theme — NexT.Gemini v6.3.0