当前位置: 首页 > article >正文

framebuffer在Ubuntu上的操作

一,frambuffer.c

1.头文件及结构体

#include "framebuffer.h"
#include <linux/fb.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <math.h>

void *pmem;
struct fb_var_screeninfo vinf;

2.初始化framebuffer

int init_fb(char *devname)
{
	//1. 打开显示设备
	int fd = open(devname, O_RDWR);	
	if (-1 == fd)
	{
		perror("fail open fb");
		return -1;
	}
	
	//2、获取显示设备相关参数 分辨率 位深度
	int ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinf);
	if (-1 ==ret)
	{
		perror("fail ioctl");
		return -1;
	}
	
	printf("xres = %d, yres = %d\n", vinf.xres, vinf.yres);
	printf("xres_virtual = %d, yres_virtual = %d\n", vinf.xres_virtual, vinf.yres_virtual);
	printf("bits_per_pixel : %d\n", vinf.bits_per_pixel);

	size_t len = vinf.xres_virtual * vinf.yres_virtual * vinf.bits_per_pixel/8;
	//3, 建立显存和用户空间的映射关系
	pmem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if ((void *)-1 == pmem)
	{
		perror("fail mmap");
		return -1;
	}
	

	return fd;
}

3.画一个点

void draw_point(int x, int y, unsigned int col)
{
	if (x >= vinf.xres || y >= vinf.yres)
	{
		return ;
	}
	if (vinf.bits_per_pixel == RGB888_FMT)
	{
		unsigned int *p = pmem;
		*(p + y * vinf.xres_virtual + x) = col;
	}
	else if (vinf.bits_per_pixel == RGB565_FMT)
	{
		unsigned short *p  = pmem;	
		*(p + y * vinf.xres_virtual + x) = col;
	}
	return ;
}

4.销毁

void uninit_fb(int fd)
{

	size_t len = vinf.xres_virtual * vinf.yres_virtual * vinf.bits_per_pixel/8;
	munmap(pmem, len);
	close(fd);
}

5.清屏

void draw_clear(unsigned int col)
{
	for (int j = 0; j < vinf.xres; j++)
	{
		for (int i = 0; i < vinf.yres; i++)
		{
			draw_point(i, j, col);
		}
	}
}

6.绘制横线,竖线,矩形,斜线,圆

void draw_h_line(int x, int y, int len, unsigned int col)
{
	for (int i = x; i < x+len; i++)
	{
		draw_point(i, y, col);
	}
}
void draw_s_line(int x, int y, int len, unsigned int col)
{
	for (int i = y; i < y+len; i++)
	{
		draw_point(x, i, col);
	}
}

void draw_rectangle(int x, int y, int w, int h, unsigned int col)
{
	draw_h_line(x, y, w, col);
	draw_s_line(x, y, h, col);
	draw_s_line(x+w, y, h, col);
	draw_h_line(x, y+h, w, col);
}

void draw_x_line(int x1, int y1, int x2, int y2, unsigned int col)
{
	
	int x = 0;
	int y = 0;

	if (x1 == x2)
	{
		if (y2 > y1)
		{
			draw_s_line(x1, y1, y2-y1, col);
		}
		else
		{
			draw_s_line(x2, y2, y1-y2, col);		
		}
	}

	double k = (double)(y2-y1)/(double)(x2-x1);
	double b = y1 - k*x1;
   

	for (int x = (x1 > x2 ? x2 : x1); x <= (x1 > x2 ? x1 : x2); x++)
	{
		y = x * k + b;
		draw_point(x, y, col);
	}
	
	return ;
}


void draw_circle(int x0, int y0, int r, unsigned int col)
{
	int x = 0;
	int y = 0;
	for (double si = 0; si <= 360; si+=0.01)
	{
		x = r * cos(2 * 3.14159/360 *si) + x0;
		y = r * sin(2 * 3.14159/360 *si) + y0;
		draw_point(x, y, col);
		draw_point(x-1, y, col);
		draw_point(x+1, y, col);
		draw_point(x, y-1, col);
		draw_point(x, y+1, col);
	}
	
}

7.绘制bmp格式图像

void draw_bmp(int x, int y, char *picname, int w, int h)
{
	int fd = open(picname, O_RDONLY);
	if (-1 == fd)
	{
		perror("fail open bmp");
		return ;
	}
	
	lseek(fd, 54, SEEK_SET);

	unsigned char r, g, b;

	unsigned char *buff = malloc(w*h*3);
	read(fd, buff, w*h*3);
	
	unsigned char *p = buff;
	for (int j = h-1; j >= 0; j--)
	{
		for (int i = 0; i < w; i++)
		{

			b = *p; p++;
			g = *p; p++;
			r = *p; p++;
			if (vinf.bits_per_pixel == RGB888_FMT)
			{
				unsigned int col = (r << 16) | (g << 8) | (b << 0);
				draw_point(i+x, j+y, col);
			}
			else if (vinf.bits_per_pixel == RGB565_FMT)
			{
				unsigned short col = ((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0);
				draw_point(i+x, j+y, col);
			}
		}
	}

	free(buff);
	close(fd);
}

8.绘制一个字

void draw_word(int x, int y, unsigned char *word, int w, int h, unsigned int col)
{

	for (int j = 0; j < h; j++)
	{
		for (int i = 0; i < w; i++)
		{
			unsigned char tmp = word[i+j*w];
			for (int k = 0; k < 8; k++)
			{
				if (tmp & 0x80)
				{
					draw_point(i*8+k+x, j+y, col);
				}
				else
				{
					//文字的背景色
				}
				tmp = tmp << 1;
			}
		}
	}
}

9.绘制文字库里的单字

int draw_utf8(UTF8_INFO *info, int x, int y, char* zi, unsigned int col, unsigned int col1)
{
    unsigned long  out = 0 ;
    int ret = enc_utf8_to_unicode_one((unsigned char*)zi,&out);

    unsigned char* data = get_utf_data(info,out);
    unsigned char temp = 0 ;
    unsigned int i,j,k;
    unsigned int num = 0;
    for(i=0;i<info->height;i++)
    {
        for(j=0;j<info->width/8;j++)
        {
            temp = data[num++];
            for(k=0;k<8;k++)
            {
                if(0x80&temp)
                {
                    draw_point( x+k+j*8, y+i, col);
                }
                else
                {

                 //   draw_point( x+k+j*8, y+i, col1);
                }
                temp= temp<<1;
            }
        }

    }
    return ret;
}

10.绘制文字库里的字符串

int draw_utf8_str(UTF8_INFO *info, int arg_x, int arg_y,  char* zi, unsigned int col, unsigned int col1)
{
    char* temp = zi;
    unsigned int x = arg_x ;
    unsigned int y =  arg_y;

    while(*temp != '\0')
    {
        int ret = draw_utf8(info, x, y, temp, col, col1);
        x += info->width;
        if(x > vinf.xres)
        {
            x = 0;
            y += info->height;
            if(y > vinf.yres)
            {
                y = 0;
            }
        }

        temp += ret;
    }
    return 0;
}

二, utf.c

#include "utf.h"

/*****************************************************************************
 * 函数名:enc_get_utf8_size
 * 将一个字符的UTF8编码转换成Unicode(UCS-2和UCS-4)编码.
 *
 * 参数:
 *    pInput      指向输入缓冲区, 以UTF-8编码
 *
 *
 * 返回值:
 *    成功则返回该字符的UTF8编码所占用的字节数; 失败则返回0.
 * 注意事项:无
 ******************************************************************************/
int enc_get_utf8_size(const unsigned char pInput)
{
    unsigned char c = pInput;
    // 0xxxxxxx 返回0
    // 10xxxxxx 不存在
    // 110xxxxx 返回2
    // 1110xxxx 返回3
    // 11110xxx 返回4
    // 111110xx 返回5
    // 1111110x 返回6
    if(c< 0x80) return 0;
    if(c>=0x80 && c<0xC0) return -1;
    if(c>=0xC0 && c<0xE0) return 2;
    if(c>=0xE0 && c<0xF0) return 3;
    if(c>=0xF0 && c<0xF8) return 4;
    if(c>=0xF8 && c<0xFC) return 5;
    if(c>=0xFC) return 6;
    return -1;
}


/*****************************************************************************
 * 函数名:enc_utf8_to_unicode_one
 * 将一个字符的UTF8编码转换成Unicode(UCS-2和UCS-4)编码.
 *
 * 参数:
 *    pInput      指向输入缓冲区, 以UTF-8编码
 *    Unic        指向输出缓冲区, 其保存的数据即是Unicode编码值,
 *                类型为unsigned long .
 *
 * 返回值:
 *    成功则返回该字符的UTF8编码所占用的字节数; 失败则返回0.
 *
 * 注意事项:
 *     1. UTF8没有字节序问题, 但是Unicode有字节序要求;
 *        字节序分为大端(Big Endian)和小端(Little Endian)两种;
 *        在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位)
 ****************************************************************************/
int enc_utf8_to_unicode_one(const unsigned char* pInput, unsigned long *Unic)
{
    assert(pInput != NULL && Unic != NULL);

    // b1 表示UTF-8编码的pInput中的高字节, b2 表示次高字节, ...
    char b1, b2, b3, b4, b5, b6;

    *Unic = 0x0; // 把 *Unic 初始化为全零
    int utfbytes = enc_get_utf8_size(*pInput);
    //int utfbytes = 3;
    unsigned char *pOutput = (unsigned char *) Unic;

    switch ( utfbytes )
    {
    case 0:
        *pOutput     = *pInput;
        utfbytes    += 1;
        break;
    case 2:
        b1 = *pInput;
        b2 = *(pInput + 1);
        if ( (b2 & 0xE0) != 0x80 )
            return 0;
        *pOutput     = (b1 << 6) + (b2 & 0x3F);
        *(pOutput+1) = (b1 >> 2) & 0x07;
        break;
    case 3:
        b1 = *pInput;
        b2 = *(pInput + 1);
        b3 = *(pInput + 2);
        if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) )
            return 0;
        *pOutput     = (b2 << 6) + (b3 & 0x3F);
        *(pOutput+1) = (b1 << 4) + ((b2 >> 2) & 0x0F);
        break;
    case 4:
        b1 = *pInput;
        b2 = *(pInput + 1);
        b3 = *(pInput + 2);
        b4 = *(pInput + 3);
        if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)
             || ((b4 & 0xC0) != 0x80) )
            return 0;
        *pOutput     = (b3 << 6) + (b4 & 0x3F);
        *(pOutput+1) = (b2 << 4) + ((b3 >> 2) & 0x0F);
        *(pOutput+2) = ((b1 << 2) & 0x1C)  + ((b2 >> 4) & 0x03);
        break;
    case 5:
        b1 = *pInput;
        b2 = *(pInput + 1);
        b3 = *(pInput + 2);
        b4 = *(pInput + 3);
        b5 = *(pInput + 4);
        if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)
             || ((b4 & 0xC0) != 0x80) || ((b5 & 0xC0) != 0x80) )
            return 0;
        *pOutput     = (b4 << 6) + (b5 & 0x3F);
        *(pOutput+1) = (b3 << 4) + ((b4 >> 2) & 0x0F);
        *(pOutput+2) = (b2 << 2) + ((b3 >> 4) & 0x03);
        *(pOutput+3) = (b1 << 6);
        break;
    case 6:
        b1 = *pInput;
        b2 = *(pInput + 1);
        b3 = *(pInput + 2);
        b4 = *(pInput + 3);
        b5 = *(pInput + 4);
        b6 = *(pInput + 5);
        if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)
             || ((b4 & 0xC0) != 0x80) || ((b5 & 0xC0) != 0x80)
             || ((b6 & 0xC0) != 0x80) )
            return 0;
        *pOutput     = (b5 << 6) + (b6 & 0x3F);
        *(pOutput+1) = (b5 << 4) + ((b6 >> 2) & 0x0F);
        *(pOutput+2) = (b3 << 2) + ((b4 >> 4) & 0x03);
        *(pOutput+3) = ((b1 << 6) & 0x40) + (b2 & 0x3F);
        break;
    default:
        return 0;
        break;
    }

    return utfbytes;
}








/*****************************************************************************
 * 函数名:enc_unicode_to_utf8_one
 * 将一个字符的Unicode(UCS-2和UCS-4)编码转换成UTF-8编码.
 *
 * 参数:
 *    unic     字符的Unicode编码值
 *    pOutput  指向输出的用于存储UTF8编码值的缓冲区的指针
 *    outsize  pOutput缓冲的大小
 *
 * 返回值:
 *    返回转换后的字符的UTF8编码所占的字节数, 如果出错则返回 0 .
 *
 * 注意事项:
 *     1. UTF8没有字节序问题, 但是Unicode有字节序要求;
 *        字节序分为大端(Big Endian)和小端(Little Endian)两种;
 *        在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位)
 *     2. 请保证 pOutput 缓冲区有最少有 6 字节的空间大小!
 ****************************************************************************/
int enc_unicode_to_utf8_one(unsigned long unic, unsigned char *pOutput,
                            int outSize)

{
    assert(pOutput != NULL);
    assert(outSize >= 6);

    if ( unic <= 0x0000007F )
    {
        // * U-00000000 - U-0000007F:  0xxxxxxx
        *pOutput     = (unic & 0x7F);
        return 1;
    }
    else if ( unic >= 0x00000080 && unic <= 0x000007FF )
    {
        // * U-00000080 - U-000007FF:  110xxxxx 10xxxxxx
        *(pOutput+1) = (unic & 0x3F) | 0x80;
        *pOutput     = ((unic >> 6) & 0x1F) | 0xC0;
        return 2;
    }
    else if ( unic >= 0x00000800 && unic <= 0x0000FFFF )
    {
        // * U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx
        *(pOutput+2) = (unic & 0x3F) | 0x80;
        *(pOutput+1) = ((unic >>  6) & 0x3F) | 0x80;
        *pOutput     = ((unic >> 12) & 0x0F) | 0xE0;
        return 3;
    }
    else if ( unic >= 0x00010000 && unic <= 0x001FFFFF )
    {
        // * U-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
        *(pOutput+3) = (unic & 0x3F) | 0x80;
        *(pOutput+2) = ((unic >>  6) & 0x3F) | 0x80;
        *(pOutput+1) = ((unic >> 12) & 0x3F) | 0x80;
        *pOutput     = ((unic >> 18) & 0x07) | 0xF0;
        return 4;
    }
    else if ( unic >= 0x00200000 && unic <= 0x03FFFFFF )
    {
        // * U-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
        *(pOutput+4) = (unic & 0x3F) | 0x80;
        *(pOutput+3) = ((unic >>  6) & 0x3F) | 0x80;
        *(pOutput+2) = ((unic >> 12) & 0x3F) | 0x80;
        *(pOutput+1) = ((unic >> 18) & 0x3F) | 0x80;
        *pOutput     = ((unic >> 24) & 0x03) | 0xF8;
        return 5;
    }
    else if ( unic >= 0x04000000 && unic <= 0x7FFFFFFF )
    {
        // * U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
        *(pOutput+5) = (unic & 0x3F) | 0x80;
        *(pOutput+4) = ((unic >>  6) & 0x3F) | 0x80;
        *(pOutput+3) = ((unic >> 12) & 0x3F) | 0x80;
        *(pOutput+2) = ((unic >> 18) & 0x3F) | 0x80;
        *(pOutput+1) = ((unic >> 24) & 0x3F) | 0x80;
        *pOutput     = ((unic >> 30) & 0x01) | 0xFC;
        return 6;
    }

    return 0;
}

/*****************************************************************************
 * 函数名:init_utf8
 * 将字库文件读取到缓存区
 *
 * 参数:
 *    info     缓存区数据结构

 *
 * 返回值:
 *    无
 *
 * 注意事项:
 *    无
 *
 ****************************************************************************/
void init_utf8(UTF8_INFO *info)
{
   int ret = 0 ;
    int fd = open(info->path,O_RDONLY);
    if(-1 == fd)
    {
        exit(1);
    }
    struct stat st;
    ret = stat(info->path,&st);
    if(-1 == ret)
    {
        printf("get zi ku file size error");
        exit(1);
    }
    if(NULL == info->g_ziku_data)
    {
       info->g_ziku_data= malloc(st.st_size);
    }
    ret = read(fd,info->g_ziku_data,st.st_size);
    if(ret<=0)
    {
        printf("read utf-8 info error!");
        exit(1);
    }
//    info->height = heigh;
//    info->width = width;
    info->zimo_size = st.st_size /65536;
    close(fd);
}

/*****************************************************************************
 * 函数名:uninit_utf8
 * 回收字模缓存区空间
 *
 * 参数:
 *    info     需要回收的字模缓存区
 *
 * 返回值:
 *    无
 *
 * 注意事项:
 *    无
 *
 ****************************************************************************/
void uninit_utf8(UTF8_INFO *info)
{
    free(info->g_ziku_data);
}

/*****************************************************************************
 * 函数名:get_utf_data
 * 根据编号得到字模
 *
 * 参数:
 *    info     字模缓存区
 *    out      字的编码
 *
 * 返回值:
 *    字模起点位置
 *
 * 注意事项:
 *    无
 *
 ****************************************************************************/
unsigned char* get_utf_data(UTF8_INFO *info,int out)
{
    unsigned char* temp =  info->g_ziku_data+out*info->width*info->height/8;
    return temp;
}

三,头文件

1.frame buffer.h

#ifndef __FRAMEBUFFER_H__
#define __FRAMEBUFFER_H__

#include "utf.h"

#define RGB888_FMT 32
#define RGB565_FMT 16


extern int init_fb(char *devname);
extern void draw_point(int x,int y, unsigned int col);
extern void uninit_fb(int fd);
extern void draw_clear(unsigned int col);

extern void draw_h_line(int x, int y, int len, unsigned int col);
extern void draw_s_line(int x, int y, int len, unsigned int col);
extern void draw_rectangle(int x, int y, int w, int h, unsigned int col);
extern void draw_x_line(int x1, int y1, int x2, int y2, unsigned int col);
extern void draw_circle(int x0, int y0, int r, unsigned int col);
extern void draw_bmp(int x, int y, char *picname, int w, int h);
extern void draw_word(int x, int y, unsigned char *word, int w, int h, unsigned int col);
extern int draw_utf8(UTF8_INFO *info, int x, int y, char* zi, unsigned int col, unsigned int col1);
extern int draw_utf8_str(UTF8_INFO *info, int arg_x, int arg_y,  char* zi, unsigned int col, unsigned int col1);



#endif

2.utf.h

#ifndef UTF
#define UTF
#ifdef __cplusplus
extern "C"{
#endif
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <fcntl.h>
#define u8 unsigned char 
#define u16 unsigned short 
#define u32 unsigned int

#define ZIKUK_FILE_SMALL "./ziku"
#define ZIKUK_FILE_BIG "./ziku2_w32_h32"
/***字模文件缓存**/
typedef struct
{
    char path[256];//字模库文件路径
    unsigned width; //字模宽度
    unsigned height;//字模高度
    unsigned zimo_size;//每个字字模字节数
    unsigned char* g_ziku_data;//字模库文件缓存区
}UTF8_INFO;

extern void init_utf8(UTF8_INFO *info);
extern unsigned char *get_utf_data(UTF8_INFO *info,int out);

extern void uninit_utf8(UTF8_INFO *info);
extern int enc_utf8_to_unicode_one(const unsigned char* pInput, unsigned long *Unic);
extern int enc_unicode_to_utf8_one(unsigned long unic, unsigned char *pOutput,int outSize);
extern int enc_get_utf8_size(const unsigned char pInput);

#ifdef __cplusplus
}
#endif
#endif // UTF

四,主函数

#include <stdio.h>
#include "framebuffer.h"


unsigned char pu[24*24/8] = {
/*--  文字:  普  --*/
/*--  仿宋18;  此字体下对应的点阵为:宽x高=24x24   --*/
0x00,0x00,0x00,0x00,0x03,0x00,0x01,0xC3,0x80,0x00,0xE3,0x00,0x00,0x77,0x00,0x00,
0xFF,0xF0,0x0F,0xFF,0xC0,0x00,0x7E,0xE0,0x06,0x7E,0xE0,0x03,0x7F,0xC0,0x03,0xFF,
0x80,0x01,0x7F,0xFC,0x7F,0xFF,0xE0,0x3E,0x00,0x80,0x03,0xFF,0xC0,0x03,0xFF,0xC0,
0x03,0x81,0xC0,0x03,0xFF,0xC0,0x01,0xFF,0x80,0x01,0x81,0x80,0x01,0xFF,0x80,0x03,
0xFF,0x80,0x01,0x81,0x80,0x00,0x00,0x00
};

int main(int argc, const char *argv[])
{
	//初始化utf8字库
	UTF8_INFO utf8_info;
    bzero(&utf8_info, sizeof(UTF8_INFO));
    strcpy(utf8_info.path, ZIKUK_FILE_BIG);
    utf8_info.width = 32;
    utf8_info.height = 32;
    init_utf8(&utf8_info);

	int fb_fd = init_fb("/dev/fb0");
	if (-1 == fb_fd)
	{
		return -1;
	}


	draw_point(400, 300, 0x00ff0000);
	
	draw_clear(0x00000000);

//	draw_rectangle(100,100, 100,200, 0x00ff0000);

	//draw_x_line(200, 200, 300, 300, 0x0000ffff);
	
	//draw_x_line(200, 200, 300, 100, 0x0000ffff);
	
//	draw_x_line(300, 300, 100, 100, 0x00ff00ff);

	draw_circle(200,200, 200, 0x00ffffff);


	sleep(2);

	draw_bmp(0, 0, "./res/1.bmp", 800, 600);

//	draw_word(100, 100, pu, 24/8, 24, 0x00ff0000);

	draw_utf8_str(&utf8_info, 100, 100, "水产品养殖远程监控系统", 0x00ff0000, 0x00ffffff);


	uninit_fb(fb_fd);

	return 0;
}


http://www.kler.cn/news/306961.html

相关文章:

  • [数据集][目标检测]智慧交通铁路人员危险行为躺站坐检测数据集VOC+YOLO格式3766张4类别
  • MySQL 中的 GROUP BY 和 HAVING 子句:特性、用法与注意事项
  • 包含 Python 与 Jupyter的Anaconda的下载安装
  • c#将int转为中文数字
  • 为什么H.266未能普及?EasyCVR视频编码技术如何填补市场空白
  • CentOS入门宝典:从零到一构建你的Linux服务器帝国
  • Linux基础开发环境(git的使用)
  • 经验笔记:Node.js 中的 process.nextTick
  • 解决Linux服务器 shell 上下左右键出现乱码^[[D ^[[C ^[[A ^[[B
  • 在linux下,找到指定命令对应的路径信息
  • echarts 5.3.2 折线图 tooltip设置trigger为axis无效
  • 面向对象程序设计之继承(C++)
  • OpenCV-上下采样
  • Pytorch是如何做显存管理的
  • qmt量化交易策略小白学习笔记第64期【qmt编程之获取获取期权全推数据--code_list全推tick数据】
  • 鸿蒙媒体开发系列01——资源分类访问
  • 移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——13.mapset
  • 【springboot】整合spring security 和 JWT
  • Vue接入高德地图并实现基本的路线规划功能
  • Redis基础,常用操作命令,主从复制,一主两从,事务数据库操作
  • day01 - Java基础语法
  • [Golang] Sync
  • HarmonyOS开发之全局状态管理
  • 天融信把桌面explorer.exe删了,导致开机之后无windows桌面,只能看到鼠标解决方法
  • C++基础面试题 | 什么是C++中的虚继承?
  • LabVIEW机动车动态制动性能校准系统
  • spring项目中如何通过redis的setnx实现互斥锁解决缓存缓存击穿问题
  • [项目][WebServer][HttpServer]详细讲解
  • 一码空传临时网盘PHP源码,支持提取码功能
  • 数据中台进化为数据飞轮的必要