2012年7月21日
平时我们使用的IP地址是192.168.1.11这种类型的字符串;而在Linux内核中是用二进制方式表达的IP地址。在程序设计中经常要用到字符串表达方式的IP地址和二进制的IP地址之间的转换。 面对网络编程中众多的地址函数,你hold住了么,tiger哥没hold住,所以就写了此篇文章,希望大家能hold住网络编程。 前言:结构体struct in_addr结构struct in_addr 在文件中定义,结构in_addr 有一个unsigned long int 类型的成员变量s_addr.通常所说的IP地址的二进制形式就保存在成员变量s_addr中。 结构struct in_addr的原型如下:structin_addr{ unsigned long int s_addr;/*IP地址*/ }一。字符串IP地址转换为二进制形式的IP地址函数1.inet系列函数的原型:#include #include #include int inet_aton(const char *cp,struct in_addr *inp);int addr_t inet_addr(const char *cp);int addr_t inet_network(const char *cp);char * inet_ntoa(struct in_addr in);struct in_addr inet_makeaddr(int net,int host);in_addr_t inet_lnaof(struct in_addr in);in_addr_t inet_netof(struct in_addr in);2.inet_aton()函数int inet_aton(const char*cp,struct in_addr *inp) 1>函数作用:inet_ation()函数将在cp中存储的点分十进制字符串类型的IP地址,转换为二进制的IP地址,转换后的值保存在指针inp指向的结构struct in_addr中。 2>形参? const char *cp:指向字符类型的IP地址。例如“192.168.1.11”? struct in_addr *inp:指向二进制的网络字节顺序的IP地址structin_addr{ unsignedlong s_addr } 3>函数执行成功则返回非0值,参数无效则返回0. 4>实例:#include #include #include #include #include #include int main() { char buffer[32];structin_addr in;in.s_addr =0;/*输入一个字符串形式的IP地址*/ printf(“pleaseinput the ip addrss\n”);scanf(“%s”,buffer);buffer[31]=‘\0’;printf(“original IP地址:%s\n”,buffer);if( 0 == inet_aton(buffer,&in)){ perror(“inet_aton”);exit(1);} else { printf(“after transfer:0x%0x\n”,in.s_addr);} 5> inet_aton函数最后计算出来的是网络字节序的二进制IP 3.inet_addr()函数in_addr_t inet_addr(const char *cp) 1>函数作用:它将参数cp所指向的字符串形式的IP地址(“192.168.1.11”)转换为二进制的网络字节序的IP地址形式该函数的缺点是:如果IP地址是255.255.255.255.那么调用inet_addr()函数后将返回-1(因为-1的补码形式是0xFFFFFFFF)。所以不建议使用inet_addr()函数,而是使用inet_aton()函数。 2>函数形参:const char*cp:cp指向字符串形式的IP地址。 3>函数返回值:函数成功后返回二进制的网络字节序的IP地址(struct in_add),否则返回-1. 4>inet_addr计算出来的是网络字节序的二进制IP 5>函数实例:#include #include #include #include #include #include int main() { char buffer[32];structin_addr in;in.s_addr =0;/*输入一个字符串形式的IP地址*/ printf(“pleaseinput the ip addrss\n”);scanf(“%s”,buffer);buffer[31]=‘\0’;printf(“original IPaddress:%s\n”,buffer);if((in.s_addr = inet_addr(buffer))==INADDR_NONE){ perror(“inet_addr”);exit(1);} else { printf(“after transfer:0x%0x\n”,in.s_addr);} 4.inet_network in_addr_t inet_network(constchar *cp) 1>函数作用:将参数cp指向的字符串形式的网络地址转换为主机字节顺序形式的二进制IP地址。 2>函数形参? const char *cp: cp指向字符串形式的IP地址。 3>函数返回值:执行成功后返回转换后的结果,参数无效后返回-1. 4>inet_network返回的是主机字节序5>函数实例:#include #include #include #include #include #include int main() { char buffer[32];structin_addr in;in.s_addr =0;/*输入一个字符串形式的IP地址*/ printf(“pleaseinput the ip addrss\n”);scanf(“%s”,buffer);buffer[31]=‘\0’;printf(“original IPaddress:%s\n”,buffer);if((in.s_addr = inet_addr(buffer))==INADDR_NONE){ perror(“inet_addr”);exit(1);} else { printf(“after transfer:0x%0x\n”,in.s_addr);}总结:1.inet_addr和inet_network函数都是用于将字符串形式转换为整数形式用的;2.inet_addr返回的整数形式是网络字节序,而inet_network返回的整数形式是主机字节序。 3.inet_addr 和inet_network有一个小缺陷,那就是当IP是255.255.255.255时,这两个函数会认为这是个无效的IP地址,这是历史遗留问题,其实在目前大部分的路由器上,这个 255.255.255.255的IP都是有效的。 4.inet_aton认为255.255.255.255是有效的,所以建议使用inet_aton.并且inet_aton函数返回的是网络字节序的IP地址。 二。进制IP地址转换为字符串形式的IP地址1.char * inet_ntoa(struct in_addr in);1>函数作用:将数值为in的网络字节序形式的二进制IP地址转换为字符串形式的IP地址。 2>形参:struct in_addr in:指向二进制的IP地址3>函数返回值:执行成功返回结果字符串的指针,参数无效返回NULL. 4>函数实例:#include #include #include #include #include #include int main() { char buffer[32];char *str;structin_addr in;in.s_addr =0;/*输入一个字符串形式的IP地址*/ printf(“pleaseinput the ip addrss\n”);scanf(“%s”,buffer);buffer[31]=‘\0’;printf(“original IP地址:%s\n”,buffer);if( 0 == inet_aton(buffer,&in)){ perror(“inet_aton”);exit(1);} else { printf(“the first transfer:0x%0x\n”,in.s_addr);} printf(“begin two process:\n”);if( (str =inet_ntoa(in) == NULL ){ printf(“inet_ntoa:argumentinvalid\n”);} else { printf(“thesecond transfer:%s\n”,str);}说明:1.函数inet_ntoa()的返回值为一个指向字符串的指针,该内存函数inet_ntoa()每次调用都会重新覆盖,因此函数不安全,可能存在某种隐患2.实例:#include #include #include #include #include #include int main() { structin_addr ip1,ip2;char *str1 ;char *str2;ip1.s_addr = 192<<24| 168 <<16 |1 <<8 | 1;ip2.s_addr =255<<24 | 255 <<16 |255<<8|255;str1 = inet_ntoa(ip1);str2 = inet_ntoa(ip2);printf(“ip1:0x%xà%s\n”,ip1.s_addr,str1);printf(“ip2:0x%xà%s\n”,ip2.s_addr,str2);}输出结果为:ip1: 0xc0a80101à255.255.255.255;ip2:0xffffffffà255.255.255.255;表明函数inet_ntoa在进行二进制IP地址到字符串IP地址的转换过程中是不可重入的,这个函数转换两个不同的IP地址得到了同一个结果。此类函数在调用之后,需要立即将结果取出,没有取出结果之前不能进行同样函数的调用。 三。最新的地址转换函数inet_pton()和inet_ntop()函数inet_pton和inet_ntop这2个函数能够处理ipv4和ipv6.算是比较新的函数了。inet_pton函数原型如下[将“点分十进制” -> “整数”],并且这两个函数是一套安全的协议无关的地址转换函数。所谓安全即这两个函数是可重入的,并且这些函数支持多种地址类型,包括IPv4和IPv6. 1.inet_pton()函数1>函数功能inet_pton()函数将字符串类型的IP地址转换为二进制类型。 2>函数原型#include #include #include intinet_pton(int af, const char *src, void *dst);3>函数形参:? int af:af表示网络类型的协议族,在IPv4下的值为AF_INET;? src:存放需要转换的字符串? dst :存放转换后的结果,在IPv4下,dst指向结构struct in_addr的指针。 4>函数返回值当函数inet_pton()的返回值为-1的时候,通常是用于af所指定的协议族不支持造成,此时errno的返回值为EAFNOSUPPORT;当函数的返回值为0时,表示src指向的值不是合法的IP地址;当函数的返回值为正值时,表示转换成功。 2.inet_ntop()函数1>函数功能inet_pton()函数将二进制的网络IP地址转换为字符串。 2>函数原型:#include #include #include intinet_nton(int af, const void *src, char *dst,socklen_t cnt);3>函数形参:? int af:af表示网络类型的协议族,在IPv4下的值为AF_INET;? src :为需要转换的二进制IP地址,在IPv4下,src指向一个structin_addr结构类型的指针。? dst指向保存结果缓冲区的指针? cnt的值是dst缓冲区的大小4>函数返回值Inet_ntop()函数返回一个指向dst的指针。当发生错误时,返回NULL.当af设定的协议族不支持时,errno设置为EAFNOSUPPORT;当dst缓冲区大小过小的时候errno的值为ENOSPC. 3.函数实例:#include #include #include #include #include #include int main(int argc,char *argv[]) { struct in_addr ip;char ipstr[] = “192.168.1.1”;char addr[ADDRLEN];const char * str = NULL;int err = 0;if(err > 0){ printf(“inet_pton:ip %s value is :0x%x\n”,ipstr,ip.s_addr);} //把192.168.12.255转换为网络字节序ip.s_addr = htonl(192 << 24 | 168<<16 | 12<<8 | 255);str = (const char *)inet_ntop(AF_INET,(void*)&ip,(char *)&addr[0],ADDRLEN);if(str){ printf(“inet_ntop :ip 0x%x is%s\n”,ip.s_addr,str);}四。inet_makeaddr()函数,inet_lnaof()函数和inet_netof()函数1.struct in_addr inet_makeaddr(int net,int host) 1>函数功能:一个主机的IP地址分为网络地址和主机地址,inet_makeaddr()函数将主机字节序的网络地址net和主机地址host合并成一个网络字节序的IP地址。 2>函数形参:? int net:存放网络号参数(二进制形式的主机字节序)? int host:存放主机号地址(二进制形式的主机字节序) 3>函数返回值:返回一个网络字节序的IP地址4>函数实例:unsigned long net,host;net = 0x0000007F;host = 0x00000001;struct in_addr ip = inet_makeaddr(net,hst);2.in_addr_t inet_lnaof(struct in_addr in)
由于最近家里诸事繁多,目前的现状再也无法为继了,于是做出了一个重要的决定--离职。事实上,在现在的公司做出这样的决定也是顺理成章的事情,毕竟在去年的这个时候一起风雨同舟的同事们都已经陆续离职了,我是为数不多坚持到现在的项目成员了。当然我也并没有继续之前的项目,而且被外派到北京的另外一个项目中。刚到伊始,由于该项目组的压力很大,周围的同事们也都比较敬业,再有这也是我第一次正式和北京的同事们一起合作,当然也是我第一次感受到北京软件开发的浓浓氛围。坦白的讲,这个项目组所做的东西和我的技术匹配度并不是很高,还好大家都比较职业,并且分工明确,而分到我负责的部分也是相对比较擅长的,即核心逻辑组件的开发和设计,至于UI逻辑和底层技术攻关部分都交给了其他人。 之前也有过几次辞职的经历,只是这次的感觉比较奇怪,可能是年龄的原因吧,确实不能做到年轻时那样毫无顾忌了。即便这次仍然能顺利找到新的工作,但是下一次呢?这种想法在之前的离职中是从未考虑的。有鉴于此,就用了将近一周的时间进行了深入的思考。离职的真实原因究竟是什么,即便是有多个理由,到底哪一个才是最最重要的呢?然后又想,离职的目的又是什么,也就是说为了什么,而这个目的一旦达到之后又能给你带来什么,所带来的这些又能对今后的发展有什么样的帮助,归根结底一句话,主因和长远的规划是否是匹配的。带着这样一连串的疑问开始了自我反省的过程。 还是先说说原因吧。 第一,家庭的负担。主要来自父母的身体,再有就是孩子还小,这样便无法保持这种每周出差的现状了。 第二,工作感觉不好。每周在天津工作的时候,周围没有一个Team Member,连沟通和开开玩笑的人都没有,周围都是其他项目组的成员,没有一个认识的。 第三,沟通效率偏低,有的时候因为一个很简单的Bug或新需求,不得不反复很多次,这种异地的工作方式在沟通上确实存在极大的障碍。 第四,现有的工作和我未来的技术方向不是非常匹配。即便如此,毕竟是老Programmer了,应付起来问题不大。 第五,对移动设备的开发仍然保持着极大的热情,希望能够继续从事这一方面的技术研发工作。 第六、在了解之后,感觉外包公司的文化和所要求的技能对我来说,确实非常不合适。不过这里的项目运作方式确实给了我一种耳目一新的感觉。 差不多就是这些了吧。从上面的几条中进行分析,第一条是刚性的需求,没有什么可说的,这是充分必要条件。而在其他原因之中,第五条是最最重要的,尽管已经Coding很多很多年,但继续Coding下去的热情仍然和当初一样炽烈,也真的希望能够兑现入行之初的誓言,Coding到退休。然而所不同的是,随着年龄的改变和经验的增多,不可能再像以前那样浑浑噩噩的去Coding了。自己一直非常渴望能够找到一个非常非常适合自己,同时又非常非常有兴趣的方向,在这条路上,最大化自己的经验值,用几年的时间做出一个真正属于自己,同时又能证明自己价值的软件产品来。 当然每个人都希望有一份薪水丰厚的工作,毕竟需要养家糊口,生儿育女。所以我们在急于实现理想的同时也不能不顾及来自于现实的考验。我想,能够完全放得下去殊死一搏并最终取得成功的人应该是极少数,更多的人没有这样的勇气和运气。我作为一名老Programmer,在心态上相比于以前更为平和了,毕竟积蓄和收入都还算说的过去。然而希望赢得尊重的心却更为浓烈了,比如说,在最近这一年多的时间里,坚持写博客和技术分享;之前独立开发的服务器平台已经为多家小型公司使用并成功部署上线;随着架构设计经验的不断提升,设计期间考虑的视角也更为多样。尽管如此,心里始终还是埋藏着那个巨大的缺憾,为什么仍然没有一个真正属于自己的产品呢?为什么不能像一个建筑师那样告诉周围人,这个建筑是我的作品。
问题:在ie浏览器下,域名A通过iframe的方式把登录信息post到域名为B的cas服务器上,经过debug发现A获取loginTicket时的sessionId和post过去时的sessionid不一致。只有ie浏览器有这个问题,火狐谷歌浏览器正常。 原因:查资料知道IE6/IE7支持的P3P(Platform for Privacy Preferences Project (P3P) specification)协议默认阻止第三方无隐私安全声明的cookie,火狐和谷歌目前还不支持P3P安全特性,所以它们不存在此问题了。 解决方法:在第一次获取loginTicket时在response中设置p3p声明,如下:
response.setHeader("P3P", "CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR");
现在正在复习linux,将一些比较常用的东西记下来,一遍以后再次复习 使用root用户登录,或者用普通用户登录之后使用su root切换,相信正常人都会选择前者。 1、切换目录: cd /etc/sysconfig/network-scripts 2、使用vi编辑器打开ifcfg-eth0 vi ifcfg-eth0 修改其中内容: DEVICE=eth0 BOOTPROTO=static IPADDR=192.168.1.3 NETMASK=255.255.255.0 GATEWAY=192.168.1.1 HWADDR=原来是什么就是什么 ONBOOT=yes 然后重启网卡服务: service network restart 如果无法使用service,那么将/sbin加入环境变量,如果可以使用则不需要执行下面命令: export PATH=$PATH:/sbin 这种修改方法是永久的,即使你重启后仍然有效,还有一种比较快捷的方法如下: ifconfig eth0 192.168.1.3 netmask=255.255.255.0 up 立马生效。
前面的章节里对linux的文件的权限做了简单的解释。现在来看看常见的命令,从简单的开始: 1 、切换目录 cd 到/tmp 目录:cd /tmp 到上层目录:cd .. 2 、查看当前目录 pwd 3、 创建一个新的文件夹: mkdir 创建一层目录: 创建多层目录: 4 、删除目录: rmdir [-p] 如果需要层级删除目录,就需要带上p(只能删除空目录) 5、查询环境变量 echo $PATH 或者$PATH 6、切换用户: su 用户名 7、移动文件 仔细阅读上面的命令,你会发现mv还可以对文件进行从命名,上面的命令将hellot.txt从a中移动到了b中,并改名为hello1.txt 8、查看文件与目录 ls ls -a 目录名称:列出目录中所有的文件 ls -al 目录名:列出长字符串,包含文件的一些详细信息 如果没有给定目录名,那么就是当前目录 9、文件的复制: cp [-adfilprsu] 源文件 目标文件 //将源文件拷贝到目标文件 cp src1,src2,... des //将多个源文件拷贝到目的文件夹 cp这个命令非常重要,不同的身份执行对命令产生不同的效果,尤其是-a,-p参数,对不同的身份来说,区别非常大。 例1: 使用root执行: 如果我们要将文件的所有的属性复制过来,则要加上参数-a 复制一个目录到另外一个目录 cp -r /src /desc 10 、移除文件或目录 rm [-fir] 文件或目录 -f 强制的意思,忽略不存在的文件,不会出现警告信息 -i互动模式:删除前,会询问是否删除 -r :递归删除 这里不再演示,记得之前的rmdir吗,只能删除空目录,所以删除非空目录只能使用rm -r 11、文件类容查询 cat -b:列出行号 -n:列出行号,包括空白行 cat 是一次性将数据显示到屏幕上,如果想一页一页的看怎么办? 使用more命令 more在运行的过程中,你有几个按键可以按: 空格键:代表向下翻一页 Enter:代表向下滚动一行 q:离开more b:往回翻页 12 、创建文件 touch touch a.txt 就会在当前目录下创建a.txt 13、查找文件的命令 whereis ,find whereis [-bmsu] 文件或目录名 -b:二进制文件 -m:只找在说明文件manual路径下的问津 -s:只找source源文件 -u:查找不在上述三个选项中的其他特殊文件 whereis ifconfig 下面看看find命令 find [path] [option] [actioin] 查找/home下面属于gavin的文件 find /home -user gavin 查找系统中不属于任何人的文件 find / -nouser 查找文件名为passwd的这个文件 find / -name passwd 查找文件类型为socket的文件 find / -type s 14、磁盘和目录的容量 df:列出文件系统的整体磁盘使用量 du:评估文件系统的磁盘使用量 15 创建链接文件 ln [-sf] 源文件 目标文件 -s :创建软连接,如果不加则是硬连接 -f:如果目标文件存在,则删除后再建 [root@localhost test2]# echo 'good'>a.txt [root@localhost test2]# ls a.txt [root@localhost test2]# ln -s a.txt b [root@localhost test2]# ls a.txt b [root@localhost test2]# ll total 12 -rw-r--r-- 1 root root 5 Aug 8 01:09 a.txt lrwxrwxrwx 1 root root 5 Aug 8 01:09 b -> a.txt [root@localhost test2]# echo 'hello'>>b [root@localhost test2]# cat b good hello [root@localhost test2]# cat a.txt good hello [root@localhost test2]# ln a.txt c [root@localhost test2]# ll total 20 -rw-r--r-- 2 root root 11 Aug 8 01:09 a.txt lrwxrwxrwx 1 root root 5 Aug 8 01:09 b -> a.txt -rw-r--r-- 2 root root 11 Aug 8 01:09 c [root@localhost test2]# echo 'bad'>>c [root@localhost test2]# cat c good hello bad [root@localhost test2]# cat a.txt good hello bad [root@localhost test2]# cat b good hello bad [root@localhost test2]# rm a.txt rm: remove regular file `a.txt'? y [root@localhost test2]# cat b cat: b: No such file or directory [root@localhost test2]# cat c good hello bad [root@localhost test2]# 运行上面的命令行,相信你对ln的使用会非常清楚的。 15、挂载CD 16、文件压缩 tar -c:创建一个压缩文件 -v:显示压缩过程 -f:给出压缩文件名 -x:解压文件 -t::查看压缩包中又哪些文件
1.设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N), 且只允许使用两个附加变量。 方法一: 每次将数组中的元素右移一位,循环K次,则实现了右移K位。 例如, 原始字符串:abcd1234 右移一位:4abcd123 右移一位:34abcd12 右移一位:234abcd1 右移一位:1234abcd 循环4次,则实现了右移4次 实现函数如下:
void right_shift(char *str, int N, int K) { char temp; K %= N; //目的是,当K > N时,移动K次与移动K-i*N次是一样的。 while(K--) { t = str[N -1]; for(int i = N - 1; i > 0; i--) str[i] = str[i - 1]; str[0] = t; } } 从上面的实现代码可以看出, 由于K %= N, 所以while循环的K值是小于N的。所以时间复杂度最大为O(N^2), 空间复杂度为O(1),不符合题目要求。 方法二: 对于原始字符串abcd1234,右移2位后为:34abcd12。 通过比较可以看出,有两段子字符串的顺序是不变的。abcd12和34。 则可发现,右移K位的过程就是把数组的两部分交换的过程。 例如:abcd12|34. 对abcd12逆序排列:21dcba 对34逆序排列: 43 对全部的21dcba|43进行逆序排列:34abcd21. 得出如下结论: 将字符串S="abcd1234"分为两部分X="abcd12"和Y="34"。那么S=(X, Y) X逆序记为X'="21dcba" Y逆序记为Y'="43" 则(X', Y')="21dcba43"整体再逆序为"34abcd12" = (Y, X) 即(X', Y')' = (Y, X) 代码实现如下: void reverse(char* str, int begin, int end) { char temp; for( ; begin < end; begin++) { temp = str[end]; str[end] = str[begin]; str[begin] = temp; } }
void right_shift(char *str, int N, int K) { K %= N; reverse(str, 0, N - K -1); reverse(str, N - K, N - 1); reverse(str, 0, N - 1); } 该算法则实现了在线性时间内实现右移操作了。 编写主函数测试如下: #include <stdio.h> #include <stdlib.h>
int main() { char str[] = "abcd1234"; printf("The initial string:%s\n", str); right_shift(str, 8, 2); printf("The string after right shift:%s\n", str); system("pause"); return 0 } 2.实现对字符串进行左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n), 空间复杂度为O(1).例如,原始字符串:abcd1234,左旋转2位后为:cd1234ab通过上面的1的分析,只是把右移改为左移。其他方法相同。代码实现如下: void reverse(char* str, int begin, int end) { char temp; for( ; begin < end; begin++) { temp = str[end]; str[end] = str[begin]; str[begin] = temp; } }
void right_shift(char *str, int N, int K) { K %= N; reverse(str, 0, K -1); reverse(str, K, N - 1); reverse(str, 0, N - 1); }
int main() { char str[] = "abcd1234"; printf("The initial string:%s\n", str); right_shift(str, 8, 2); printf("The string after right shift:%s\n", str); system("pause"); return 0 }
(一)浅谈游标 (1)游标的概念 游标是指向查询结果集的一个指针,它是一个通过定义语句与一条Select语句相关联的一组SQL语句,即从结果集中逐一的读取一条记录。游标包含两方面的内容: ●游标结果集:执行其中的Select语句所得到的结果集; ●游标位置:一个指向游标结果集内的某一条记录的指针 利用游标可以单独操纵结果集中的每一行。游标在定义以后存在两种状态:关闭和打开。当游标关闭时,其查询结果集不存在;只有当游标打开时,才能按行读取或修改结果集中的数据。 (2)浅谈游标 游标我们可以通俗的解释为变动的标示。正如它的解释一样,数据库中的游标其实也是一种读取数据的方式。举个简单的例子来说:我有一个电话本,电话本上的号码首先是按地域划分的,现在我想找个家住廊坊的李四。首先我们要做的是先找到廊坊地区的电话表,找到后的表也即是我们上面所说的游标结果集;而为了找到李四我们可能会用手一条一条逐行的扫过,以帮助我们找到所需的那条记录。对应于数据库来说,这就是游标的模型。所以,你可以这样想象:表格是数据库中的表,而我们的手好比是游标。 总结来说游标就好比是在电话本上逐一扫描号码的手指。 (二)使用游标 一个应用程序中可以使用两种类型的游标:前端(客户)游标和后端(服务器)游标,它们是两个不同的概念。 但无论使用哪种游标,都必须经过如下的步骤: ●声明游标 ●打开游标 ●从游标中操作数据 ●关闭游标 下面我们主要讲述下服务器游标: (1)定义游标 使用游标之前必须先声明它。声明指定定义游标结果集的查询。通过使用for update或for read only关键词将游标显式定义成可更新的或只读的。 Declare cursor_name cursor For select_statement [for{read only|update[of colum_name_list]}] 举例: Declare company_crsr cursor For select name,salary from company where salary>2000 For update of name,salary 上面我们声明了一个名为company_crsr的游标。 (2)打开游标 open的语法为: open 游标名 在声明游标后,必须打开它以便用fetch,update,delete读取、修改、删除行。在打开一个游标后,它将被放在游标结果集的首行前,必须用fetch语句访问该首行。 (3)读取游标数据 在声明并打开一个游标后,可用fetch命令从游标结果集中获取数据行。 Fetch的语法为: Fetch [[Next | Prior | First | Last | Absolute{n|@nvar} |Relative {n|@nvar}] From] 游标名 [into 变量列表] 参数说明: Next:返回结果集中当前行的下一行,如果该语句是第一次读取结果集中数据则返回的是第一行 Prior:返回结果集中当前行的上一行,如果该语句是第一次读取结果集中的数据则无记录结果返回并把游标位置设置为第一行。 First:返回游标第一行;Last:返回游标中的最后一行; Absolute{n|@nvar}:如果 n 或 @nvar 为正数,返回从游标头开始的第 n 行并将返回的行变成新的当前行。如果 n 或 @nvar 为负数,返回游标尾之前的第 n 行并将返回的行变成新的当前行。如果 n 或 @nvar 为 0,则没有行返回。n 必须为整型常量且 @nvar 必须为smallint、tinyint 或 int。 RELATIVE {n | @nvar}:如果 n 或 @nvar 为正数,返回当前行之后的第 n 行并将返回的行变成新的当前行。如果 n 或 @nvar 为负数,返回当前行之前的第 n 行并将返回的行变成新的当前行。如果 n 或 @nvar 为 0,返回当前行。如果对游标的第一次提取操作时将FETCH RELATIVE 的 n 或 @nvar 指定为负数或 0,则没有行返回。n 必须为整型常量且@nvar 必须为 smallint、tinyint 或 int。 举例: Fetch next company_crsr into @name,@salary SQL Server在每次读取后返回一个状态值。可用@@sql_status访问该值,下表给出了可能的@@sql_status值及其意义。 值意义: 0——Fetch语句成功 1——Fetch语句导致一错误 2——结果集没有更多的数据,当前位置位于结果集最后一行,而客户对该游标仍发出Fetch语句时。 若游标是可更新的,可用update和delete语句来更新和删除行。 删除游标当前行的语法为: Delete [from] 表名 where current of 游标名 举例:delete from authors where current of authors_crsr 当游标删除一行后,SQL Server将游标置于被删除行的前一行上。 更新游标当前行的语法为: update 表名 set column_name1={expression1|NULL|(select_statement)} [,column_name2={expression2|NULL|(select_statement)} [……] where current of 游标名 举例: update company set name=”张三”,salary=”5000” where current of company_crsr (4)关闭游标 当结束一个游标结果集时,可用close关闭。该语法为: close 游标名 关闭游标并不改变其定义,可用open再次打开。若想放弃游标,必须使用deallocate释放它,deallocater的语法为: deallocater cursor 游标名 deallocater语句通知SQL Server释放Declare语句使用的共享内存,不再允许另一进程在其上执行Open操作。
在oracle世界,你可以使用: 1)case表达式 或者 2)decode函数 来实现逻辑判断。Oracle的DECODE函数功能很强,灵活运用的话可以避免多次扫描,从而提高查询的性能。而CASE是9i以后提供的语法,这个语法更加的灵活,提供了IF THEN ELSE的功能。 case表达式 case表达式,可分两种,简单和搜索,简单case后接表达式,如: 对于简单的case需要几点注意: 1)寻找when的优先级:从上到下 2)再多的when,也只有一个出口,即其中有一个满足了expr就马上退出case 3)不能把return_expr和else_expr指定为null,而且,expr、comparison_expr和return_expr的数据类型必须相同。 搜索case: CASE WHEN condition THEN return_expr [WHEN condition THEN return_expr] ... ELSE else_expr END 例子: - SELECT (CASE WHEN cust_credit_limit BETWEEN 0 AND 3999 THEN ' 0 - 3999'
- WHEN cust_credit_limit BETWEEN 4000 AND 7999 THEN ' 4000 - 7999'
- WHEN cust_credit_limit BETWEEN 8000 AND 11999 THEN ' 8000 - 11999'
- WHEN cust_credit_limit BETWEEN 12000 AND 16000 THEN '12000 - 16000' END)
- AS BUCKET, COUNT(*) AS Count_in_Group
- FROM customers WHERE cust_city = 'Marshal' GROUP BY
- (CASE WHEN cust_credit_limit BETWEEN 0 AND 3999 THEN ' 0 - 3999'
- WHEN cust_credit_limit BETWEEN 4000 AND 7999 THEN ' 4000 - 7999'
- WHEN cust_credit_limit BETWEEN 8000 AND 11999 THEN ' 8000 - 11999'
- WHEN cust_credit_limit BETWEEN 12000 AND 16000 THEN '12000 - 16000' END);
-
- BUCKET COUNT_IN_GROUP
- ------------- --------------
- 0 - 3999 8
- 4000 - 7999 7
- 8000 - 11999 7
- 12000 - 16000 1
用decode可以违反第3NF(行不可再分,列不可再分,列不可重复):列重复 - hr@ORCL> select * from a;
-
- ID NAME
- ---------- ----------
- 1 a
- 2 b
- 3 c
- 1 a
-
- hr@ORCL> select sum(decode(id,1,1,0)) think,
- 2 sum(decode(id,2,2,0)) water,
- 3 sum(decode(id,3,3,0)) linshuibin
- 4 from a;
-
- THINK WATER LINSHUIBIN
- ---------- ---------- ----------
- 2 2 3
一个字段,decode函数可以完全改写简单case; 多个字段,需要复杂的case,方可。 语法: DECODE(value,if1,then1,if2,then2,if3,then3,...,else),表示如果value等于if1时,DECODE函数的结果返then1,...,如果不等于任何一个if值,则返回else。可以用函数或表达式来替代value,if,then,else从而作出一些更有用的比较。 来看看具体的运用: 1 假设我们想给百度职员加工资,其标准是:工资在8000元以下的将加20%;工资在8000元以上的加15% 则: select decode(sign(salary - 8000),1,salary*1.15,-1,salary*1.2,salary) "revised_salary" from employee 2 表table_subject,有subject_name列。要求按照:语、数、外的顺序进行排序 则: select * from table_subject order by decode(subject_name, '语文', 1, '数学', 2, , '外语',3) decode和简单case的性能比较 Oracle的DECODE函数功能很强,灵活运用的话可以避免多次扫描,从而提高查询的性能。而CASE是9i以后提供的语法,这个语法更加的灵活,提供了IF THEN ELSE的功能。
对于很多情况,DECODE和CASE都能解决问题,个人更倾向于使用DECODE,一方面是从8i保留下来的习惯,另一方面是DECODE的语法更加的简洁,代码量要小一些。 不过今天在看Oracle9i的数据仓库手册时发现,Oracle在文档中提到CASE语句的效率会更高一些,尤其是CASE表达式 WHEN 常量 THEN的语法,效率要比CASE WHEN表达式 THEN的语法更高一些。对于后面这种说法倒是没有太多的疑问,对于CASE比DECODE效率高这种说法倒是第一次看到,印象中DECODE效率很高,应该不会比CASE的效率差。 到底效率如何,还是要具体的实例来说: SQL> CREATE TABLE T AS 2 SELECT A.* 3 FROM DBA_OBJECTS A, DBA_MVIEWS; Table created. SQL> SELECT COUNT(*) FROM T; COUNT(*) ---------- 6075760 下面检查DECODE和两种CASE语句的效率: SQL> SET ARRAY 1000 SQL> SET TIMING ON SQL> SET AUTOT TRACE SQL> SELECT DECODE(OWNER, 'SYSTEM', 'SYSTEM', 'SYS', 'SYSTEM', 'USER') 2 FROM T; 6075760 rows selected. Elapsed: 00:00:07.24 Execution Plan ---------------------------------------------------------- Plan hash value: 1601196873 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 4245K| 68M| 13828 (1)| 00:03:14 | | 1 | TABLE ACCESS FULL| T | 4245K| 68M| 13828 (1)| 00:03:14 | -------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 47551 consistent gets 0 physical reads 0 redo size 46288564 bytes sent via SQL*Net to client 67317 bytes received via SQL*Net from client 6077 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 6075760 rows processed
SQL> SELECT CASE OWNER WHEN 'SYSTEM' THEN 'SYSTEM' 2 WHEN 'SYS' THEN 'SYSTEM' 3 ELSE 'USER' END 4 FROM T; 6075760 rows selected. Elapsed: 00:00:07.22 Execution Plan ---------------------------------------------------------- Plan hash value: 1601196873 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 4245K| 68M| 13828 (1)| 00:03:14 | | 1 | TABLE ACCESS FULL| T | 4245K| 68M| 13828 (1)| 00:03:14 | -------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 47551 consistent gets 0 physical reads 0 redo size 46288578 bytes sent via SQL*Net to client 67317 bytes received via SQL*Net from client 6077 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 6075760 rows processed
SQL> SELECT CASE WHEN OWNER = 'SYSTEM' THEN 'SYSTEM' 2 WHEN OWNER = 'SYS' THEN 'SYSTEM' 3 ELSE 'USER' END 4 FROM T; 6075760 rows selected. Elapsed: 00:00:07.23 Execution Plan ---------------------------------------------------------- Plan hash value: 1601196873 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 4245K| 68M| 13828 (1)| 00:03:14 | | 1 | TABLE ACCESS FULL| T | 4245K| 68M| 13828 (1)| 00:03:14 | -------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 47551 consistent gets 0 physical reads 0 redo size 46288585 bytes sent via SQL*Net to client 67317 bytes received via SQL*Net from client 6077 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 6075760 rows processed
我们在学习数据库的时候经常用到数据库的查询语句,它的重要性可想而知,下面我就来分析一下吧。 - txtSQL = "select*from student_Info where student_ID='" & Trim(txtSID.Text) & "'"
-
-
-
- Set mrc = executeSQL(txtSQL, MsgText)
select * from student_Info 这句是查询表 student_Info where student_ID = '" & Trim(txtSID.Text) & "'" 这句是筛选条件 其中Trim()是去前后空格,txtSID.Text这个控件上输入的值。 student_ID等于你控件上输入的值。 ExecuteSQL(txtSQL, MsgText) 很明显是执行SQL。 ExecuteSQL是自定义函数。 传递参数SQL传递查询语句,MsgString传递查询信息。自身以一个数据集对象的形式返回 。 一定是执行SQL语句,里面的两个参数 txtSQL 是指 用来执行的SQL语句 比如:elect * from 表 MsgText参数 指的是实行完SQL语句后的弹出框 是成功了还是失败了之类的
第一句的意思就是:查询学生信息表,筛选出学生ID号为txtSID.Text的学生。 第二句的意思是:执行sql语句,并把MsgText作为参数传递进去,返回一个set类型的数据。 举列: 假如我把我们班的所有的同学排成一列,站在第一位的号码是1,排在1后面的号码为2,以此类推。 第一句sql的意思就是:我现在找到一个同学李四,然后告诉他让他把号码是5的同学给找出来。 那么这个同学就会从1数到5,就把号码是5的同学给找了出来。txtSQL就相当于李四。 但是数据库的sql查询时通过索引查询的,在数据库中不是通过1,2,3,4,5数到5才找到的。而是通过索引直接找到的。 举例: 我找的这个同学手里会有一个名单,每个名字前都有学号。直接叫学号对应的名字,这个人就被找到了。 这个学号就相当于索引。 我要从student_info里面找人,但是,这个人的ID必须是txtSID.Text 例如:我从5年级1班的86个人中找人,我只找一个,这个人的名字叫张三(txtSID.Text)
在做学生管理系统中,由于并不太理解函数的意思,前几天就在程序的后面多写了两个0 <span style="font-family:KaiTi_GB2312;font-size:18px;">Private Sub MDIForm_Load() '从注册表中取得上次关闭MDIForm时的大小 Me.Left = GetSetting(App.Title, "Settings", "MainLeft", 30000) Me.Top = GetSetting(App.Title, "Settings", "MainTop", 30000) Me.Width = GetSetting(App.Title, "Settings", "MainWidth", 80000) Me.Height = GetSetting(App.Title, "Settings", "MainHeight", 80000) End Sub </span>
当时并没有做任何记录,异地访问的过程当中,数据库能连上是没有任何问题,但是就是加载的登录界面就消失了,没有任何反应、提示错误之类的,后来在师傅的指导下,才发现这个问题,是由于多了两个0,是窗体的大小不能显示出来了,超出了屏幕的显示范围。我还以为真的消失了呢? 发现自己的问题:第一:没有及时的记录 第二:没有遵循严格的编程标准 第三:没有及时的学习相关的知识 第四:思考的还是太少,考虑不全,“为人民服务的宗旨”落实的不好 随后进行了相关知识的学习
VB之savesetting|GetSetting用法(保存与索取数据)
VB 中提供了用于访问注册表的方法
GetSetting 函数, 从 Windows 注册表中的应用程序项目返回注册表项设置值。SaveSetting 语句, 在 Windows 注册表中保存或建立应用程序项目。
DeleteSetting 语句, 在 Windows 注册表中,从应用程序项目里删除区域或注册表项设置。
GetAllSettings 函数, 从 Windows 注册表中返回应用程序项目的所有注册表项设置及其相应值(开始是由 SaveSetting 产生)。
诸如窗口位置、使用的文件以及其它项目等程序设置值是存储在各种 .ini 文件中。在 Windows NT、Windows 95 以及 Windows 的较新版本中,这些程序设置值则是存储在系统注册位置中。
Visual Basic 提供了一个标准的注册位置以存储创建于 Visual Basic 的应用程序的程序信息:
HKEY_CURRENT_USER\Software\VB and VBA Program Settings\appname\section\key
GetSetting 函数 从 Windows 注册表中的应用程序项目返回注册表项设置值。语法GetSetting(appname, section, key[, default])GetSetting 函数的语法具有下列命名参数:部分描述appname必要。字符串表达式,包含应用程序或工程的名称,要求这些应用程序或工程有注册表项设置。section必要。字符串表达式,包含区域名称,要求该区域有注册表项设置。key必要。字符串表达式,返回注册表项设置的名称。default可选。表达式,如果注册表项设置中没有设置值,则返回缺省值。如果省略,则 default 取值为长度为零的字符串 ("")。说明如果 GetSetting 的参数中的任何一项都不存在,则 GetSetting 返回 default 的值。 该方法其实读取,注册表中HKEY_CURRENT_USER\Software\VB and VBA Program Settings下相应的值。 ------------------------------------ 语法 GetSetting(appname, section, key[, default]) GetSetting 函数的语法具有下列命名参数: 部分 描述 appname 必要。字符串表达式,包含应用程序或工程的名称,要求这些应用程序或工程有注册表项设置。 section 必要。字符串表达式,包含区域名称,要求该区域有注册表项设置。 key 必要。字符串表达式,返回注册表项设置的名称。 default 可选。表达式,如果注册表项设置中没有设置值,则返回缺省值。如果省略,则 default 取值为长度为零的字符串 ("")。 说明 如果 GetSetting 的参数中的任何一项都不存在,则 GetSetting 返回 default 的值。
在上一遍文章中我们说了VB中基于ADO的数据库访问,接下来让我们一起来看一下ADO的七个对象,其中我们会重点讲述Command和Recordse两个对象。 我们先通过下面这张图对ADO的七个对象有一个大概的了解: 从图中的关系线以及我们可以看出,当我们通过Connection对象与数据源建立连接以后,既可以通过Recordset对象对数据进行操作,也可以通过Command命令对象来执行查询,然后在传送给Recordset对象进行数据操作。 下面我们先说Recordset对象: 例如: - Dim objCn As New Connection Dim objRs As New Recordset
- Dim strCn As String
- Dim strSQL As String
- '建立数据库连接
- objCn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
- "Data Source=" & App.Path \实例1.mdb"
- objCn.Open
- '执行查询命令,获得用户登录口令
- strSQL = "SELECT 口令,身份 FROM 系统用户 WHERE 用户名='" & UserName & "'"
- Set objRs.ActiveConnection = objCn
- objRs.Open (strSQL)
- With objRs '创建客户端的记录集
- .CursorLocation = adUseClient '指定使用客户端光标
- .CursorType = adOpenStatic '指定使用静态光标
- .Open "系统用户", objCn, adOpenStatic, adLockReadOnly
- End With
- ShowData (lngPage) '显示当前记录页数
我们来说一下Command对象: 使用Command对象之前,我们需要执行一下步骤: 1.通过设置ActiveConnection属性是打开的连接与Command对象关联。 2.使用CommandText属性定义命令(如SQL,储存过程)的可执行文本。 3.使用commandType属性指定命令类型。通过Parameter对象和Parameters集合定义参数化查询或存储过程参数。 4.使用Execute方法执行命令并在适当的时候返回Recordset对象 5.使用 CreateParameter方法创建一个与命令相关的新的参数对象。 6.将Command对象传递给Recordset的Source属性以便获得数据。 具体实现: - Private Sub Form_Load()
- Dim strcn As String
- Set objCn = New Connection
- strcn = "Provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;" & "Data Source=" & App.Path & "\实例5.mdb"
- objCn.ConnectionString = strcn
- objCn.Open
-
- '创建执行参数查询的command 对象 objcmd
-
- Set objCmd = New Command
- Set objCmd.ActiveConnection = objCn '创建连接
-
- With objCmd
- .CommandText = "select * from 系统用户 where 用户名 like ?" & "and 身份 like ?"
- '定义命令的可执行文本
- .CommandType = adCmdText '指定命令类型
- End With
- '为command对象创建参数
- Dim parm As New Parameter
- Set parm = objCmd.CreateParameter("用户名", adVarChar, adParamInput, 10)
- objCmd.Parameters.Append parm
- Set parm = objCmd.CreateParameter("身份", adVarChar, adParamInput, 10)
- objCmd.Parameters.Append parm
- et objRs = New Recordset
-
-
- objCmd("用户名") = "%" & Trim(txtUserName) & "%" '%是什么意思???
-
-
- objCmd("身份") = "%" & txtStatus & "%"
-
- Set objRs = objCmd.Execute() '返回recordset对象
- lbl4 = ""
- End Sub
我们还可以在一个Recordset对象实体中使用command对象: - Set cmd.ActiveConnection = cn
- cmd.CommandText = strSql
- cmd.CommandType = adCmdText
- rs.Open cmd, , adOpenStatic, adLockOptimistic
今天在QQ上看到姐的留言,说爸妈吵架了。我以为当孩子都大了,而孙子也都好几岁了,他们也该消停消停了吧。 也许至少在这几年里我没有看到过他们吵过架,在我很小的时候,吵架是常有的事,有一次我印象很深刻, 妈妈出走了,好几天找不到,我被带到舅舅家,那时的我哭着喊着,一个几岁的孩子,任何人都拿我没办法。 我也知道,这给我造成了心理上的伤害,我很害怕。 渐渐的长大了,自己也谈了恋爱,我们也是偶尔的会闹矛盾,有时候也会吵。也慢慢的明白了,这个世界本来 就是这样的,没有永久的和谐,但我只是希望,这只是生活中的一段小插曲而已,希望它会慢慢的褪去。 如今我一人在北京,一年半了,只过年的时候回去过一次,姐说想让我回家一趟,当看到亲人这样要求的时候, 我不知道该如何,是无奈还是愧疚。 为了生活,我失去了很多,曾经我希望,是无牵无挂的。曾经我梦想,是无忧无虑的。 可这一切看来,我们不可能独善其身,总有想念的人,总有要做的事,总有我们无法释怀的,总有我们不得不做出选择的。 一年前为了梦想来到北京,我以为这里是一个新的开始,离开了家的束缚,我以为在这里我可以找到快乐,逃脱了家的闷闷不乐。 我以为...而这仅仅只是我以为。现在什么都变了。 我有大大的梦想,但我深知,那实现不了。我只是把它铭记在心中。 现在我只想要简简单单的生活,不需要轰轰烈烈,不需要哭哭啼啼。 这半年来一直想找个理由辞去工作,去过一段真正属于自己的生活,每隔一段时间我都会定一个日期,"那一天就是我离开的日子" 可每次都艰难的度过了那个我认为的末日,我的身体很累,而现在心也要累了,一直矛盾着,我留下来的唯一理由也许就是为了糊口, 等有一天我足够承受生活的时候,也许我该走了。 我怕我做不到。当周末真正来临的时候, 突然我变的手足无措了,不知道干什么,所以我害怕,当我真正的自由的时候,也许就该颓废了。 我也一直在坚持,哪怕一天。 每天清晨起床的时候,就心想,还好,我还有工作,我还有事情可以做。
此处用的是CheckboxTreeViewer 和treeview大同小异 首先获得Point tree.addMouseListener(new MouseListener() { @Override public void mouseUp(MouseEvent e) { } @Override public void mouseDown(MouseEvent e) { point = new Point(e.x, e.y); } @Override public void mouseDoubleClick(MouseEvent e) { } }); 其次根据point获得TreeItem 再变色 tv.addCheckStateListener(new ICheckStateListener() { public void checkStateChanged(CheckStateChangedEvent event) { // If the item is checked . . . TreeItem ti = tree.getItem(point); // 也可以不用point // TreeItem ti = ((TreeItem) tv.testFindItem(event.getElement())); if (event.getChecked()) { tv.setSubtreeChecked(event.getElement(), true); ti.setBackground(0, Display.getCurrent().getSystemColor(SWT.COLOR_RED)); //获得当前行的第一列 并设置RED色 } else { tv.setSubtreeChecked(event.getElement(), false); ti.setBackground(0, Display.getCurrent().getSystemColor(SWT.COLOR_CYAN)); //获得当前行的第一列 并设置CYAN色
} } });
沟通是当今世界必可或缺能力之一.如何让别人更能了解自己?很简单.只要肯张开你的嘴巴即可. 张开你的嘴巴,愿意让别人了解自己,这样,自己就不会感觉孤独. 人的需求,总结起来,基本都一样.正如马斯洛把人的需求分为七个层次,形成一个金字塔.从最低到最上面分别是:生理需求,安全需求,归属于爱的需求,尊重的需求,认识的需求,审美的需求,自我实现的需求.金字塔形状从下往上,逐渐变窄.说明越往上做到的人不多.生理需求基本上大家都能够解决,处于吃饱不饿的状态.但是越往上,沟通越重要. 感情无论是亲情,友情还是爱情,情情重要,情情要沟通. 血浓于水的亲情 当谈论各种感情的时候,想必大家都会把亲情排在首位.是呢.也许在你最快乐的时候,你想不到与家人分享.但是当你在最痛苦最悲伤的时候,是谁给你力量挺过来,又是谁默默无私不求任何回报的支持你奉献着他自己?是亲情,是一辈子都不能忘怀的苍老的爸妈. 但是亲情也是需要不断沟通,让他们了解你的内心的想法,同时也可以多多了解了解他们的辛酸,他们的不容易. 若是父子之间多沟通,也不会产生过激的矛盾,也不会产生父子反目成仇,最终酿成不堪的后果.这样,孩子多多理解父母,父母多多理解孩子. 感激一生师生情 对于我们每个人来说,在我们从顽皮稚童到青涩少年再到风华正茂的生命历程中,老师是值得我们感恩的人和尊重的人.虽是一把烛火,却燃尽自己,照亮别人. 老师,您是大桥,为我们连接被割断的山峦,让我们走向收获的峰巅;您是青藤,坚韧而修长,指引我们采撷到崖顶的灵芝和人参。当苗儿需要一杯水的时候,绝不送上一桶水;而当需要一桶水的时候,也绝不给予一杯水。适时,适量地给予,这是一个好园丁的技艺。 但是老师的职责不仅仅是教书,最为关键的在于是分析学生的内心状态。每个学生,因为家庭环境,生活环境不同造成性格心态不同,所以,学生的性格心态,都是需要老师来分析的.再说,学生的性格,也不能一槌定音,不能因一面而断定怎么怎么,其实,接触的人不同,表现的性格肯定有所不同而已。正所谓到什么山唱什么歌一样。若是都一样,岂不是被人笑话。即使一个整天活泼开朗嘻嘻哈哈的人到一个陌生人面前,肯定一开始是文文静静的,随后不断交流,才会逐渐表现其外向的性格。但是不能第一面文静就断定这个人是内向,不爱说话什么的吧。那样的话,是不是太武断,对此人有点不公平?并且人的性格也是随环境不断变化的,正所谓没有一成不变的,变才是真正不变的。所以人的性格心思,貌似很难猜透哦,不够大体了解,已经很可以了。并且男女差异也蛮大的,男孩子还是相对于可以吧。毕竟社会对其要求甚大,所以胸怀也相对于强大。 时刻了解学生的动态,对症下药.现在时代是如此开发,只靠静态观察揣摩是远远不够,必须进行时时交流沟通,这样才能做到因材施教. 纯净似水的友情 我很难想象没有朋友的日子,也很难想象没有[朋友的人.正如一位名人所言,没有朋友的天空是黑暗的.我的世界里也坚决不能没有朋友.没有朋友的日子是孤独的,没有诉说的对象是痛苦的,没有谈心的知己是伤不起的呀. 但是,朋友之间也是需要时常聊天,保持联系的呀.为什么有些人的qq动态一直提示,有事没事经常联系,曾经再好的朋友,也是需要时常慰问的,再好的友谊也是需要不断维持的.若是N久不联系,再好的朋友之间也会产生一种说不出来的别扭.所以逢年过节,发个短信,打个电话问候一声.其实费不了多长时间,费不了多少钱.朋友是买不来的,纯洁的友谊是拿俗气的金钱换不回来的,所以不必在乎那一条短信,三四分钟的电话聊天. 在我的生命中,朋友是不可或缺的.对待朋友,以一种真诚的态度对待.我相信,你对他如何,将来他也对你如何.朋友多了,路好走.走的舒心,走的心情舒畅,精神爽了,吃啥啥香,干啥啥行.
英文原文:What makes a great software engineer? 原文发布于 2009-8-21 近几周,一份反映 Netflix 公司企业文化的报告在网上广为流传。 这份报告里列举了很多Netflix公司里令人称赞的做法,包括这个公司是如何的招聘和辞退员工的。 里面有大量的信息是描述Netflix公司是怎样对待员工的,这使Netflix公司变成了一个很有吸引力的工作场所。报告里面提到过有一个关于员工所期望的内容的清单,但没有把清单列出来。 报告的开始部分就谈及了企业价值问题,而且是按照员工的立场角度写的,可惜并没有把这个问题展开。 我并不在Netflix工作 —— 你也知道 (我在 Yahoo!工 作) —— 但我深切的感觉到,不管你在哪里工作,成为一个优秀的员工、优秀的软件开发工程师的过程是一样的。 下面所列举的都是伟大的程序员所具有的经验和品质。 只做正确的事 对于软件这一行的人,我们有个很大的挑战,就是如何能够用正确的方法做事情。什么是正确的方法,这依赖于你在做什么和为谁做。而究竟所谓 “正确的方法”里都包括了什么内容,这并不是重点,重点是你是否能坚持按照这种方式做事。初级程序员的问题通常是不能做到坚持,而资历较深的程序员却能始终坚持原则。 也许会有一个“非常紧急”的项目,或者这个项目很特殊,不能按常规过程开发。这只是个假象。 好的程序员知道即使在任何情况和环境下都要坚持做正确的事情。如果说按正确的方式开发将导致不能按时完成任务,那么,他们就会知道,这个项目是不能按时完工的。 不要妥协,工程质量是你作为一个优秀程序员的唯一终极证明。 确保你所有的代码都是在正确的方法下100%正确的写出的。要按一个优秀的程序员的标准来要求自己。 甘愿受苦 听起来很傻,但却是真的,优秀的程序员都乐于承担工作上给他们带来的痛苦。你说出一个伟大的程序员,我都能告诉你,在他或她的职业生涯里,各个阶段,都曾有花好几天时间去解决一个问题的经历。优秀的程序员品味着困难给他们带来的挑战,这让他们日以继夜,他们明白,问题必须要解决掉。 不太优秀的程序员就不一样了,他们在刚刚碰到有麻烦的迹象时就先想到要寻求帮助。在问题面前,他们习惯于去寻求帮助,而不是自己去努力解决这个问题。他们最喜欢的一句话是:“帮我看看这个问题”。伟大的程序员的第一反应是我要自己解决这个问题。解决问题是种技能,是优秀的程序员非常看重的一种技能。 好的程序员是通过痛苦的磨练才成为伟大的程序员的。痛苦的磨练是说当你对这个问题实在无能为力时才去请求外援。求助就意味着认输, 所有尽量减少这种处境的发生。甘愿受苦。和问题做不懈的斗争。这就是你要学会的。 注意: 我并不是说你不能寻求他人的帮助。我说的是,你首先要尝试自己去完成任务,如果你不能完成,再寻求帮助。不要在自己没有努力过前就轻易的求助。你经常会发现,当你知道了解决方法后,你才认识到,你用自己的力量本也能解决这个问题的。 学无止境 如果有人敢声称他不需要再学任何新的知识,我是绝对不愿意和他共事的。在有些行业,你也许很多年不学新的东西也能干的很好,但软件技术革新的如此之快,你不能不时刻关注。你的老板是由于你有某些技能才花钱雇你的,如果你的技能已经落伍、过期了,那你也就没有价值了。 想成为一名伟大的程序员,你首先要承认你不是无所不知,你必须每天都要努力的寻找、学习新的知识。 在你现在的公司里或组织里寻找能让你学习、让你钦佩的人。在复杂的问题上征求他们的意见,看看他们是怎么思考的。向他们介绍你的解决思路,请他们给予批评指点。如果在你的周围你不能找出一个能作为你的导师的人,这要么是你还没有认真的寻找,要么是你留在了一个不该留的公司里。如果你在现在的工作上不能学习进步,那是到了你该换个工作的时候了。 要阅读网上的博客。关注一些研讨会。与其他程序员交流。伟大的程序员从不停止学习。 分享知识 有一些程序员认为,他们的唯一价值所在就是他们所拥有的知识,于是,分享出他们的知识就会让他们的价值降低。这是大错特错了。让你有价值的不是你的知识,而是如何运用你的知识给公司创造价值。难道还会有比分享知识给他人更能给公司创造价值的方法吗? 我曾经面试过一家公司,知识不共享、相互保密、相互提防的理念在这家公司里根深蒂固。在这样的环境里,员工之间形成了一种恶性竞争的关系,这直接导致了勾心斗角和诬陷中伤的产生。我可不想在这样的公司里工作。如果每个人都对自己知道的事情讳莫如深,那你什么都学不到。 伟大的程序员希望他人也能知道自己所掌握的知识。他们并不担心会因此而失去优势,因为他们相信大家都会这样做。伟大的程序员乐意看到他们的同伴成长、成功。一个公司,它应该被一群喜欢知识共享的人组成,就像人们在运动场上,让团队的每个对员都强大起来,整个团队才会强大。 伸出援助之手 伟大的程序员从来不会说“这不关我的事”。他们总是愿意伸出援助之手。他们经常在做自己的工作之余,去帮助那些编程新手。如果有件任务必须按时完成,而又没有其他人能胜任,伟大的程序员会主动承担起这项任务。他们从来不嘲笑来请求帮助的人,即使问题是那么的小、那么无意义、无价值。伟大的程序员重视他们的团队,愿意为团队做任何的事情。不管是要去写1,000行的代码,还是去编辑一个图片,伟大的程序员都会立即站出来帮助完成。 十年磨一剑 伟大的程序员不是天生的,是后天炼成的。他们是本文上面提到的那些因素造就的,加上还要通过努力的工作。如果你是刚刚意识到这些,那还不晚,你仍然有充分的时间来成为一个伟大的程序员。耐心是关键。伟大的程序员不是在旦夕之间就可以成就的。有些人可能要花上数年,有些人则需要十几年。没有人为你写血泪史。好的公司当发现你有成为伟大程序员的潜质时,会帮助你,为你提供舞台。而你会通过你的努力工作、让你的团队进步来证明自己。要坚定,要自律,通往伟大程序 员的道路会很长。 更新 (5 Sep 2009):针对“甘愿受苦”段内容增加一个声明。好像很多人都误解了我的观点。 声明: 本文里的所有观点和立场都是来自 Nicholas C. Zakas 本人 ,跟 Yahoo!, Wrox 出版公司,O’Reilly 出版公司, 或其他人没有任何关系。我只代表我自己,不代表他们。
英文原文:A Google Interviewing Story 很多年前我进入硅谷人才市场,当时是想找一份高级工程师的职位。如果你有一段时间没有面试过,根据经验,有个非常有用的提醒你应该接受,就是: 你往往会在前几次面试中的什么地方犯一些错误。简单而言就是,不要首先去你梦想的公司里面试。面试中有多如牛毛的应该注意的问题,你可能全部忘记了,所 以,先去几个不太重要的公司里面试,它们会在这些方面对你起教育(再教育)作用。 我第一家面试的公司叫做gofish.com,据我所知,gofish这家公司如今的情况跟我当时面试时完全的不同。我几乎能打保票的说,当时 我在那遇到的那些人都已不再那工作了,这家公司的实际情况跟我们这个故事并不是很相关。但在其中的面试却是十分相关的。对我进行技术性面试的人是一个叫做 Guy的家伙。 Guy穿了一条皮裤子。众所周知,穿皮裤子的面试官通常是让人“格外”恐怖的。而Guy也没有任何让人失望的意思。他同样也是一个技术难题终结者。而且是一个穿皮裤子的技术难题终结者——真的,我做不到他那样。 我永远不会忘记他问我的一个问题。事实上,这个问题是非常的普通——在当时也是硅谷里标准的面试题。 问题是这样的: 假设这有一个各种字母组成的字符串,假设这还有另外一个字符串,而且这个字符串里的字母数相对少一些。从算法上讲,什么方法能最快的查出所有小字符串里的字母在大字符串里都有? 比如,如果是下面两个字符串: String 1: ABCDEFGHLMNOPQRS String 2: DCGSRQPOM 答案是true,所有在string2里的字母string1也都有。如果是下面两个字符串: String 1: ABCDEFGHLMNOPQRS String 2: DCGSRQPOZ 答案是false,因为第二个字符串里的Z字母不在第一个字符串里。 当他问题这个问题时,不夸张的说,我几乎要脱口而出。事实上,对这个问题我很有信心。(提示:我提供的答案对他来说显然是最糟糕的一种,从面试中他大量的各种细微表现中可以看出来)。 对于这种操作一种幼稚的做法是轮询第二个字符串里的每个字母,看它是否同在第一个字符串里。从算法上讲,这需要O(n*m) 次操作,其中n是string1的长度,m是string2的长度。就拿上面的例子来说,最坏的情况下将会有16*8 = 128次操作。 一个稍微好一点的方案是先对这两个字符串的字母进行排序,然后同时对两个字串依次轮询。两个字串的排序需要(常规情况)O(m log m)+ O(n log n) 次操作,之后的线性扫描需要O(m+n) 次操作。同样拿上面的字串做例子,将会需要16*4 + 8*3 = 88加上对两个字串线性扫描的16 + 8 = 24的操作。(随着字串长度的增长,你会发现这个算法的效果会越来越好) 最终,我告诉了他一个最佳的算法,只需要O(n+m) 次操作。方法就是,对第一个字串进行轮询,把其中的每个字母都 放入一个Hashtable里(成本是O(n)或16次操作)。然后轮询第二个字串,在Hashtable里查询每个字母,看能否找到。如果找不到,说明 没有匹配成功。这将消耗掉8次操作——这样两项操作加起来一共只有24次。不错吧,比前面两种方案都要好。 Guy没有被打动。他把他的皮裤子弄的沙沙响作为回应。”还有没有更好的?“他问道。 我的天?这个家伙究竟想要什么?我看看白板,然后转向他。”没有了,O(n+m)是你能得到的最好的结果了——我是说,你至少要对每个字母至少访问一次才能完成这项操作——而这个方案是刚好是对每个字母只访问一次“。我越想越确信我是对的。 他走到白板前,”如果这样呢——假设我们有一个一定个数的字母组成字串——我给每个字母分配一个素数,从2开始,往后类推。这样A将会是2,B 将会是3,C将会是5,等等。现在我遍历第一个字串,把每个字母代表的素数相乘。你最终会得到一个很大的整数,对吧?然后——轮询第二个字符串,用每个字 母除它。如果除的结果有余数,这说明有不匹配的字母。如果整个过程中没有余数,你应该知道它是第一个字串恰好的子集了。这样不行吗?“ 每当这个时候——当某个人的奇思异想超出了你的思维模式时,你真的需要一段时间来跟上他的思路。现在他站在那里,他的皮裤子并没有帮助我理解他。 现在我想告诉你—— Guy的方案(不消说,我并不认为Guy是第一个想出这招的人)在算法上并不能说就比我的好。而且在实际操作中,你很可能仍会使用我的方案,因为它更通 用,无需跟麻烦的大型数字打交道。但从”巧妙水平“上讲,Guy提供的是一种更、更、更有趣的方案。 我没有得到这份职位。也许是因为我拒绝了他们提供给我的一些讨厌的工作内容和其它一些东西,但这都无所谓了。我还有更大更好的目标呢。 接着,我应 聘了become.com。在跟CTO的电话面试中,他给我布置了一道”编程作业“。这个作业有点荒唐——现在回想起来,大概用了我 3天的时间去完成。我得到了面试,得到了那份工作——但对于我来说,最大的收获是这道编程作业强迫我去钻研并有所获。我需要去开发一个网页爬虫,一个拼写 检查/纠正器,还有一些其它的功能。不错的东西。然而,最终,我拒绝了这份工作。 终于,我来到了Google面试。我曾说过Google的面试过程跟外面宣传的很一致。冗长——严格,但诚实的说,相当的公平。他们在各种面试过程中尽最大的努力去了解你、你的能力。并不是说他们在对你做科学研究,但我确信他们是努力这样做。 我在Google的第四场面试是一个女工程师,老实话,是一场很无聊的面试。在前面几场面试中我表现的很好,感觉到我的机会非常的大。我相信如果不做出什么荒唐事情来,十拿九稳我能得到这份工作。 她问了我一些关于排序或设计方面的非常简单的问题,我记不清了。但就在45分钟的面试快要结束时,她对我说”我还有一个问题。假设你有一个一定长度的由字母组成的字符串。你还有另外一个,短些。你如何才能知道所有的在较短的字符串里的字母在长字符串里也有?“ 哇塞。Guy附身了。 现在,我完全可以马上结束这场面试。我可以对她说“哈哈,几个星期前我就知道答案啦!”,这是事实。但就是在几个星期前被问到这个问题时——我 给出的也是正确的答案。这是我本来就知道答案的问题。看起来就好像是Guy为我的这次面试温习过功课一样。而且,可恶,人们通常是通过上网来搜集面试问题 ——而我,我可以毫不客气的说,对于这些问题,我不需要任何“作 弊”。我自己知道这些答案! 现在你们可能认为——就在她问出了问题之后,在我准备开始说出在脑海里构思完成的最后的演讲之前——你们可能会想,我应该是,当然该,从情理上 讲,镇定的回答出这个问题,并且获得赞赏。可糟糕的是,事实并不是这样。打个比喻,就像是她问出来问题后,我在脑子里立即举起了手,并大叫着“我!嗨! 嗨!我知道!让我来回答吧!”我的大脑试图夺走我对嘴巴的控制权(这事经常发生),幸亏我坚强的毅力让我镇定下来。 于是我开始回答。平静的。带着不可思议的沉着和优雅。带着一种故意表现出来的——带着一种,我认为,只有那种完全的渊博到对古今中外、不分巨细的知识都精通的人才能表现出来的自信。 我轻描淡写的说出来那种很幼稚的方案,就好象是这种方案毫无价值。我提到了给它们排序,就好像是在给早期的《星际迷航》中的一个场景中的人物穿上红T恤似的。最后,平淡的,就好像是我决定了所有事情的好坏、算法上的效率,我说出了O(n+m) 一次性方案。 我要告诉你——尽管我表明上的平静——这整个过程我却在做激烈的挣扎,内心里我在对自己尖着——“你个笨蛋,赶紧告诉她素数方案!” 当我完成了对一次性算法的解释后,她完全不出意外的认可的点了下头,并开始在笔记本上记录。这个问题她以前也许问过了一百次,我想大部分的人都能回答上来。她也许写的是“回答正确。无聊的面试。正确的回答了无聊的字符串问题。没有惊喜。无聊的家伙,但可以留下。” 我等了一会。我让这种焦灼的状态持续的尽可能的长。我可以发誓的说,如果再耽搁一分钟,我一定会憋出脑血栓、脱口说出关于素数的未解之谜。 我打破了沉默。“你知道吗,还有另外一个,可能是更聪明的算法。” 她二目空空的抬头看了一眼,仅在瞬间闪现过一丝希望。 “假设我们有一定长度的字符串。我们可以给每个字母分配一个素数,从2开始。然后我们把大字串中的每个字母代表的素数相乘得出一个数,用小字串中的每个字母代表的素数去除它。如果除的过程中没有产生余数,则小字串是大字串的一个子集。” 在此时,我猜,她看起来就像是Guy当时把相同的话说给我听时我表现出来的样子。而我演讲时泰然自若的表情没了,眼睛瞪大,说话时稍微带出来一些唾沫星子。 一会儿后,她不得不说了,“可是…等一下,有可能…是的,可以这样!可是如何…如果…噢,噢,可行!简洁!” 我得意洋洋的吸了一口气。我在我的面试记录里写下了“她给了我一个‘简洁’的评语!”在她提出这个问题之前我就确信能得到这份工作,现在我更加确信了。还有一点我十分确信的是,我(更准确的说是Guy)给了她今天的好心情。 我在Google干了3年,生活的十分愉快。我在2008年辞职去到一个小公司里做CTO,之后又开办了一个自己的公司。大概是一年前,我偶然的在一个创业论坛会上遇到了Guy,他记不得我了,当我向他细述这段往事时,他对他那条皮裤子大笑不已。 话说回来,如果这个故事里有什么教育意义的话——永远不要冒失的首先去应聘你梦想的公司,应先去应聘那些你不看好的职位。你除了能从这些面试中获得经验外,你指不定能遇到某个能为你的更重要的面试铺路的人呢。事实上,这个经验在你生活中的很多其它事情上也适应。 说正经的,如果你有机会想找一个解决问题的高手——雇佣Guy比谁都强。那个家伙很厉害。 (在这些陈年旧账里发现的一点技术瑕疵:字母有可能重复而字符串可能会很长,所以必须要有统计。用那个最幼稚的解决方案时,当在大字符串里找到 一个字符后就把它删掉,当这样仍然是 O(n*m)次。在Hashtable里我们会有一个key->value的计数。Guy的方案在这种情况下仍然好用。)
近日较火的一帖子就是京东员工按时上下班遭“被离职”。话说一员工入职一个多月以来,每天保质保量完成任务,没迟到过,没早退过,按时上下班。因为没有加班,被京东开除,领导的理由是:按时上下班,没有奉献精神。坑爹啊。 人剥削人的社会现象是永远都存在的,然而当文明越来越发达的今天,人对于自我的思考也就越多。以现在社会生产力,人的生存早已不成问题,当人们解决了生存问题,解决了生活问题,肯定就会对自己长久的发展开始了思考。 对比着目前的状态,思索未来的道路。 若现在的企业还沿用着古老的方式,压榨剥削着人们,我认为这个企业就是在为自己挖掘坟墓,努力地挖坑,然后把自己给埋了。埋了就埋了,还想着在坑爹,谁会呆在这样的公司。而现在,这种傻逼的公司,傻逼的老板太多了,你按时下班他就会感觉着心里不舒服,觉得给你发那多工资亏了,只有在对你不断的压榨中才能找到心理的平衡。不去寻求高效的管理,高效的开发,单纯的靠加班又不给加班费来降低成本,完成目标,这样的企业能有什么竞争力。 试想一下,头天晚上加班到深夜,第二天还要早早上班,即便不昏昏欲睡,效率也会大大降低,就这样磨洋工,混日子,哪还有什么工作积极性,如此恶性循环,长此以往,身体也会搞垮掉。没有周末,没有节假日,每天还要加班的深夜,谁堪承受。身体是革命的本钱,把身体都累垮了,给你再多的钱又有什么用呢,只有工作没有休息,赚了钱都消费不出去,那赚钱还有什么意义。苦逼的程序员啊,加班加班,30岁的年龄80岁的心脏。看一博客,说有一个漂亮女人和一个帅哥在吃KFC,说了句“没事的,我们还有的是时间,我老公是做IT的,他现在还在加班呢!”,老公是做IT的……听着欲哭无泪啊。谁想加班,谁还会去做IT…… 看一个员工的能力,要看他单位时间内完成的工作量,八小时工作的时间就精力高度集中,高效完成任务,下班就好好休息。学要学好,玩要玩好。如果仅凭他是否加班来评定那将是多么扯淡,当一员工老是要加班才能完成别人都能按时完成的任务,那就要对他的能力产生怀疑了,或者是他在别人工作时打酱油去了。若一个公司有加班费,而员工本来没什么任务也呆在公司混时间赚加班费,这样的员工也不会有什么大的作为,甚至要对其人品产生质疑。这样的加班对公司,对员工都没什么意义。 所以啊请不要成为傻逼的公司,请不要再做傻逼的老板了。IT公司,想要真的有所作为,请不要再加班了,有木有,有木有啊…… 如真是紧急情况需要加班,也不能说不行,但也要通过调休或者加薪的方式对员工补偿回来。并且加班的持续时间不能过长,要是连续加班两周估计就会有人受不了,更要把这种紧急加班情况减少到最低。
|
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
24 | 25 | 26 | 27 | 28 | 29 | 30 | 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 | 1 | 2 | 3 | 4 |
|
导航
统计
- 随笔: 17
- 文章: 0
- 评论: 10
- 引用: 0
常用链接
留言簿
随笔档案
搜索
最新评论
阅读排行榜
评论排行榜
|
|