RustFisher

Android App, Java, Python

0%

一些关于文件的操作
例如,实现查看目录内容的功能。类似Linux下的tree命令。
统计目录下指定后缀文件的行数。

功能是将目录下所有的文件路径存入list中。
可以加入后缀判断功能,搜索指定的后缀名文件。
主要利用递归的方法来检索文件。

仿造 tree 功能示例代码

  • Python2.7

列出目录下所有文件
递归法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import os

def tree_dir(path, c_path='', is_root=True):
"""
Get file list under path. Like 'tree'
:param path Root dir
:param c_path Child dir
:param is_root Current is root dir
"""
res = []
if not os.path.exists(path):
return res
for f in os.listdir(path):
if os.path.isfile(os.path.join(path, f)):
if is_root:
res.append(f)
else:
res.append(os.path.join(c_path, f))
else:
res.extend(tree_dir(os.path.join(path, f), f, is_root=False))
return res

下面是加入后缀判断的方法。在找到文件后,判断一下是否符合后缀要求。不符合要求的文件就跳过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def tree_dir_sur(path, c_path='', is_root=True, suffix=''):
""" Get file list under path. Like 'tree'
:param path Root dir
:param c_path Child dir
:param is_root Current is root dir
:param suffix Suffix of file
"""
res = []
if not os.path.exists(path) or not os.path.isdir(path):
return res
for f in os.listdir(path):
if os.path.isfile(os.path.join(path, f)) and str(f).endswith(suffix):
if is_root:
res.append(f)
else:
res.append(os.path.join(c_path, f))
else:
res.extend(tree_dir_sur(os.path.join(path, f), f, is_root=False, suffix=suffix))
return res

if __name__ == "__main__":
for p in tree_dir_sur(os.path.join('E:\ws', 'rnote', 'Python_note'), suffix='md'):
print p

统计目录下指定后缀文件的行数

仅适用os中的方法,仅检索目录中固定位置的文件

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
# -*- coding: utf-8 -*-
import os


def count_by_categories(path):
""" Find all target files and count the lines """
if not os.path.exists(path):
return
c_l_dict = dict() # e.g. {category: lines}
category_list = [cate for cate in os.listdir(path) if
os.path.isdir(os.path.join(path, cate)) and not cate.startswith('.')]
for category_dir in category_list:
line_count = _sum_total_line(os.path.join(path, category_dir), '.md')
if line_count > 0:
c_l_dict[category_dir] = line_count
return c_l_dict


def _sum_total_line(path, endswith='.md'):
""" Get the total lines of target files """
if not os.path.exists(path) or not os.path.isdir(path):
return 0
total_lines = 0
for f in os.listdir(path):
if f.endswith(endswith):
with open(os.path.join(path, f)) as cur_f:
total_lines += len(cur_f.readlines())
return total_lines


if __name__ == '__main__':
note_dir = 'E:/ws/rnote'
ca_l_dict = count_by_categories(note_dir)
all_lines = 0
for k in ca_l_dict.keys():
all_lines += ca_l_dict[k]

print 'all lines:', str(all_lines)
print ca_l_dict

以笔记文件夹为例,分别统计分类目录下文件的总行数,测试输出

1
2
all lines: 25433
{'flash_compile_git_note': 334, 'Linux_note': 387, 'Algorithm_note': 3637, 'Comprehensive': 216, 'advice': 137, 'Java_note': 3013, 'Android_note': 11552, 'DesignPattern': 2646, 'Python_note': 787, 'kotlin': 184, 'cpp_note': 279, 'PyQt_note': 439, 'reading': 686, 'backend': 1136}

本文链接Python 操作 MySQL

开发环境与配置

  • win_x64
  • Ubuntu14.04
  • Python3.x

pip安装pymysql模块

直接使用pip安装 pip install pymysql
win64上直接在cmd中执行

连接本地数据库

使用模块pymysql连接数据库
本地数据库相关配置请参阅:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/python
# coding=utf-8
import pymysql

# 连接本地数据库
conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='yourpwd', db='samp_db1', charset='utf8')
cursor = conn.cursor()
cursor.execute('select * from bigstu')
for row in cursor.fetchall():
print(row)

# 查
cursor.execute('select id, name from bigstu where age > 22')
for res in cursor.fetchall():
print(str(res[0]) + ", " + res[1])

cursor.close()
print('-- end --')

输出:

1
2
3
4
5
6
7
(1, '张三', '男', 24, datetime.date(2017, 3, 29), '13666665555')
(6, '小刚', '男', 23, datetime.date(2017, 3, 11), '778899888')
(8, '小霞', '女', 20, datetime.date(2017, 3, 13), '13712345678')
(12, '小智', '男', 21, datetime.date(2017, 3, 7), '13787654321')
1, 张三
6, 小刚
-- end --

可以直接执行sql语句。获得的结果是元组。

sql相似条件查询

1
SELECT * FROM anindex.subject_basic_table where season_id having '2018';

插入数据

插入一条数据,接上面的代码

1
2
3
4
insertSql = "insert into bigstu (name, sex, age,  mobile) values ('%s','%s',%d,'%s') "
xiuji = ('秀吉', '男', 15, '13400001111')
cursor.execute(insertSql % xiuji)
conn.commit() # 别忘了提交

添加列

在mobile后面添加一列cash

1
2
addCo = "alter table bigstu add cash int after mobile"
cursor.execute(addCo)

如果要设置默认值

1
2
addCo = "alter table bigstu add cash int default 0 after mobile"
cursor.execute(addCo)

删除数据

删除 name=秀吉 的数据

1
2
deleteSql = "delete from bigstu where name = '%s'"
cursor.execute(deleteSql % '秀吉')

删除列

删除cash列

1
2
dropCo = "alter table bigstu drop cash"
cursor.execute(dropCo)

修改数据

更新符合条件的数据

1
2
3
4
updateSql = "update bigstu set sex = '%s' where name = '%s'"
updateXiuji = ('秀吉', '秀吉') # 秀吉的性别是秀吉
cursor.execute(updateSql % updateXiuji)
conn.commit()

事物处理

给某个记录的cash增加

1
2
3
4
5
6
7
8
9
10
11
table = "bigstu"
addCash = "update " + table + " set cash = cash + '%d' where name = '%s'"
lucky = (1000, "秀吉")

try:
cursor.execute(addCash % lucky)
except Exception as e:
conn.rollback()
print("加钱失败了")
else:
conn.commit()

直接执行SQL语句,十分方便

代码片段

给数据库添加列

从json中读取需要添加的列名,获取当前2个表中所有的列名
整理得出需要插入的列名,然后将列插入到相应的表中

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
import pymysql
import json
import os
import secureUtils

mapping_keys = json.load(open("key_mapping_db.json", "r"))
db_keys = [] # json中所有的key

for k in mapping_keys.values():
db_keys.append(k)

conn = pymysql.connect(host='localhost', port=3306, user='root',
passwd='*****', db='db_name', charset='utf8')

cursor = conn.cursor()
table_main = "table_main"
main_table_keys = [] # 主表的列名
cursor.execute("show columns from " + table_main)
for row in cursor.fetchall():
main_table_keys.append(row[0])

staff_table_keys = []
cursor.execute("show columns from table_second")
for row in cursor.fetchall():
staff_table_keys.append(row[0])

need_to_insert_keys = []
for k in db_keys:
if k not in staff_table_keys and k not in main_table_keys and k not in need_to_insert_keys:
need_to_insert_keys.append(k)

print("need to insert " + str(len(need_to_insert_keys)))
print(need_to_insert_keys)
for kn in need_to_insert_keys:
print("add key to db " + kn)
cursor.execute("alter table staff_table add " + kn +" text")

conn.close()

将字段字符改变

这里将main_table_keys中的所有字段改为utf8

1
2
3
4
5
# change column character set to utf8
for co in main_table_keys:
change_sql = "alter table " + table_main + " modify " + co + " text character set utf8"
print(change_sql)
cursor.execute(change_sql)

JSON与Dictionary简介

  • Python3
  • PyCharm CE

JSON简介

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。
它是一种文本格式。它的结构主要由键值对来构成。
一个键(key)对应一个值(value)。最外围用大括号{ }包围起来。
例如

1
2
3
4
{
"firstName": "Rust",
"lastName": "Fisher"
}

大括号括起来的叫做对象结构

JSON里也可以放数组。用中括号[ ]括起来。叫做数组结构

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"desc":"这个是一个简单的例子",
"userInfo":{
"firstName":"Rust",
"lastName":"Fisher"
},
"books":[
"Python入门",
"Python进阶",
"数据分析",
"可视化"
]
}

对象结构和数组结构可以同时存在,只要满足键值对的要求即可。

最外层也可以是中括号括起来的,里面存放着多个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[
{
"firstName": "Tom",
"lastName": "Hanks",
"movies": ["Cast Away"]
},
{
"userInfo": {
"firstName": "Rust",
"lastName": "Fisher"
},
"books": ["Python入门", "Python进阶"],
"desc": "可以直接添加一个key-value进去"
}
]

Python的Dictionary(字典)简介

Dictionary(以下简称为dict或字典)是一种键值对数据结构。
有点像Java里的Map和Set。

初始化一个dict可以直接用大括号。里面写上key和value。

1
2
3
4
5
6
7
8
9
10
def use_dict():
user_info = {'firstName': 'Rust', 'lastName': 'Fisher'}
books = ['Python入门']
books.append('Python进阶')
result = {'userInfo': user_info, 'books': books}
result['desc'] = '可以直接添加一个key-value进去'
print(result)

# 运行结果
# {'userInfo': {'firstName': 'Rust', 'lastName': 'Fisher'}, 'books': ['Python入门', 'Python进阶'], 'desc': '可以直接添加一个key-value进去'}

可以看到,dict和JSON有些类似。都是键值对,都有数组结构。
从Python语法上来看,dict操作起来也比较简单。找到确定的key后,可以直接赋值。

Dictionary 转为JSON

Python中的dict是一种键值对的数据结构。
JSON是一种轻量级的数据交换格式,它是一种文本格式
它们都是以键值对为基础。那么它们应该能相互转换。

将dict转为JSON,这里利用json包里提供的dumps方法。

dumps方法将传入的dict转换成JSON格式的文本。

引入json

1
import json

我们写出了第一个dict转JSON的方法

1
2
3
4
def to_json1(input_dict):
print('input:', input_dict)
jsonTxt = json.dumps(input_dict)
print(jsonTxt)

输出:

1
2
input: {'userInfo': {'firstName': 'Rust', 'lastName': 'Fisher'}, 'books': ['Python入门', 'Python进阶'], 'desc': '可以直接添加一个key-value进去'}
{"userInfo": {"firstName": "Rust", "lastName": "Fisher"}, "books": ["Python\u5165\u95e8", "Python\u8fdb\u9636"], "desc": "\u53ef\u4ee5\u76f4\u63a5\u6dfb\u52a0\u4e00\u4e2akey-value\u8fdb\u53bb"}

中文字符都变成了字母和数字符号。这有点出乎我们意料。

涉及到中文字符的时候,需要dumps方法里指定ensure_ascii=False

1
2
3
4
def to_json2(input_dict):
print('input:', input_dict)
jsonTxt = json.dumps(input_dict, ensure_ascii=False)
print(jsonTxt)

输出:

1
2
input: {'userInfo': {'firstName': 'Rust', 'lastName': 'Fisher'}, 'books': ['Python入门', 'Python进阶'], 'desc': '可以直接添加一个key-value进去'}
{"userInfo": {"firstName": "Rust", "lastName": "Fisher"}, "books": ["Python入门", "Python进阶"], "desc": "可以直接添加一个key-value进去"}

这样中文字符就ok了。

list转为JSON

list中存储着多个dict。可以直接把list转为JSON。

接上面的代码

1
2
3
4
5
6
7
def list_json_demo():
tom_hanks = {'firstName': 'Tom', 'lastName': 'Hanks', 'movies': ['Cast Away']}
info = use_dict()
list = [tom_hanks, info]
jsonTxt = json.dumps(list, ensure_ascii=False)
print(jsonTxt)
return jsonTxt

输出的JSON部分:

1
[{"firstName": "Tom", "lastName": "Hanks", "movies": ["Cast Away"]}, {"userInfo": {"firstName": "Rust", "lastName": "Fisher"}, "books": ["Python入门", "Python进阶"], "desc": "可以直接添加一个key-value进去"}]

读取JSON文本

json.loads方法将输入的JSON文本转为对象。

1
2
3
def json_to_dict1(jsonTxt):
obj1 = json.loads(jsonTxt)
print(obj1)

得到的对象可能是数组或者是dict。

读取JSON文件

先打开文件,用json.load方法,读取JSON内容

1
2
3
with open(json_file_path) as json_file:
json_content = json.load(json_file) # 读取出来的是dict
# ...

  • Ubuntu 14.04

pip 使用国内镜像源

使用pip install 的时候总是出现read timeout 之类的错误

使用国内镜像 https://pypi.tuna.tsinghua.edu.cn/simple
例如我要安装 scrapy

1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple scrapy

添加源的配置

Linux下,修改 ~/.pip/pip.conf (没有就创建一个), 修改 index-url至tuna,内容如下:

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

pip install 出错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ pip install pycairo
Collecting pycairo
Downloading https://files.pythonhosted.org/packages/e8/9d/c8be300fc6b1298559d37a071c3833b0b251e0fff334d2e4c408d5789162/pycairo-1.19.1.tar.gz (205kB)
100% |████████████████████████████████| 215kB 644kB/s
Installing collected packages: pycairo
Running setup.py install for pycairo ... error
Complete output from command /Users/rustfisher/Desktop/intGo/studySR/venv/bin/python -u -c "import setuptools, tokenize;__file__='/private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-install-jhvl5plj/pycairo/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-record-dqg8zbp0/install-record.txt --single-version-externally-managed --compile --install-headers /Users/rustfisher/Desktop/intGo/studySR/venv/include/site/python3.7/pycairo:
running install
running build
running build_py
creating build
creating build/lib.macosx-10.9-x86_64-3.7
creating build/lib.macosx-10.9-x86_64-3.7/cairo
copying cairo/__init__.py -> build/lib.macosx-10.9-x86_64-3.7/cairo
copying cairo/__init__.pyi -> build/lib.macosx-10.9-x86_64-3.7/cairo
copying cairo/py.typed -> build/lib.macosx-10.9-x86_64-3.7/cairo
running build_ext
[Errno 20] Not a directory: 'pkg-config'

----------------------------------------
Command "/Users/rustfisher/Desktop/intGo/studySR/venv/bin/python -u -c "import setuptools, tokenize;__file__='/private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-install-jhvl5plj/pycairo/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-record-dqg8zbp0/install-record.txt --single-version-externally-managed --compile --install-headers /Users/rustfisher/Desktop/intGo/studySR/venv/include/site/python3.7/pycairo" failed with error code 1 in /private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-install-jhvl5plj/pycairo/
You are using pip version 10.0.1, however version 20.2.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

用brew安装pkg-config

1
2
3
4
5
 $ brew install pkg-config
==> Downloading https://mirrors.ustc.edu.cn/homebrew-bottles/bottles/pkg-config-0.29.2_3.mojave.bottle.tar.g
######################################################################## 100.0%
==> Pouring pkg-config-0.29.2_3.mojave.bottle.tar.gz
🍺 /usr/local/Cellar/pkg-config/0.29.2_3: 11 files, 623.6KB

然后再运行pip install pycairo
出现错误

Collecting pycairo
Using cached pycairo-1.19.1.tar.gz (205 kB)
Using legacy setup.py install for pycairo, since package ‘wheel’ is not installed.
Installing collected packages: pycairo
Running setup.py install for pycairo … error
ERROR: Command errored out with exit status 1:
command: /Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7 -u -c ‘import sys, setuptools, tokenize; sys.argv[0] = ‘“‘“‘/private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-install-_fvz20yx/pycairo/setup.py’”‘“‘; file=’”‘“‘/private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-install-_fvz20yx/pycairo/setup.py’”‘“‘;f=getattr(tokenize, ‘“‘“‘open’”‘“‘, open)(file);code=f.read().replace(‘“‘“‘\r\n’”‘“‘, ‘“‘“‘\n’”‘“‘);f.close();exec(compile(code, file, ‘“‘“‘exec’”‘“‘))’ install –record /private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-record-0xkj4in4/install-record.txt –single-version-externally-managed –compile –install-headers /Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m/pycairo
cwd: /private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-install-_fvz20yx/pycairo/
Complete output (15 lines):
running install
running build
running build_py
creating build
creating build/lib.macosx-10.9-x86_64-3.7
creating build/lib.macosx-10.9-x86_64-3.7/cairo
copying cairo/init.py -> build/lib.macosx-10.9-x86_64-3.7/cairo
copying cairo/init.pyi -> build/lib.macosx-10.9-x86_64-3.7/cairo
copying cairo/py.typed -> build/lib.macosx-10.9-x86_64-3.7/cairo
running build_ext
Package cairo was not found in the pkg-config search path.
Perhaps you should add the directory containing `cairo.pc’
to the PKG_CONFIG_PATH environment variable
No package ‘cairo’ found

Command '['pkg-config', '--print-errors', '--exists', 'cairo >= 1.13.1']' returned non-zero exit status 1.
----------------------------------------

ERROR: Command errored out with exit status 1: /Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7 -u -c ‘import sys, setuptools, tokenize; sys.argv[0] = ‘“‘“‘/private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-install-_fvz20yx/pycairo/setup.py’”‘“‘; file=’”‘“‘/private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-install-_fvz20yx/pycairo/setup.py’”‘“‘;f=getattr(tokenize, ‘“‘“‘open’”‘“‘, open)(file);code=f.read().replace(‘“‘“‘\r\n’”‘“‘, ‘“‘“‘\n’”‘“‘);f.close();exec(compile(code, file, ‘“‘“‘exec’”‘“‘))’ install –record /private/var/folders/ds/b1cvbdm97dz7bynp0xzr3f7c0000gn/T/pip-record-0xkj4in4/install-record.txt –single-version-externally-managed –compile –install-headers /Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m/pycairo Check the logs for full command output.

执行brew install cairo pkg-config freetype harfbuzz,把这几个包安装一下。
然后再pip install pycairo,安装成功。

定义

将一个类的接口变换成客户端锁期待的另一种接口,从而使原本因接口不匹配而无法工作在一起的两个类能够在一起工作。
也叫作变压器模式,亦称包装模式,但包装模式不止一个。
简单而言,适配器模式就是把一个接口或类转换成其他的接口或类。

应用

优点:

  • 可以让没有任何关系的类在一起运行
  • 增加了类的透明性
  • 提高了类的复用度
  • 灵活度好

注意事项:在详细阶段不要考虑适配器模式,它主要是用来解决正在服役的项目问题

代码示例

向已运行的系统添加新增的用户类型

文件目录如下

1
2
3
4
5
6
7
8
9
10
11
12
adapter/
├── sadapter // 新增的适配器代码
│   ├── SecondUserAdapter.java
│   ├── SecondUserAddress.java
│   └── SecondUser.java
├── stable // 已经在运行的代码,不可变
│   ├── FirstUser.java
│   └── IFirstUser.java
├── TestAdapter.java // 测试代码
└── updated // 第三方提供的接口,不可变
├── ISecondUserAddress.java
└── ISecondUser.java

首先看已经在运行的部分 (stable)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface IFirstUser {
void printInfo();
}
public class FirstUser implements IFirstUser {

private String username;

public FirstUser(String username) {
this.username = username;
}

@Override
public void printInfo() {
System.out.println(this.username);
}
}

再看按需求添加的部分 (updated)

1
2
3
4
5
6
public interface ISecondUser {
void printUsername();
}
public interface ISecondUserAddress {
void printAddress();
}

为此新建的适配器 (sadapter)
分别新建2个类来实现接口

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
public class SecondUser implements ISecondUser {

private String username;

public SecondUser(String name) {
this.username = name;
}

@Override
public void printUsername() {
System.out.print(username + " ");
}
}

public class SecondUserAddress implements ISecondUserAddress {

private String addr;

public SecondUserAddress(String address) {
this.addr = address;
}

@Override
public void printAddress() {
System.out.print(this.addr);
}
}

适配器持有这两个接口的引用,并实现原有的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SecondUserAdapter implements IFirstUser {

private ISecondUser iSecondUser;
private ISecondUserAddress iSecondUserAddress;

public SecondUserAdapter(ISecondUser iSecondUser, ISecondUserAddress iSecondUserAddress) {
this.iSecondUser = iSecondUser;
this.iSecondUserAddress = iSecondUserAddress;
}

@Override
public void printInfo() {
iSecondUser.printUsername();
iSecondUserAddress.printAddress();
}
}

适配器构建完毕,测试代码

1
2
3
4
5
IFirstUser user1 = new FirstUser("User1");
user1.printInfo();
SecondUserAdapter userAdapter =
new SecondUserAdapter(new SecondUser("SUser2"),new SecondUserAddress("5 street"));
userAdapter.printInfo();

output
1
2
User1
SUser2 5 street

最吸引人的地方就是适配器实现了原有的接口。需求变化时,可尽量少的改动已有代码。

参考:《设计模式之禅》 秦小波

环境: win7_x64, Navicat for MySQL

本文链接

操作数据库

前面已经将MySQL服务跑起来了。

现在我们以root身份进行MySQL操作
进入MySQL

1
C:\Users\Administrator>mysql -uroot -p

新建数据库

1
2
mysql> create database samp_db1 character set gbk;
Query OK, 1 row affected (0.00 sec)

数据库字符编码指定为 gbk

选择要操作的数据库

已经登录后可以直接选择数据库

1
2
mysql> use samp_db1;
Database changed

创建数据表

以建立person_t数据表为例

1
2
3
4
5
6
7
8
mysql> create table person_t (
-> id int unsigned not null auto_increment primary key,
-> name char(14) not null,
-> sex char(4) not null,
-> age tinyint unsigned not null,
-> tell char(13) null default "-"
-> );
Query OK, 0 rows affected (0.22 sec)

打开Navicat for MySQL,可以看到我们新建的表

输入这么长的文本很容易出错,我们可以直接先写好SQL语句,再导进来

新建文件create_student_table.sql,输入SQL语句

1
2
3
4
5
6
7
create table student (
id int unsigned not null auto_increment primary key,
name char(14) not null,
sex char(4) not null,
age tinyint unsigned not null,
tell char(13) null default "-"
);

直接执行SQL文件,操作samp_db1数据库

1
2
3
C:\Users\Administrator>mysql -D samp_db1 -u root -p < H:\create_student_table.sq
l
Enter password: ****

操作数据库

选定要操作的数据库use samp_db1;

增 - 插入数据

insert [into] 表名 [(列名1, 列名2, 列名3, …)] values (值1, 值2, 值3, …);

1
2
mysql> insert into student values(null,"张三","男",23,"13666665555");
mysql> insert into student (name,sex,age) values("李四","女",20);
查 - 查询表中的数据

select 列名称 from 表名称 [查询条件];

多插入了一些数据后

1
2
3
4
5
6
7
8
9
10
11
mysql> select name, age from student;
+-------+-----+
| name | age |
+-------+-----+
| 张三 | 23 |
| 李四 | 20 |
| Tom | 13 |
| Jerry | 12 |
| 王五 | 32 |
+-------+-----+
5 rows in set (0.00 sec)
使用通配符*来查询
1
2
3
4
5
6
7
8
9
10
11
mysql> select * from student;
+----+-------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+-------+-----+-----+-------------+
| 1 | 张三 | 男 | 23 | 13666665555 |
| 2 | 李四 | 女 | 20 | - |
| 3 | Tom | 男 | 13 | 13111115555 |
| 4 | Jerry | 男 | 12 | 2333333 |
| 5 | 王五 | 男 | 32 | 666666666 |
+----+-------+-----+-----+-------------+
5 rows in set (0.00 sec)
特定条件查询

where 关键词用于指定查询条件, 用法形式为: select 列名称 from 表名称 where 条件;

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// 查询所有性别为女的记录
mysql> select * from student where sex="女";
+----+------+-----+-----+------+
| id | name | sex | age | tell |
+----+------+-----+-----+------+
| 2 | 李四 | 女 | 20 | - |
+----+------+-----+-----+------+
1 row in set (0.04 sec)

// age大于20的记录
mysql> select * from student where age>20;
+----+------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+------+-----+-----+-------------+
| 1 | 张三 | 男 | 23 | 13666665555 |
| 5 | 王五 | 男 | 32 | 666666666 |
+----+------+-----+-----+-------------+
2 rows in set (0.00 sec)

// age小于等于20的记录
mysql> select * from student where age<=20;
+----+-------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+-------+-----+-----+-------------+
| 2 | 李四 | 女 | 20 | - |
| 3 | Tom | 男 | 13 | 13111115555 |
| 4 | Jerry | 男 | 12 | 2333333 |
+----+-------+-----+-----+-------------+
3 rows in set (0.00 sec)

// age小于等于20并且id大于等于3的记录
mysql> select * from student where age<=20 and id >=3;
+----+-------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+-------+-----+-----+-------------+
| 3 | Tom | 男 | 13 | 13111115555 |
| 4 | Jerry | 男 | 12 | 2333333 |
+----+-------+-----+-----+-------------+
2 rows in set (0.03 sec)

// 按名字特征查询
mysql> select * from student where name like "%三%";
+----+------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+------+-----+-----+-------------+
| 1 | 张三 | 男 | 23 | 13666665555 |
+----+------+-----+-----+-------------+
1 row in set (0.00 sec)

mysql> select * from student where name like "%o%";
+----+------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+------+-----+-----+-------------+
| 3 | Tom | 男 | 13 | 13111115555 |
+----+------+-----+-----+-------------+
1 row in set (0.00 sec)

// tell 以5结尾的记录
mysql> select * from student where tell like "%5";
+----+------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+------+-----+-----+-------------+
| 1 | 张三 | 男 | 23 | 13666665555 |
| 3 | Tom | 男 | 13 | 13111115555 |
+----+------+-----+-----+-------------+
2 rows in set (0.00 sec)

mysql> select * from student where tell like "131%";
+----+------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+------+-----+-----+-------------+
| 3 | Tom | 男 | 13 | 13111115555 |
+----+------+-----+-----+-------------+
1 row in set (0.00 sec)

按条件查询非常的灵活,运用得当会节省运行时间

改 - 修改表中的数据

基本的使用形式为:

update 表名称 set 列名称=新值 where 更新条件;

我们终于拿到了李四的联系方式,将数据库中的tell更新

1
2
3
4
5
6
7
8
9
10
11
mysql> update student set tell="13900001111" where name="李四";
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from student where name="李四";
+----+------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+------+-----+-----+-------------+
| 2 | 李四 | 女 | 20 | 13900001111 |
+----+------+-----+-----+-------------+
1 row in set (0.00 sec)

过了一年,大家都长了一岁,修改表中的age值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> update student set age=age+1;
Query OK, 5 rows affected (0.05 sec)
Rows matched: 5 Changed: 5 Warnings: 0

mysql> select * from student;
+----+-------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+-------+-----+-----+-------------+
| 1 | 张三 | 男 | 24 | 13666665555 |
| 2 | 李四 | 女 | 21 | 13900001111 |
| 3 | Tom | 男 | 14 | 13111115555 |
| 4 | Jerry | 男 | 13 | 2333333 |
| 5 | 王五 | 男 | 33 | 666666666 |
+----+-------+-----+-----+-------------+
5 rows in set (0.00 sec)

修改多个信息,Jerry有了中文名“赵六”,换了tell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> update student set name="赵六",tell="10001-1001" where name="Jerry";
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from student;
+----+------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+------+-----+-----+-------------+
| 1 | 张三 | 男 | 24 | 13666665555 |
| 2 | 李四 | 女 | 21 | 13900001111 |
| 3 | Tom | 男 | 14 | 13111115555 |
| 4 | 赵六 | 男 | 13 | 10001-1001 |
| 5 | 王五 | 男 | 33 | 666666666 |
+----+------+-----+-----+-------------+
5 rows in set (0.00 sec)
删 - 删除表中的数据

基本用法为:

delete from 表名称 where 删除条件;

年龄太小不能入学

1
2
3
4
5
6
7
8
9
10
11
12
mysql> delete from student where age < 18;
Query OK, 2 rows affected (0.04 sec)

mysql> select * from student;
+----+------+-----+-----+-------------+
| id | name | sex | age | tell |
+----+------+-----+-----+-------------+
| 1 | 张三 | 男 | 24 | 13666665555 |
| 2 | 李四 | 女 | 21 | 13900001111 |
| 5 | 王五 | 男 | 33 | 666666666 |
+----+------+-----+-----+-------------+
3 rows in set (0.00 sec)

修改现有的表

alter table 语句用于修改现有表

添加列

alter table 表名 add 列名 列数据类型 [after 插入位置];

在表的最后添加address列
mysql> alter table student add address char(70);

在名为 age 的列后插入列 birthday
mysql> alter table student add birthday date after age;

此时的表

1
2
3
4
5
6
7
8
mysql> select * from student;
+----+------+-----+-----+----------+-------------+---------+
| id | name | sex | age | birthday | tell | address |
+----+------+-----+-----+----------+-------------+---------+
| 1 | 张三 | 男 | 24 | NULL | 13666665555 | NULL |
| 2 | 李四 | 女 | 21 | NULL | 13900001111 | NULL |
| 5 | 王五 | 男 | 33 | NULL | 666666666 | NULL |
+----+------+-----+-----+----------+-------------+---------+

列的名字不能是mysql的关键字,比如不能是index

修改列

基本形式: alter table 表名 change 列名称 列新名称 新数据类型;

将tell列名修改为mobile
alter table student change tell mobile char(13) default "-";

修改name列的类型为char(11) not null

1
2
3
mysql> alter table student change name name char(11) not null;
Query OK, 3 rows affected (0.54 sec)
Records: 3 Duplicates: 0 Warnings: 0
删除列

alter table 表名 drop 列名称;

删除address列 alter table student drop address;

重命名表

alter table 表名 rename 新表名;

重命名表student -> bigstu alter table student rename bigstu;

删除整张表

drop table 表名;
删掉前面我们创建的person_t

1
2
mysql> drop table person_t;
Query OK, 0 rows affected (0.12 sec)

删除整个数据库

drop database 数据库名;

新建一个数据库samp_4_delete,再删除它

1
2
3
4
5
mysql> create database samp_4_delete;
Query OK, 1 row affected (0.00 sec)

mysql> drop database samp_4_delete;
Query OK, 0 rows affected (0.01 sec)

复制schema

没有特定的复制命令。思路是新建一个目标schema,然后把原数据库中的表全部复制到新建的库中去。

参考:

本章目的

  • Build types 构建类型
  • Product flavors
  • Build variants 构建不同种类
  • Signing configurations

开发APP时,会有生成不同版本的需求。比如测试版本和发布版本。不同版本之间通常有不同的设置。

Build types

定义APP或者模块该被如何构建。

可以用buildTypes来定义构建类型。例如:

1
2
3
4
5
6
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

默认的build.gradle文件会包含一个release构建类型

创建构建类型

比如创建一个staging构建类型

1
2
3
4
5
6
7
8
9
10
buildTypes {
// staging 是一个自定义名字
// 生成signed App时可以选择这个类型
staging.initWith(buildTypes.debug)
staging {
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
buildConfigField("String", "BASE_URL", "\"http://www.staging.com\"")
}
}

这里定义了applicationIdSuffix,让staging版本的applicationId和release版本的不同。

initWith()创建一个新的构建类型并复制现有的构建类型。用这个方法可以复写已有的构建类型。

资源目录

创建了新的构建类型后,可以建立新的资源文件。例如我们已经有了staging构建类型

1
2
3
4
5
6
7
8
src
├── androidTest
├── debug
├── greenRelease
├── main
├── redDebug
├── staging// 可以新建资源目录
└── test

不同资源目录里的文件可以用相同的文件名。

main目录里的strings.xml

1
2
3
<resources>
<string name="app_name">GDemo</string>
</resources>

1
2
3
4
<resources>
<!-- staging strings.xml -->
<string name="app_name">GStaging</string>
</resources>

生成不同版本的app时,会自动去找相应的资源文件

依赖包管理

每一种构建类型可以有自己的依赖。Gradle自动为每个类型创建依赖配置。
下面就是单独为debug版本添加logging模块的依赖

1
2
3
4
5
6
7
8
9
10
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.1.1'
testCompile 'junit:junit:4.12'

debugCompile 'de.mindpipe.android:android-logging-log4j:1.0.3'
}

Product flavors 产品特征

product flavors用于创建同一个APP的不同版本。最直接的例子就是免费和付费版APP。

当我们要发布APP时,可以选择release或者staging(上面的例子)版。但是对同一个构建类型,比如对
于release版,我们可以用Product flavors打包出有各自特征的APP。比如:

1
2
3
4
5
6
7
8
9
10
11
// 多渠道打包可以用在这里配置
// 一旦配置了productFlavors,生成apk时会默认选其中一个选项
productFlavors {
red {
versionName "1.0-red"
}
green {
applicationId "com.rustfisher.gradletest.green" // 使用另一个签名
versionNameSuffix "-green"// 版本名添加后缀
}
}

资源文件

新建了productFlavors类型后,我们可以新建相应的资源目录。

1
2
3
4
5
6
7
8
src
├── androidTest
├── debug
├── greenRelease // release版本 采用green
├── main
├── redDebug // debug版本 采用red
├── staging
└── test

多种特种的变量 Multiflavor variants

在Product flavors中可以进行组合,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
android {

flavorDimensions("color", "price") // 新建了2种类型

// 多渠道打包可以用在这里配置
// 一旦配置了productFlavors,debug时会默认选一个选项
productFlavors {
red {
versionName "1.0-red"
dimension "color"
}
green {
applicationId "com.rustfisher.gradletest.green" // 使用另一个签名
versionNameSuffix "-green"
dimension "color"
}
freeApp {
dimension "price"
}
paidApp {
dimension "price"
}
}
}

那么在打包apk时,可以有如下4种版本

1
2
3
4
green-freeApp 
green-paidApp
red-freeApp
red-paidApp

一旦添加flavorDimensions,就必须为每一个flavor制定dimension。
就像上面的colorprice必须出现在下面4种productFlavors之中。否则会报错。

Build Variants

Android Studio左下角可以打开Build Variants窗口。选择模块和Build Variants
前面配置的构建类型都会在这个列表中出现。

Tasks 任务

Android plugin for Gradle 会自动为每个配置的构建类型创建任务。
新建项目时,会有默认的assembleDebug 和 assembleRelease。
经过上面的配置以后,会有产生相对应的任务

1
2
3
4
5
6
7
8
9
10
11
12
13
assemble
assembleAndroidTest
assembleDebug
assembleFreeApp
assembleGreen
assembleGreenFreeApp
assembleGreenPaidApp
assemblePaidApp
assembleRed
assembleRedFreeApp
assembleRedPaidApp
assembleRelease
assembleStaging

Resource and manifest merging

Android的Gradle插件会在打包app前将主要资源和构建类型资源合在一起。另外,lib工程也可以提供
额外可被合并的资源文件。manifest文件也可被合并。比如在debug版本中申请正式版中不需要的权限。

定义构建变量

给productFlavors中的类型添加资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
productFlavors {
red {
versionName "1.0-red"
dimension "color"
resValue("color", "flavor_color", "#ff0000")
}
green {
applicationId "com.rustfisher.gradletest.green" // 使用另一个签名
versionNameSuffix "-green"
resValue("color", "flavor_color", "#00ff00")
dimension "color"
}
// ...
}

上面的flavor_color可以在代码中通过R文件找到R.color.flavor_color

参考:Gradle for Android Kevin Pelgrims

win7 Android Studio 2.1.3

基础自定义构建 Basic Build Customization

本章目的

  • 理解Gradle文件
  • build tasks入门
  • 自定义构建

理解Gradle文件

在Android Studio中新建一个项目后,会自动创建3个Gradle文件。

1
2
3
4
5
MyApp
├── build.gradle
├── settings.gradle
└── app
└── build.gradle

每个文件都有自己的作用

settings.gradle文件

新建工程的settings文件类似下面这样

1
include ':app'

Gradle为每个settings文件创建Settings对象,并调用其中的方法。

The top-level build file 最外层的构建文件

能对工程中所有模块进行配置。如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.3'

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

buildscript代码块是具体配置的地方,引用JCenter仓库。
本例中,一个仓库代表着依赖库,换句话说是app可以从中下载使用库文件。
JCenter是一个有名的 Maven 仓库。

dependencies代码块用来配置依赖。上面注释说明了,不要在此添加依赖,而应该到独立的模块
中去配置依赖。

allprojects能对所有模块进行配置。

模块中的build文件

模块中的独立配置文件,会覆盖掉top-level的build.gradle文件

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
apply plugin: 'com.android.application'

android {
compileSdkVersion 25
buildToolsVersion "25.0.2"

defaultConfig {
applicationId "com.xxx.rust.newproj"
minSdkVersion 18
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.1.0'
}

下面来看3个主要的代码块。

plugin

第一行应用了Android 应用插件。Android插件由Google团队开发维护。该插件提供构建,测试,打包应用和模块需要的所有的task。

android

最大的一个区域。defaultConfig区域对app核心进行配置,会配置覆盖AndroidManifest.xml中的配置。

applicationId复写掉manifest文件中的包名。但applicationId和包名有区别。
manifest中的包名,在源代码和R文件中使用。所以package name在android studio中理解为一个查询类的路径比较合理。
applicationId在Android系统中是作为应用的唯一标识,即在一个Android设备中所有的应用程序的applicationId都是唯一的。

dependencies

是Gradle标准配置的一部分。
Android中用来配置使用到的库。

定制化构建 Customizing the build

BuildConfig and resources

自从SDK17以来,构建工具会生成一个BuildConfig类,包含着静态变量DEBUG和一些信息。
如果你想在区分debug和正式版,比如打log,这个BuildConfig类很有用。
可以通过Gradle来扩展这个类,让它拥有更多的静态变量。

以NewProj工程为例,app\build.gradle

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
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"

defaultConfig {
applicationId "com.xxx.rust.newproj"
minSdkVersion 18
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
buildTypes {
debug {
buildConfigField("String", "BASE_URL", "\"http://www.baidu.com\"")
buildConfigField("String", "A_CONTENT", "\"debug content\"")
resValue("string", "str_version", "debug_ver")
}
release {
buildConfigField("String", "BASE_URL", "\"http://www.qq.com\"")
buildConfigField("String", "A_CONTENT", "\"release content\"")
resValue("string", "str_version", "release_ver")

minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

上面的buildConfigFieldresValue在编译后,能在源代码中使用
注意上面那个转义的分号不可少;注意里面的大小写,这里传入的参数就像是直接填入的代码一样

下面是编译后生成的BuildConfig文件,可以看到buildConfigField的东西已经在里面了

1
2
3
4
5
6
7
8
9
10
11
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.xxx.rust.newproj";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
// Fields from build type: debug
public static final String A_CONTENT = "debug content";
public static final String BASE_URL = "http://www.baidu.com";
}

resValue会被添加到资源文件中

1
mTv2.setText(R.string.str_version);

通过 build.gradle 增加获取 applicationId 的方式

模块build.gradle中添加属性applicationId,会被编译到BuildConfig中

1
2
3
4
5
project.afterEvaluate {
project.android.applicationVariants.all { variant ->
def applicationId = [variant.mergedFlavor.applicationId, variant.buildType.applicationIdSuffix].findAll().join()
}
}

在代码中可以直接使用

1
String appID = BuildConfig.APPLICATION_ID;

获取时间的方法

模块build.gradle中添加方法getTime(),并在buildTypes中添加域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 获取当前时间
static def getTime() {
String timeNow = new Date().format('YYYYMMdd-HHmmss')
return timeNow
}

android {
// ...
buildTypes {
debug {
buildConfigField "String", "BUILD_TIME", "\"" + getTime() + "\""
}
release {
buildConfigField "String", "BUILD_TIME", "\"" + getTime() + "\""
// ...
}
}
}

BuildConfig.java中得到这个域。

1
2
// Fields from build type: debug
public static final String BUILD_TIME = "20180912-100335";

修改release apk文件名的方法

gradle版本3.1.4。使用了上面的方法getTime()

1
2
3
4
5
6
7
8
9
10
11
android {
// ...
// 修改release的apk名字
applicationVariants.all { variant ->
variant.outputs.all {
if (variant.buildType.name == 'release') {
outputFileName = "xxx_release_${defaultConfig.versionName}_${getTime()}.apk"
}
}
}
}

以前的方法可能会遇到问题:Cannot set the value of read-only property 'outputFile' for ApkVariantOutputImpl_Decorated
参考:https://stackoverflow.com/questions/44239235/android-gradle-3-0-0-alpha2-plugin-cannot-set-the-value-of-read-only-property

工程范围的设置

如果一个工程中有多个模块,可以对整个工程应用设置,而不用去修改每一个模块。

NewProj\build.gradle

1
2
3
4
5
6
7
8
9
10
allprojects {
repositories {
jcenter()
}
}

ext {
compileSDKVersion = 25
local = 'Hello from the top-level build'
}

每一个build.gradle文件都能定义额外的属性,在ext代码块中。

在一个模块的libmodule\build.gradle文件中,可以引用rootProject的ext属性

1
2
3
4
5
android {
compileSdkVersion rootProject.ext.compileSDKVersion
buildToolsVersion "25.0.2"
// ....
}

工程属性 Project properties

定义properties的地方

  • ext代码块
  • gradle.properties文件
  • 命令行 -P 参数

工程build.gradle文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ext {
compileSDKVersion = 25
local = 'Hello from the top-level build'
}

/**
* Print properties info
*/
task aPrintSomeInfo {
println(local)
println('project dir: ' + projectDir)
println(projectPropertiesFileText)
}

task aPrintAllProperites() {
println('\nthis is aPrintAllProperites task\n')
Iterator pIt = properties.iterator()
while (pIt.hasNext()) {
println(pIt.next())
}
}

gradle.properties文件中增加

1
projectPropertiesFileText = Hello there from gradle.properties

在as的Gradle栏上双击执行aPrintSomeInfo,会连带下一个task也执行

1
2
3
4
5
6
7
8
9
10
11
13:08:10: Executing external task 'aPrintSomeInfo'...
Hello from the top-level build
project dir: G:\openSourceProject\NewProj
Hello there from gradle.properties

this is aPrintAllProperites task
......
BUILD SUCCESSFUL

Total time: 1.025 secs
13:08:11: External task execution finished 'aPrintSomeInfo'.

参考:Gradle for Android Kevin Pelgrims