相信用过linux的都执行过这样一条命令:chmod 754 xxx
。
在linux文件系统中,有三个角色组,分别是:所有者(Owner)、组(Group)、其他用户(Other)。
每个组权限中又分别包含: r(读)、w(写)、x(执行) 三种权限,每个权限有一个对应的数字值:r(4)、w(2)、x(1)。
可以通过将这三种权限数字相加得到角色的权限值,例如,读写权限可以表示为 6(4+2+0)。
回到上面的命令chmod 754,7,5,4 每个数字分别对应这三个所属角色权限,7
表示所有者具备读、写和可执行权限,中间的5
表示组具备读和可执行权限,最后一个4
表示其它用户只具备读权限。
❓ 这几个权限的数字为什么是r(4)、w(2)、x(1),而不是3,2,1?
用10进制的角度来看,这几个数字的规律分别是2⁰=1,2¹=2,2²=4。
进一步转换成二进制可以用001,010,100来表示。
再回过头来看权限,权限要么是可以,要么是不可以,可以用一个Boolean来表示,也就是要么是0,要么是1。如果用000来表示3种权限,第一个0表示执行权限,第二个0表示写权限,第三个0表示读权限,那么表示可读写但不可执行就可以用110来表示,而110转换成10进制恰好就等于6,以此类推,111=7(可读写执行),101=5(可读可执行不可写)。
所以用三个二进制位就包含了读,写和执行权限的所有组合情况,用8或10进制来看就是它们可以组合成[1,7]之间任意一个数字。
除了chmod 754 这种纯数字授权,还有一个chmod +x命令
chmod +x其实等价于chmod a+x,这里面的a其实是all的意思,其它的还有u(所有者),g(组),o(其它用户),它的作用是给三组权限全部加上执行权限。假设xxx文件当前权限是763,用二进制表示111 110 011,a+x就是已经有x的不变,没有的加上x执行权限,这与二进制的或( | )运算符的定义不谋而合:对应位置上的两个二进制位中至少有一个为1时,结果位为1;否则为0。这个计算过程用二进制的角度来看其实就是
7 | 1 = 111 | 001 = 111 = 7
6 | 1 = 110 | 001 = 111 = 7
3 | 1 = 011 | 001 = 011 = 3
当然,有+x,那就还有-x,移除权限。不难看出移除权限要做的就是对应位置上的两个二进制位中,如果对应位置都为1,结果位为0,否则取原二进制位的值
这里没有直接对应的二进制运算符可以一步到位满足计算需求,但依然是有办法的
同样以763为例
7 & (1 ^ 7) = 111 & (001 ^ 111) = 111 & 110 = 110 = 6
6 & (1 ^ 7) = 110 & (001 ^ 111) = 110 & 110 = 110 = 6
3 & (1 ^ 7) = 011 & (001 ^ 111) = 011 & 110 = 010 = 2
最终 763 - x = 662。
假设有这样一个需求:查找一个手机号在哪些平台注册过,假设目前只有微信、QQ、抖音、小红书四个平台,将来或许还有微博,快手等。
常规表结构设计可能是phone,exists_wechat,exists_qq,exists_tiktok,exists_xhs这几个字段,后面如果增加其它的平台只能再继续增加表字段。但细心观察就会发现,后面这几个字段都是boolean值,也就是一个二进制位就能表示了。那么我们现在就可以先用四个二进制位来分别表示这4个平台,0000,从右往左第一位表示是否注册过微信,第二位表示是否注册过QQ,以此类推。那么表示该手机号只注册过QQ就可以表示成0010,如果只注册过小红书和QQ,那么就用0110来表示。
表结构就可以设计成phone, apps这两个字段,apps用一个10进制数字表示。
那么如何查询某个手机号是否在某个app平台注册过呢?假设我们需要查询在抖音注册过的手机号,
已知我们现在总共有4个app平台,用二进制表示就是0000,其中从右往左,第3个是表示抖音的位置,也就是要找到值包含?1??
的数字,不难发现 [4,5,6,7,12,13,14,15] 这些都是的。最终需要的查询SQL就应该是select * from tablename where apps in (4,5,6,7,12,13,14,15)
。那用什么方法才能计算出是这几个数字呢?方法也很简单
首先定义一个掩码mask = 1 << n。n(从0开始)是你想找的位下标为1的值,比如n=2,那么mask = 1 << 2 = 0001 << 2 = 0100 = 4。
将1~15分别与4 做 & 运算,只有第2位为1的情况下,&运算的结果才不为0。用代码实现如下:
/**
* 查找第index位上为1的数字
*
* @param index 位下标,从右往左第0位开始
* @return int[]
* @author 敖癸
* @since 2024/1/26 - 10:02
*/
public static int[] findApps(int index) {
int mask = 1 << index;
return IntStream.range(1, 16).filter(i -> (i & mask) != 0).toArray();
}
public static void main(String[] args) {
int[] apps = findApps(2);
for (int i: apps){
System.out.print(i+",");
}
}
// 输出结果:4,5,6,7,12,13,14,15
实体类设计
@Data
public class PhoneApp{
private String phone;
private Integer apps;
/**
* 添加app
*
* @param index 位下标 0:微信,1:QQ,2:抖音,3:小红书
* @author 敖癸
* @since 2024/1/26 - 10:21
*/
public void addApps(int index){
int mask = 1 << index;
this.apps |= mask;
}
}