# 5.4 位图数据类型的应用

在Redis里,位图(Bitmap)是由一串二进制数字组成的,它不是一种数据类型,而是基于字符串、能面向字节操作的对象.位图的长度不固定,但是在计算机里8位(bit)能组成一个字节(Byte),所以位图的长度一般是8或者是8的倍数

## 5.4.1 `SETBIT`和`GETBIT`操作

* `SETBIT`
  * 语法:`SETBIT key offset value`.其中:
    * `offset`:偏移量(偏移量从左到右计算)
    * `value`:待设置的值
  * 功能:设置指定键的位图数据
* `GETBIT`
  * 语法:`GETBIT key offset`
  * 功能:读取位图指定位数据.若指定位不存在则返回0

例:

设置位图:

```
127.0.0.1:6379> SETBIT myBitmap 0 1
(integer) 0
127.0.0.1:6379> SETBIT myBitmap 1 1
(integer) 0
127.0.0.1:6379> SETBIT myBitmap 2 0
(integer) 0
127.0.0.1:6379> SETBIT myBitmap 3 0
(integer) 0
127.0.0.1:6379> SETBIT myBitmap 5 1
(integer) 0
```

注意:设置位图数据时只能将值设置为0或1:

```
127.0.0.1:6379> SETBIT myBitmap 7 3
(error) ERR bit is not an integer or out of range
```

读取位图:

```
127.0.0.1:6379> GETBIT myBitmap 1
(integer) 1
127.0.0.1:6379> GETBIT myBitmap 3
(integer) 0
```

读取一个不存在的位:

```
127.0.0.1:6379> GETBIT myBitmap 7
(integer) 0
```

## 5.4.2 用`BITOP`对位图进行运算

* `BITOP`
  * 语法:`BITOP operation destkey key [key ...]`.其中:
    * `operation`:操作符.
      * `AND`:按位与
      * `OR`:按位或
      * `XOR`:按位异或(如果两个比较的位相同,则结果为0;如果两个比较的位不同,则结果为1)
      * `NOT`:按位取反
    * `destkey`:用于保存运算结果的key名
  * 功能:操作位图

例:

创建2个位图:

```
127.0.0.1:6379> SETBIT bit1 0 1
(integer) 0
127.0.0.1:6379> SETBIT bit1 1 1
(integer) 0
127.0.0.1:6379> SETBIT bit1 3 1
(integer) 0
127.0.0.1:6379> SETBIT bit2 2 1
(integer) 0
```

即:

* `bit1`:`1011`
* `bit2`:`0100`

按位与操作:

注:按位与操作的结果应为`0000`

```
127.0.0.1:6379> BITOP AND result bit1 bit2
(integer) 1
```

查看结果:

```
127.0.0.1:6379> GETBIT result 0
(integer) 0
127.0.0.1:6379> GETBIT result 1
(integer) 0
127.0.0.1:6379> GETBIT result 2
(integer) 0
127.0.0.1:6379> GETBIT result 3
(integer) 0
127.0.0.1:6379> get result
"\x00"
```

按位或操作:

注:按位或操作的结果应为`1111`

```
127.0.0.1:6379> BITOP OR result bit1 bit2
(integer) 1
```

查看结果:

```
127.0.0.1:6379> GETBIT result 0
(integer) 1
127.0.0.1:6379> GETBIT result 1
(integer) 1
127.0.0.1:6379> GETBIT result 2
(integer) 1
127.0.0.1:6379> GETBIT result 3
(integer) 1
```

按位取反操作:

注:`bit1`按位取反的结果应为`0100`

```
127.0.0.1:6379> BITOP not result bit1
(integer) 1
```

查看结果:

```
127.0.0.1:6379> GETBIT result 0
(integer) 0
127.0.0.1:6379> GETBIT result 1
(integer) 0
127.0.0.1:6379> GETBIT result 2
(integer) 1
127.0.0.1:6379> GETBIT result 3
(integer) 0
```

按位异或操作:

注:按位异或的结果应为`1111`

```
BITOP xor result bit1 bit2
```

查看结果:

```
127.0.0.1:6379> GETBIT result 0
(integer) 1
127.0.0.1:6379> GETBIT result 1
(integer) 1
127.0.0.1:6379> GETBIT result 2
(integer) 1
127.0.0.1:6379> GETBIT result 3
(integer) 1
```

## 5.4.3 `BITCOUNT`操作

* `BITCOUNT`
  * 语法:`BITCOUNT key [start end]`
  * 功能:统计key在指定范围内的1的出现次数.`0, -1`或不写参数表示统计范围为整个key

注:关于`BITCOUNT`命令中的`start, end`:

`start, end`**表示字符串中的字节偏移,而不是比特偏移**.这一点非常重要.

* `start`:是子范围的起始字节位置(从0开始)
* `end`:是子范围的结束字节位置

例如,对于字符串"foobar":

* 字符"f"在字节偏移0中
* 字符"o"在字节偏移1和2中
* 字符"b"在字节偏移3中
* ...以此类推。

如果你执行命令`BITCOUNT key 0 1`.它会计算"fo"中设置为1的比特位的数量,因为"fo"占据了字节偏移0到1

还有一些其他需要注意的事项:

1. 当start和end都是正数或0时,范围包括start和end两端
2. 当start或end是负数时,它表示从字符串的末尾开始的偏移.例如,-1表示字符串的最后一个字节
3. 如果start大于字符串的长度,或end小于0,结果将是 0
4. 如果end在start之后,则它们会被交换.所以命令`BITCOUNT key 2 0`和`BITCOUNT key 0 2`会产生相同的结果

例:统计用户在线天数

设置用户在线天数

```
127.0.0.1:6379> SETBIT user1 0 1
(integer) 0
127.0.0.1:6379> SETBIT user1 3 1
(integer) 0
127.0.0.1:6379> SETBIT user1 7 1
(integer) 0
```

统计用户在线天数:

```
127.0.0.1:6379> BITCOUNT user1
(integer) 3
127.0.0.1:6379> BITCOUNT user1 0 0
(integer) 3
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://redis.sai.show/di-5-zhang-redis-shu-ju-ku-cao-zuo-shi-zhan/5.4-wei-tu-shu-ju-lei-xing-de-ying-yong.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
