烦恼一般都是想太多了。

0%

安卓的世界里,除了 Xposed ,还有一个后起之秀 Magisk,他与 Xposed 的不他是,Xposed 是通过利用替换 app_process 这个程序,预先 C 层加载一些服务,然后对运行时做了一些修改来达成目的;而 Magisk 则是通过将一个文件系统, overlay ,类似分层的形式,来 merge system 目录达成目的。不过,实现的过程中,其实手续会更多。

Read more »

Android系统的启动过程 过程中,我们知道,Android 启动在启动的时候,首先会调用 app_process 这个程序,来启动一个 Zygote 进程,然后其他所有的进程都会有这个进程进行 fork 而来。因此,在这个进程里面所加载的任何内容,在新的 APP 进程中都是可用的,所以呢,这 Xposed 和 Magsik 都利用了子进程会继承父进程环境的这么一个事实来进行实现。

Read more »

Mysql 可以直接支持 load data 命令,而 Oracle 似乎没有这样的支持。而且还不支持类似 MySQL 的 insert into ... values () 这样的语句。实在用起来累。

<—more—>

拼 SQL 的形式导入数据

SQLLoader

用法: SQLLDR keyword=value [,keyword=value,...]

有效的关键字:

userid -- ORACLE username/password
control -- Control file name
log -- Log file name
bad -- Bad file name
data -- Data file name
discard -- Discard file name
discardmax -- Number of discards to allow (全部默认)
skip -- Number of logical records to skip (默认0)
load -- Number of logical records to load (全部默认)
errors -- Number of errors to allow (默认50)
rows -- Number of rows in conventional path bind array or between direct path data saves
(默认: 常规路径 64, 所有直接路径)
bindsize -- Size of conventional path bind array in bytes(默认256000)
silent -- Suppress messages during run (header,feedback,errors,discards,partitions)
direct -- use direct path (默认FALSE)
parfile -- parameter file: name of file that contains parameter specifications
parallel -- do parallel load (默认FALSE)
file -- File to allocate extents from
skip_unusable_indexes -- disallow/allow unusable indexes or index partitions(默认FALSE)
skip_index_maintenance -- do not maintain indexes, mark affected indexes as unusable(默认FALSE)
commit_discontinued -- commit loaded rows when load is discontinued(默认FALSE)
readsize -- Size of Read buffer (默认1048576)
external_table -- use external table for load; NOT_USED, GENERATE_ONLY, EXECUTE(默认NOT_USED)
columnarrayrows -- Number of rows for direct path column array(默认5000)
streamsize -- Size of direct path stream buffer in bytes(默认256000)
multithreading -- use multithreading in direct path
resumable -- enable or disable resumable for current session(默认FALSE)
resumable_name -- text string to help identify resumable statement
resumable_timeout -- wait time (in seconds) for RESUMABLE(默认7200)
date_cache -- size (in entries) of date conversion cache(默认1000)

一般我们分别使用控制文件和数据文件比较好,当然也可以在控制文件中指定数据文件。

这样个程序的核心就是控制文件,他控制了我们插入什么数据的行为和方式,已经各种更细致的逻辑。

控制文件示例

OPTIONS (skip=1,rows=128) 
LOAD DATA
INFILE "loginnames"
truncate
INTO TABLE tmp1_rengy
Fields terminated by ","
Optionally enclosed by '"'
trailing nullcols
(
id,
loginname
)
`

sqluldr2

这里还有一个好用的数据批量导出工具。官方网站打不开了,在 github.com上找到个地址

自己编译出来试试。使用的方法如下:


SQL*UnLoader: Fast Oracle Text Unloader (GZIP, Parallel), Release 4.0.1
(@) Copyright Lou Fangxin (AnySQL.net) 2004 - 2010, all rights reserved.

License: Free for non-commercial useage, else 100 USD per server.

Usage: SQLULDR2 keyword=value [,keyword=value,...]

Valid Keywords:
user = username/password@tnsname
sql = SQL file name
query = select statement
field = separator string between fields
record = separator string between records
rows = print progress for every given rows (default, 1000000)
file = output file name(default: uldrdata.txt)
log = log file name, prefix with + to append mode
fast = auto tuning the session level parameters(YES)
text = output type (MYSQL, CSV, MYSQLINS, ORACLEINS, FORM, SEARCH).
charset = character set name of the target database.
ncharset= national character set name of the target database.
parfile = read command option from parameter file

for field and record, you can use '0x' to specify hex character code,
\r=0x0d \n=0x0a |=0x7c ,=0x2c, \t=0x09, :=0x3a, #=0x23, "=0x22 '=0x27

通过 sql 指定 sql文件,或者通过 query 指定 查询语句,来进行导出。

库路径

dialog(package.path)
dialog(package.cpath)
/data/data/?.lua;
/sdcard/TouchSprite/lua/?.lua;
/sdcard/TouchSprite/lua/?.luac;
/data/data/com.touchsprite.android/TouchSprite/?.lua;
/data/data/com.touchsprite.android/files/tslibs/?.lua;
/data/data/com.touchsprite.android/files/tslibs/?/?.lua;
/data/data/?.so;
/data/data/com.touchsprite.android/files/tslibs/?.so;
/data/data/com.touchsprite.android/files/plugin/?.so;
/data/data/?.so;
/sdcard/TouchSprite/lua/?.so;

关于http.post 文件

触动有三个地方提供了 http 相关的操作。

TSLib

str = httpPost(url,data,options)
```
遗憾的是,这里只能传输 data 为字符串类型的数据。

```lua
local url = 'http://www.baidu.com'
data = "hello world",
options = {
tstab = 1,
timeOut = 10,
urlEnCode = true
}
local str = httpPost(url, data, options)

这个生成的内容如下:

Content-Length: 11
Content-Type: application/x-www-form-urlencoded
TE: trailers
Host: 42.192.43.15:8989
Connection: close, TE
User-Agent: LuaSocket 3.0-rc1

hello world

很遗憾,我们不能指定头部等信息,Content-Type 也是固定的。

ts.so

这个就可以指定头部,和直接用 lua 表来进行作为参数了。
但是 body 必须是 table 类型,会转换成 query 形式,那我要传 json 的话怎么办?没办法。

函数签名:

-- ios
status_resp, header_resp,body_resp = ts.httpPost(url,header_send,body_send,encode)

-- android
status_resp, header_resp,body_resp = ts.httpPost(url,tab)

安卓是把几个参数放在了一个 table 处理,这里 header_send, body_send 都是表。

iOS

local ts = require("ts")
header_send = {typeget = "iOS"}
body_send = {
["username"] = "aa",
["password"] = "1234"
}
ts.setHttpsTimeOut(60)
code, status_resp, body_resp = ts.httpsPost("https://www.baidu.com", header_send, body_send)

Android

--Android 脚本实例
local ts = require("ts")
data = {
tstab = "tstab",
header_send = {typeget = "android"},
body_send = {id = "687"},
format = "gbk"
}
code, header_resp, body_resp = ts.httpsPost("http://whois.pconline.com.cn/ip.jsp", data)

但是这个函数生成的内容,也是坑的,字段信息居然莫名其妙:

POST / HTTP/1.1
Host: 42.192.43.15:8989
Accept: */*
typeget: android
t-Type:application/x-www-form-urlencoded;charset=UTF-8;Content-Length:
Content-Length: 6
Content-Type: application/x-www-form-urlencoded

id=687

我们可以指定头信息,但指定 Content-Type 没有卵用的;但是 body_send 却无法变更,只能是 table 格式,如果不是 table 格式,那就会给你变成 GET 请求,坑吧?

tsnet.so

这个高级库,需要购买VIP才能用,或者是IOS 专业版,放弃他。

require("tsnet")
status, header, content =
http.post(
"https://whois.pconline.com.cn/ip.jsp",
{
headers = {aaa = 123, cd = 12},
params = {aaa = 111, bbb = 222},
opts = {charset = "gbk"}
}
)

这个也是把 params 转成 query 形式,我要传 json 怎么办呢?

这个就只能是不带 params 参数,postdata 来手撸格式了。

但这几个都没有解决一个问题:对于文件是如何处理的?是将文件直接传递文件描述符,还是需要手动进行转换成分段的形式进行传输呢?

问题的解决

tsnet.so

使用 ltn12, multipart-post 来解决。

multipart-post 用来将文件封装成 multipart 格式,然后调用 tsnet 的API进行上传:

require("tsnet")
local enc = (require "multipart-post").encode

function uploadfile(url, filepath)
local body, boundary = enc {file = {data = io.open(filepath)}}
local headers = {
["content-length"] = #body,
["content-type"] = string.format("multipart/form-data; boundary=%s", boundary)
}
print(body)
return http.post(
url,
{
headers = headers,
params = body,
opts = {charset = "gbk"}
}
)
end

status, header, content = uploadfile("http://oss.888ce.cn:8081/mz/oss/pic/upload/scriptImg", "1.png")
dialog(status)
dialog(content)

ts.so

这个其实也无法解决问题,用 body_send 必须是 table 格式。

require("ts")
local enc = (require "multipart-post").encode

function uploadfile(url, filepath)
local body, boundary = enc {file = {data = io.open(filepath)}}
local headers = {
typeget='android',
["content-length"] = #body,
["content-type"] = string.format("multipart/form-data; boundary=%s", boundary)
}

return ts.httpPost(
url,
{
tstab='tstab',
header_send = headers,
body_send = body,
format = 'gbk'
}
)
end
status, header, content = uploadfile("http://oss.888ce.cn:8081/mz/oss/pic/upload/scriptImg", "1.png")

Socket 模块

没办法了,手撸吧。