目录 一、环境变量的概念 1、环境变量的含义 2、环境变量的分类 3、Linux环境变量 二、常用的环境变量 1、查看环境变量 2、常用的环境变量 三、设置环境量 1、系统环境变量 2、用户环境变量 3、环境变量脚本文件的执行顺序 四、重要环境变量的详解 1、PATH环境变量 2、LANG环境变量 3、LD_LIBRARY_PATH环境变量 4、CLASSPATH 五、环境变量的生效 六、应用经验 七、版权声明 一、环境变量的概念 1、环境变量的含义 程序(操作系统命令和应用程序)的执行都需要运行环境,这个环境是由多个环境变量组成的。 2、环境变量的分类 1)按生效的范围分类。 系统环境变量:公共的,对全部的用户都生效。 用户环境变量:用户私有的、自定义的个性化设置,只对该用户生效。 2)按生存周期分类。 永久环境变量:在环境变量脚本文件中配置,用户每次登录时会自动执行这些脚本,相当于永久生效。 临时环境变量:使用时在Shell中临时定义,退出Shell后失效。 3、Linux环境变量 Linux环境变量也称之为Shell环境量变,以下划线和字母打头,由下划线、字母(区分大小写)和数字组成,习惯上使用大写字母,例如PATH、HOSTNAME、LANG等。 二、常用的环境变量 1、查看环境变量 1)env命令 在Shell下,用env命令查看当前用户全部的环境变量。 上图只截取了部分环境变量,并非全部。 用env命令的时候,满屏显示了很多环境变量,不方便查看,可以用grep筛选。
1 |
env|grep 环境变量名 |
例如查看环境变量名中包含PATH的环境变量。
1 |
env|grep PATH |
2)echo命令
1 |
echo $环境变量名 |
1 |
<img style="background-color: #ffffff; font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 16px;" src="https://longsheng.org/wp-content/uploads/2020/09/6dd2aa3bec1b66f9e354678685aa51e6.png" alt="在这里插入图片描述" /> |
注意,符号$不能缺少,这是语法规定。 2、常用的环境变量 1)PATH 可执行程序的搜索目录,可执行程序包括Linux系统命令和用户的应用程序,PATH变量的具体用法本文后面的章节中有详细的介绍。 2)LANG Linux系统的语言、地区、字符集,LANG变量的具体用法本文后面的章节中有详细的介绍。 3)HOSTNAME 服务器的主机名。 4)SHELL 用户当前使用的Shell解析器。 5)HISTSIZE 保存历史命令的数目。 6)USER 当前登录用户的用户名。 7)HOME 当前登录用户的主目录。 8)PWD 当前工作目录。 9)LD_LIBRARY_PATH C/C++语言动态链接库文件搜索的目录,它不是Linux缺省的环境变量,但对C/C++程序员来说非常重要,具体用法本文后面的章节中有详细的介绍。 10)CLASSPATH JAVA语言库文件搜索的目录,它也不是Linux缺省的环境变量,但对JAVA程序员来说非常重要,具体用法本文后面的章节中有详细的介绍。 三、设置环境量
1 2 |
变量名='值' export 变量名 |
或
1 |
export 变量名='值' |
如果环境变量的值没有空格等特殊符号,可以不用单引号包含。 示例:
1 2 3 4 5 6 |
export ORACLE_HOME=/oracle/home export ORACLE_BASE=/oracle/base export ORACLE_SID=snorcl11g export NLS_LANG='Simplified Chinese_China.ZHS16GBK' export PATH=$PATH:$HOME/bin:$ORACLE_HOME/bin:. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME/lib:. |
采用export设置的环境变量,在退出Shell后就会失效,下次登录时需要重新设置。如果希望环境变量永久生效,需要在登录脚本文件中配置。 1、系统环境变量 系统环境变量对全部的用户生效,设置系统环境变量有三种方法。 1)在/etc/profile文件中设置。 用户登录时执行/etc/profile文件中设置系统的环境变量。但是,Linux不建议在/etc/profile文件中设置系统环境变量。 2)在/etc/profile.d目录中增加环境变量脚本文件,这是Linux推荐的方法。 /etc/profile在每次启动时会执行/etc/profile.d下全部的脚本文件。/etc/profile.d比/etc/profile好维护,不想要什么变量直接删除/etc/profile.d下对应的 shell 脚本即可。 […]
View Details快手极速版是我个人最喜欢的APP,原因很简单,薅羊毛的时候简单粗暴无需过多的技术也不需要有提现的各种限制,只要够3元就可以提现,而且也不吝惜金币,每天1万多金币问题不大,废话不多说直接上代码。 我的快手极速版邀请码: 2rvxaem.看文章加关注点分享都不用…加下邀请码就好。
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
auto.waitFor();//判断和等待开启无障碍 let see_count = rawInput('请输入滑动次数','1000');//手动输入滑动次数默认是1000次。 app.launchApp('快手极速版');//只有一个快手极速版所以直接Launch就可以,不用包名 sleep(10000);//等待splash时间 console.show(); //开启日志(悬浮窗权限) for (var i = 1; i < see_count; i++) { toast("快手极速版滑动" + i + "次"+"总计:"+ see_count + "次");//系统自带目前我huweinova不显示还不知道为啥 console.log("快手极速版滑动" + i + "次"+"总计:"+ see_count + "次"); kuaiShouCloseIsLike(); randomUpSildeScreen();//模仿人类随向上滑动一次,表示对这个视频有兴趣 randomDownSildeScreen();//模仿人类随连续下滑2次,表示对当前视频无兴趣 randomHeart();//模仿人类随随机点赞 randomFollow();//模仿人类随随机关注 slideScreenDown(device.width / 2, device.height-200, device.width / 2, 500, 300); } //关闭当前程序 home();//回到首页 exits();//退出js脚本 /** * 快手关闭是否喜欢对话框 */ function kuaiShouCloseIsLike(){ if(className("android.widget.TextView").text("不影响").exists()){ className("android.widget.TextView").text("不影响").findOnce().click(); } } /** * 屏幕向下滑动并延迟8至12秒 */ function slideScreenDown(startX, startY, endX, endY, pressTime) { swipe(startX, startY, endX, endY, pressTime); let delayTime = random(8000, 12000); sleep(delayTime);//模仿人类随机时间 } /** * 随机上滑(防止被判定是机器)上滑后停留时间至少是10S,造成假象表示是对内容感兴趣 * 点赞和关注先不搞。 */ function randomUpSildeScreen(){ let randomIndex = random(1, 50); if(randomIndex==1){ console.log("快手极速版随机上滑被执行了!!!"); pressTime = random(200, 500); swipe(device.width / 2, 500, device.width / 2, device.height-200, 300); delayTime = random(10000, 15000); sleep(delayTime); } } /** * 连续下滑对上一个无兴趣 * 其实得和上滑做个排他,既然无兴趣不要在上滑 */ function randomDownSildeScreen(){ let randomIndex = random(1, 50); if(randomIndex==1){ console.log("连续下滑被执行了"); swipe(device.width / 2, device.height-200, device.width / 2, 500, 300); sleep(2000); swipe(device.width / 2, device.height-200, device.width / 2, 500, 300); delayTime = random(8000, 10000); sleep(delayTime); } } /**随机点赞并休息一秒 */ function randomHeart() { index = random(1, 50); if (index == 6) { var target = id('a4l').findOnce(); if (target == null) { return; } else { target.click(); sleep(1000); console.log("随机点赞并休息一秒"); } } } function randomFollow(){ index = random(1, 100); if (index == 66) { var target = id('nebula_thanos_bottom_follow_button_layout').findOnce(); if (target == null) { return; } else { target.click(); sleep(1000); } } } /** * 随机评论(未实现) */ function randomComment() { content = "666" id('comment_button').findOnce().click(); sleep(1000);//阻塞下面的动作 id("recycler_view").className("androidx.recyclerview.widget.RecyclerView").scrollable(true).findOne().children().forEach(child => { var target = child.findOne(id("comment")); target.click(); }); sleep(1000); } |
from:https://www.cnblogs.com/zy0412326/p/12590829.html
View Details一、docker 安装及设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#安装 CentOS已经将Docker软件包放在了Extras软件源中,直接利用即可 yum install docker-io -y #查看docker的版本 version docker -v #开启Docker服务 systemctl start docker.service #开机启动Docker服务 systemctl enable docker.service #查看Docker服务启动状态 systemctl status docker.service #重启Docker服务 systemctl restart docker.service |
二、新建Net Core 程序 1、新建Net Core 项目。注意不启动Docker 支持 2、发布新建的项目(目标运行时:可移植) 3、在发布后的文件夹中新建一个Dockerfile 文件(没有后缀) 大概内容如下:
1 2 3 4 5 6 |
FROM microsoft/dotnet:2.1-aspnetcore-runtime //注意和你的版本要匹配 WORKDIR /app COPY . . //将当前目录下的所有文件(除了.dockerignore排除的路径),都拷贝进入 image 文件的/app目录。 EXPOSE 5000 //端口号(将容器 5000 端口暴露出来, 允许外部连接这个端口。) //EXPOSE 443 //Https 端口开启 ENTRYPOINT ["dotnet", "DockerDemo5.dll"] //运行的程序集 改成你自己的 |
三、上传发布后的项目到Linux服务器(CentOS) 1、进入程序的发布目录
1 2 3 4 5 6 7 8 9 |
#进入到程序的发布目标 cd /data/web/mydocker #创建 image文件 (-t参数用来指定 image 文件的名字,后面还可以用冒号指定标签 PS:注意最后的 点) docker build -t aspnetcoredocker1.1 . #生成容器,每运行一次,就会新建一个容器(这里的5000:5000 代表把容器内的5000端口映射到你主机的5000端口,容器端口在后) docker run -it -p 5000:5000 aspnetcoredocker1.1 #docker run -it -p 5000:5000 aspnetcoredocker1.1:TAG // 默认TAG是latest |
2、直接访问就可以了 3、docker 容器自动启动(在容器退出或断电开机后,docker可以通过在容器创建时的 --restart参数来指定重启策略)
1 2 3 4 5 6 7 8 9 10 11 |
# 设置启动策略 docker run --restart always -it -p 5000:5000 aspnetcoredocker1.1 #如果容器已经被创建,我们想要修改容器的重启策略 docker update --restart always 3ec28be7254a //容器ID # --restart 多个参数值选择 no 不自动重启容器. (默认值) on-failure 容器发生error而退出(容器退出状态不为0)重启容器,可以指定重启的最大次数,如:on-failure:10 unless-stopped 在容器已经stop掉或Docker stoped/restarted的时候才重启容器,手动stop的不算<br>always 在容器已经stop掉或Docker stoped/restarted的时候才重启容器 |
4、docker 相关命令 镜像文件和容器命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#查看所有镜像 docker images #删除一个imageid的镜像 docker rmi [IMAE_ID] #删除所有镜像 sudo docker rmi $(docker images -q) #查看所有容器运行状态 docker ps -a docker container ls -all #删除一个containerid的容器(实例) docker rm 6f0c67de4b72 #删除所有容器 docker rm $(sudo docker ps -a -q) |
容器日志
1 2 3 4 5 6 7 8 9 10 11 |
#查看指定时间后的日志,只显示最后100行: docker logs -f -t --since="2019-06-08" --tail=100 CONTAINER_ID #查看某时间之后的日志: docker logs -t --since="2019-06-08" CONTAINER_ID #查看某时间段日志: docker logs -t --since="2019-06-08" --until "2019-06-09" CONTAINER_ID #查看最近30分钟的日志: docker logs --since 30m CONTAINER_ID |
from:https://www.cnblogs.com/songl/p/11128012.html
View Details微服务架构无疑是当前最火热的开发架构,而Docker作为微服务架构的首选工具,是我们必须要了解掌握的。 我通过一天的时间,网上查文档,了解基础概念,安装Docker,试验Docker命令,通过Docker,成功部署运行Asp.NET core示例程序,算是基本入门。 这篇文章是自己总结的Docker入门篇,力求简洁,快速入门,以最短的时间看到学习成果,为深入学习Docker做基础。 学习前提:不要畏惧 面对未知,人们心里往往会产生恐惧,这是人与生俱来的,所以,我们在进入新的领域之前,首先要克服的是自己的畏难心理。不要因为困难,看几眼就放弃,那样你永远学不会。 面对新的未知领域,我们要把它当成一座灯塔,让它指引我们前进的方向。 第一:了解几个概念 镜像(Image):相信大家看到这个词,都明白什么意思,我们可以把它理解为操作系统的安装盘,Ghost镜像。我给它个定义,就叫:Docker基础运行环境副本。 容器(Container):运行中的Docker实例,称为容器。也就是一个镜像(Image)的运行时状态。 镜像仓库(Repository):Docker为开发者提供了面向各种环境的已经打包好的镜像,这些镜像构成了一个镜像仓库。开发者只需找到自己需要的Docker镜像,下载到本地,添加自己的应用上去,运行即可,某些工具类的镜像,可无需修改,直接运行。 Docker 主机(Host):运行着Docker容器的计算机或虚拟机,用于执行Docker的守护进程。 Docker客户端(Client):是与Docker主机守护进程进行通信的工具,如:Docker控制台。 第二:安装Docker 不同操作系统按照方式不同,以Win7系统为例,需要利用 docker toolbox 来安装,可以使用阿里云的镜像来下载。 下载地址:http://mirrors.aliyun.com/docker-toolbox/windows/docker-toolbox/ 安装完成之后,在桌面找到三个启动图标:Oracle VM VirtualBox,Kitematic(Alpha),Docker Quickstart …。 安装完成之后,建议重启一下计算机。 Oracle VM VirtualBox :是一个虚拟机程序。Docker是运行在Linux环境下的,要想在Windows下运行,必须借助虚拟机。感兴趣的话可以留着以后研究。 kitematic(alpha):是docker推出的GUI工具,可以更简便地操作Docker,非常适合windows用户使用习惯,推荐大家试试。这个alpha表示预览版吧,可能功能还不完善。 Docker Quickstart Terminal:是Docker控制台启动程序,双击图标启动Docker。 如果一切正常的话,可以看到以下界面。 如果启动过程中出现下面错误,Looks like something went wrong in step 'Looking for vboxmanage.exe’… 意思是没有找到虚拟机启动程序,需要设置VirtualBox的环境变量,系统环境变量中增加VBOX_MSI_INSTALL_PATH和VBOX_INSTALL_PATH 值都为C:\Program Files\Oracle\VirtualBox\ ,即VirtualBox的安装路径,注意后面的\ 不能少。环境变量设置完成之后,可尝试重新启动。 第三:熟悉几个命令 我建议实际工作中使用图形界面 kitematic,真的既简单又实用,但Docker命令还是要学习的,最重要的是,使用命令行操作显得更酷更专业。 docker 命令都是以docker开头,下面介绍几个简单,常用的命令。仅作基础介绍,具体参数用法可后期详细学习 。 docker pull:从镜像仓库中拉取镜像 。 docker run:通过镜像创建一个新的容器,并运行。需要注意的是,如果本地没有指定的镜像,会直接去镜像库下载,一定要保证拼写正确。 docker stop:停止一个容器 。 docker start:启动一个容器 。 docker restart:重启一个容器 。 docker ps:列出当前运行的容器机器状态 。 docker images 或 docker image ls:列出本地镜像。 docker build:使用Dockerfile创建自己的镜像。 第四:操作演示,从hello world开始 你可以登录Docker官方镜像仓库,选择自己感兴趣的镜像进行试验,这里我们选择最简单的 hello-world。 Docker官方镜像仓库地址:https://hub.docker.com […]
View Details最近大家都知道,手机版的按键精灵APP对其导出编译脚本做了限制。本来免费就能打包,现在就只能按月收费。有没有像按键精灵一样的手机端脚本编写软件呢?小编对此做了个小调查。以下是一些软件推荐: 【1】autojs 它的语法和javascipt非常相似,可以说是其在手机端的衍生编写程序app。如果你已经大概掌握了按键精灵的编写技能,就应该有学习这门语言的能力。内置帮助文件说明很详细的脚本案例,让初学者轻松掌握它的用法。 【2】Airtest 它是由网易开发的 UI 界面自动化测试工具。你可以借助 AirtestIDE,通过在 IDE 中进行所见即所得的编码方式,来简化 App 图形界面的测试流程。除此之外,你还可以借助该工具来编写 App 爬虫,效率也是蛮高的。 【3】TC简单开发 你可能听说过它的电脑端,也是十分强大的倾向于网页自动化编程的软件。其他它也有手机端。它是脚本工具中唯一一个完美支持真多线程的工具,支持调用近10000个WIN32函数,支持调用COM组件,集合了文字识别,图色识别,网络,数据库,正则等等各种强大的功能库。 【4】Tasker Tasker是一个让系统根据用户定制的”配置文件”(Profiles),在特定的”背景”下(Contexts),执行指定”任务”(Tasks)的软件,除此之外,它还提供”可供点击”的(Clickable)或”定时运行”的(Timer)桌面”插件”(Widget)。对于自学能力稍差的同学,可以考虑下这款软件试试。 【5】B4A-Basic4android 官方下载网址,安装下载,需要安装JDK,ANDROID SDK,模拟器或手机等Install Java JDK v7 or v8。此应用为VB语言,支持在电脑端编写程序,这些工具都是用BASIC语言写的安卓应用,自已写安卓工具。 以下是几款在手机上编写代码的app: 1)java和Android:AIDE集成开发环境。 2)C语言:c语言编译器、C4droid。 3)python:QPython3、Termux。 4)CSS/HTML/JavaScript:HTMLplay from:http://www.360doc.com/content/19/0809/21/58781721_853937895.shtml
View Details什么是Auto.JS? Auto.JS是Android平台上的JavaScript自动化工具。 它的本质是可执行自己编写的简易Javascript脚本的,尤其可以在开启“无障碍模式”的情况下对其他App进行一些操作的一个Android App,便于进行自动化操作。学习成本非常低。 Auto.JS已被黑产广泛使用,以至于作者关闭了官方下载通道。 官网:https://github.com/hyb1996/Auto.js 我们能用它自动化地做什么? 1) 对于黑产 微博:自动注册、远程获取内容、动发微博,点赞关注收藏、评价回复转发 注册类:163邮箱注册,抖音注册 签到类:百度地图签到、大众点评签到、叮咚买菜签到、拼多多签到、云闪付签到积分、支付宝签到积分、京东签到京豆等 2) 对于普通人 启动游戏时自动屏蔽通知、一键与特定联系人微信视频、淘宝双十一一键领猫币等 跟按键精灵的区别?跟Robotium等的区别? 1) VS 按键精灵 无需Root;可直接指定控件并点击,无需识图找坐标 2) VS Robotium 手机无需连电脑即可运行;代码极其简单;无需Eclipse或bat脚本;可在手机上选择不同脚本执行 在自动化操作演示/黑产模拟时,比较有用的功能? 1) APP相关 启动App(通过应用名/包名)、打开App设置页、卸载App等 2) 时序相关 等待指定的Activity(页面)出现、等待指定的App启动、获取当前Activity 3) 控件相关※ 输入:点击/长按含特定文字的控件、滑动特定控件、在第N个输入框输入/追加文字、复制粘贴等; ※控件选择器:通过控件的各种xml属性(如ID、text、desc、包名、位置)选择一个或多个控件并进行操作; 等待:等待指定控件出现 4) 创建界面相关 可编写界面、弹出Toast、弹出对话框、创建悬浮窗 5) 坐标/按键类 点击指定坐标&滑动、模拟点击各种按键(Home、后退键、菜单键、电源键等)等 6) 其他 随机数、网络请求、定时器、多线程、文件操作、找图等常见功能;监听按键&屏幕点击、获取各种设备相关信息(Build.**、音量、震动等等);Linux Shell命令 版本限制 在非Root情况下,Auto.JS只能运行在>=Android7.0以上的系统。 如何编写脚本、运行脚本? 1)安装Auto.JS APK:在手机上安装Auto.js_V4.1.1_Alpha2 注:App会自动引导开启“无障碍服务”。以小米为例,按程序指示,在程序跳转到的页面点击“更多已下载的服务”->“Auto.js”->开启服务 2)在PC上编写 首先安装VSCode,在VS Code中菜单"查看"->"扩展"->输入"Auto.js"或"hyb1996"搜索,即可看到"Auto.js-VSCodeExt"插件,安装即可。请把文件保存为.js,方便代码补全。 3)在PC侧调试 1.jpg 注1:“连接电脑”开关若为蓝色才表示连接成功,否则请确认连接到了同一WIFI,若WIFI环境复杂(比如多个同名WIFI但实为不同路由器),请用笔记本/热点开WIFI 4)脱离电脑运行 先把编写并测试好js文件复制到手机上,在手机上启动Auto.js,点⊕按钮-导入,导入到App里,然后在对应的脚本右边点“▶”即可运行。 5)中止运行 点击Auto.JS 右下角的“×” 或在VSCode里ctrl+shift+p然后选”Stop” 官方文档 https://hyb1996.github.io/AutoJs-Docs/ 注:使用选择器时无需加UiSelector. 脚本范例 https://github.com/bjc5233/autojs https://github.com/bayson/autojs https://github.com/hyb1996/Auto.js/tree/master/app/src/main/assets/sample 作者:RedB 链接:https://www.jianshu.com/p/4602db0618df 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
View Details一、【必须】安装adb工具 adb全称Android Debug Bridge,是Android系统的调试工具。 下并安装ADB Installer v1.4.3,下载链接:http://pan.webscraping.cn:8000/index.php/s/7kDAJUOmKEa1h4N 安装完成后,启动一个新的cmd窗口,输入adb devices,若无错误提示则表明安装成功。 Ubuntu下安装adb可以参考这篇文章:http://bernaerts.dyndns.org/linux/74-ubuntu/354-ubuntu-xenial-android-adb-fastboot-qtadb) 二、【可选】安装UI Automator Viewer辅助工具 为了使用UI Automator Viewer这个辅助分析工具,我们需要先安装Android SDK,步骤如下: 1. 下载并安装Java 8 2. 下载并安装Google Android SDK 3. 启动Android SDK Manager,选择并安装Android SDK Platform-tools. 4. 双击uiautomatorviewer.bat,启动UI Automator Viewer,点击第二个图标获取设备截图及相关UI信息,如下图所示。 三、【主角】AndroidViewClient AndroidViewClient是用纯Python编写的Android应用程序自动测试框架,它不依赖其它程序(例如 monkeyrunner, jython)。AndroidViewClient在底层是通过调用adb命令实现对Android设备的控制,因此在本文的一开始就先介绍了adb的安装。 开始下文之前,假设你已经安装配置好Python运行环境,否则请先安装Python 2.7(注意:AndroidViewClient不兼容Python3)。 1. 安装AndroidViewClient 项目主页:https://github.com/dtmilano/AndroidViewClient 推荐用easy_install安装: easy_install --upgrade androidviewclient 安装详细说明见这里:https://github.com/dtmilano/AndroidViewClient/wiki#installation PS:依赖库比较多,安装需要有点耐心。 2. 测试安装是否成功 下载https://github.com/dtmilano/AndroidViewClient/archive/master.zip包,解压并切换到examples目录下,执行python check-import.py,如果没有问题,会输出OK。 3. 写一个例子 实现这样一个功能: 点击屏幕微信图标启动微信,点击第一个联系人/群,发送一个报时消息。 代码如下: view plaincopy to clipboardprint? # coding: utf-8 # 点击屏幕微信图标启动微信,点击第一个联系人/群,发送一个报时消息 import sys import os import re import time from com.dtmilano.android.viewclient import ViewClient def test(): # 连接手机 device, serialno = ViewClient.connectToDeviceOrExit() vc = ViewClient(device, serialno) # 按HOME键 device.press('KEYCODE_HOME') time.sleep(3) # 找到微信图标 vc.dump() weixin_button = vc.findViewWithTextOrRaise(u'微信') # 点击微信图标 weixin_button.touch() time.sleep(10) # 找到第一个联系人/群 # 可以使用UI Automator Viewer查看到对应第一个联系人/群的resource-id为"com.tencent.mm:id/auj" vc.dump() group_button = vc.findViewByIdOrRaise("com.tencent.mm:id/auj") # 点击进群 group_button.touch() time.sleep(5) # 找到输入框并输入当前时间 vc.dump() […]
View Details用法一 this代表当前类的实例对象
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 |
namespace Demo { public class Test { private string scope = "全局变量"; public string getResult() { string scope = "局部变量"; // this代表Test的实例对象 // 所以this.scope对应的是全局变量 // scope对应的是getResult方法内的局部变量 return this.scope + "-" + scope; } } class Program { static void Main(string[] args) { try { Test test = new Test(); Console.WriteLine(test.getResult()); } catch (Exception ex) { Console.WriteLine(ex); } finally { Console.ReadLine(); } } } } |
用法二 用this串联构造函数
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 |
namespace Demo { public class Test { public Test() { Console.WriteLine("无参构造函数"); } // this()对应无参构造方法Test() // 先执行Test(),后执行Test(string text) public Test(string text) : this() { Console.WriteLine(text); Console.WriteLine("有参构造函数"); } } class Program { static void Main(string[] args) { try { Test test = new Test("张三"); } catch (Exception ex) { Console.WriteLine(ex); } finally { Console.ReadLine(); } } } } |
用法三 为原始类型扩展方法
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 75 |
namespace Demo { public static class Extends { // string类型扩展ToJson方法 public static object ToJson(this string Json) { return Json == null ? null : JsonConvert.DeserializeObject(Json); } // object类型扩展ToJson方法 public static string ToJson(this object obj) { var timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" }; return JsonConvert.SerializeObject(obj, timeConverter); } public static string ToJson(this object obj, string datetimeformats) { var timeConverter = new IsoDateTimeConverter { DateTimeFormat = datetimeformats }; return JsonConvert.SerializeObject(obj, timeConverter); } public static T ToObject<T>(this string Json) { return Json == null ? default(T) : JsonConvert.DeserializeObject<T>(Json); } public static List<T> ToList<T>(this string Json) { return Json == null ? null : JsonConvert.DeserializeObject<List<T>>(Json); } public static DataTable ToTable(this string Json) { return Json == null ? null : JsonConvert.DeserializeObject<DataTable>(Json); } public static JObject ToJObject(this string Json) { return Json == null ? JObject.Parse("{}") : JObject.Parse(Json.Replace(" ", "")); } } class Program { static void Main(string[] args) { try { List<User> users = new List<User>{ new User{ID="1",Code="zs",Name="张三"}, new User{ID="2",Code="ls",Name="李四"} }; // list转化json字符串 string json = users.ToJson(); // string转化List users = json.ToList<User>(); // string转化DataTable DataTable dt = json.ToTable(); } catch (Exception ex) { Console.WriteLine(ex); } finally { Console.ReadLine(); } } } public class User { public string ID { get; set; } public string Code { get; set; } public string Name { get; set; } } } |
用法四 索引器(基于索引器封装EPList,用于优化大数据下频发的Linq查询引发的程序性能问题,通过索引从list集合中查询数据)
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; namespace MyDemo.Web { /// <summary> /// EPList 支持为List创建索引 /// </summary> /// <typeparam name="T">类型</typeparam> public class EPList<T> { #region 成员变量 /// <summary> /// 索引 /// </summary> private List<string[]> m_Index = new List<string[]>(); /// <summary> /// 缓存数据 /// </summary> private Dictionary<string, List<T>> m_CachedData = new Dictionary<string, List<T>>(); /// <summary> /// List数据源 /// </summary> private List<T> m_ListData = new List<T>(); /// <summary> /// 通过索引值取数据 /// </summary> /// <param name="indexFields">索引字段</param> /// <param name="fieldValues">字段值</param> /// <returns></returns> public List<T> this[string[] indexFields] { get { string key = string.Join(",", indexFields); if (m_CachedData.ContainsKey(key)) return m_CachedData[key]; return new List<T>(); } } #endregion #region 公共方法 /// <summary> /// 创建索引 /// </summary> /// <param name="indexFields">索引字段</param> public void CreateIndex(string[] indexFields) { if (m_Index.Contains(indexFields)) return; m_Index.Add(indexFields); } /// <summary> /// 添加 /// </summary> /// <param name="record">记录</param> public void Add(T record) { m_ListData.Add(record); m_Index.ForEach(indexFields => { string key = getKey(record, indexFields); if (m_CachedData.ContainsKey(key)) { m_CachedData[key].Add(record); } else { List<T> list = new List<T> { record }; m_CachedData.Add(key, list); } }); } #endregion #region 私有方法 /// <summary> /// 获取值 /// </summary> /// <param name="record">记录</param> /// <param name="fieldName">字段名</param> /// <returns></returns> private object getValue(T record, string fieldName) { Type type = typeof(T); PropertyInfo propertyInfo = type.GetProperty(fieldName); return propertyInfo.GetValue(record, null); } /// <summary> /// 获取Key /// </summary> /// <param name="record">记录</param> /// <param name="indexFields">索引字段</param> private string getKey(T record, string[] indexFields) { List<string> values = new List<string>(); foreach (var field in indexFields) { string value = Convert.ToString(getValue(record, field)); values.Add(field + ":" + value); } return string.Join(",", values); } /// <summary> /// 获取Key /// </summary> /// <param name="indexFields">索引字段</param> /// <param name="fieldValues">字段值</param> /// <returns></returns> private string getKey(string[] indexFields, object[] fieldValues) { if (indexFields.Length != fieldValues.Length) return string.Empty; for (int i = 0; i < indexFields.Length; i++) { fieldValues[i] = indexFields[i] + ":" + fieldValues[i]; } string key = string.Join(",", fieldValues); return key; } #endregion } } |
给EPList创建索引,并添加数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
private EPList<SysDepartInfo> GetEPListData() { EPList<SysDepartInfo> eplist = new EPList<SysDepartInfo>(); eplist.CreateIndex(new string[] { "ParentId" }); string sql = "select Id,ParentId,Code,Name from SysDepart"; SqlHelper.ExecuteReader(sql, null, (reader) => { SysDepartInfo record = new SysDepartInfo(); record.Id = Convert.ToString(reader["Id"]); record.ParentId = Convert.ToString(reader["ParentId"]); record.Code = Convert.ToString(reader["Code"]); record.Name = Convert.ToString(reader["Name"]); eplist.Add(record); }); return eplist; } |
通过索引高效查询数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/// <summary> /// 获取子节点 /// </summary> /// <param name="data"></param> /// <param name="parentId"></param> private IEnumerable<TreeInfo> CreateChildren(EPList<SysDepartInfo> data, TreeInfo node) { string id = node == null ? "0" : node.id; List<TreeInfo> childNodes = new List<TreeInfo>(); // ParentId字段上创建了索引,所以这里就可以通过索引值直接取出下一层子节点数据,避免Linq查询引发的效率问题 var indexValues = new string[] { "ParentId:" + id }; var childData = data[indexValues]; childData.ForEach(record => { var childNode = new TreeInfo { id = record.Id, text = record.Code + " " + record.Name }; childNodes.Add(childNode); childNode.children = CreateChildren(data, childNode); }); return childNodes.OrderBy(record => record.text); } |
from:https://www.cnblogs.com/yellowcool/p/7908607.html
View DetailsSQL(Structure Query Language)语言是数据库的核心语言。 SQL的发展是从1974年开始的,其发展过程如下: 1974年—--由Boyce和Chamberlin提出,当时称SEQUEL。 1976年—--IBM公司的Sanjase研究所在研制RDBMS SYSTEM R 时改为SQL。 1979年—--ORACLE公司发表第一个基于SQL的商业化RDBMS产品。 1982年—--IBM公司出版第一个RDBMS语言SQL/DS。 1985年—--IBM公司出版第一个RDBMS语言DB2。 1986年—--美国国家标准化组织ANSI宣布SQL作为数据库工业标准。 SQL是一个标准的数据库语言,是面向集合的描述性非过程化语言。 它功能强,效率高,简单易学易维护(迄今为止,我还没见过比它还好 学的语言)。然而SQL语言由于以上优点,同时也出现了这样一个问题: 它是非过程性语言,即大多数语句都是独立执行的,与上下文无关,而 绝大部分应用都是一个完整的过程,显然用SQL完全实现这些功能是很困 难的。所以大多数数据库公司为了解决此问题,作了如下两方面的工作: (1)扩充SQL,在SQL中引入过程性结构;(2)把SQL嵌入到高级语言中, 以便一起完成一个完整的应用。 二. SQL语言的分类 SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL。 1. 数据查询语言DQL 数据查询语言DQL基本结构是由SELECT子句,FROM子句,WHERE 子句组成的查询块: SELECT <字段名表> FROM <表或视图名> WHERE <查询条件> 2 .数据操纵语言DML 数据操纵语言DML主要有三种形式: 1) 插入:INSERT 2) 更新:UPDATE 3) 删除:DELETE 3. 数据定义语言DDL 数据定义语言DDL用来创建数据库中的各种对象—--表、视图、 索引、同义词、聚簇等如: CREATE TABLE/VIEW/INDEX/SYN/CLUSTER | | | | | 表 视图 索引 同义词 簇 DDL操作是隐性提交的!不能rollback 4. 数据控制语言DCL 数据控制语言DCL用来授予或回收访问数据库的某种特权,并控制 数据库操纵事务发生的时间及效果,对数据库实行监视等。如: 1) GRANT:授权。 2) ROLLBACK [WORK] TO [SAVEPOINT]:回退到某一点。 回滚—ROLLBACK 回滚命令使数据库状态回到上次最后提交的状态。其格式为: SQL>ROLLBACK; 3) COMMIT [WORK]:提交。 在数据库的插入、删除和修改操作时,只有当事务在提交到数据 库时才算完成。在事务提交前,只有操作数据库的这个人才能有权看 […]
View Details概述 为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁。 为什么要使用分布式锁 成员变量 A 存在 JVM1、JVM2、JVM3 三个 JVM 内存中 成员变量 A 同时都会在 JVM 分配一块内存,三个请求发过来同时对这个变量操作,显然结果是不对的 不是同时发过来,三个请求分别操作三个不同 JVM 内存区域的数据,变量 A 之间不存在共享,也不具有可见性,处理的结果也是不对的 注:该成员变量 A 是一个有状态的对象 如果我们业务中确实存在这个场景的话,我们就需要一种方法解决这个问题,这就是分布式锁要解决的问题 分布式锁应该具备哪些条件 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行 高可用的获取锁与释放锁 高性能的获取锁与释放锁 具备可重入特性(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误) 具备锁失效机制,防止死锁 具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败 分布式锁的实现有哪些 Memcached:利用 Memcached 的 add 命令。此命令是原子性操作,只有在 key 不存在的情况下,才能 add 成功,也就意味着线程得到了锁。 Redis:和 Memcached 的方式类似,利用 Redis 的 setnx 命令。此命令同样是原子性操作,只有在 key 不存在的情况下,才能 set 成功。 Zookeeper:利用 Zookeeper 的顺序临时节点,来实现分布式锁和等待队列。Zookeeper 设计的初衷,就是为了实现分布式锁服务的。 Chubby:Google 公司实现的粗粒度分布式锁服务,底层利用了 Paxos 一致性算法。 通过 Redis 分布式锁的实现理解基本概念 分布式锁实现的三个核心要素: 加锁 最简单的方法是使用 setnx 命令。key 是锁的唯一标识,按业务来决定命名。比如想要给一种商品的秒杀活动加锁,可以给 key 命名为 “lock_sale_商品ID” 。而 value 设置成什么呢?我们可以姑且设置成 1。加锁的伪代码如下:
1 2 |
setnx(lock_sale_商品ID,1) |
当一个线程执行 setnx 返回 1,说明 key 原本不存在,该线程成功得到了锁;当一个线程执行 setnx 返回 0,说明 key […]
View Details