5.數位相框-額外項目電子書總結

来源:https://www.cnblogs.com/lifexy/archive/2018/03/15/8574766.html
-Advertisement-
Play Games

在LCD顯示任意編碼的文本文件,類似電子書 怎樣在LCD上顯示文件: 需要哪幾個文件? 1.頂部文件 通過main.c分析命令行的操作,然後初始化各個管理文件下的結構體,比如DisplayInit(); 然後進入draw.c,在draw.c里按順序調用3個管理文件,並控制顯示. 2. encodin ...


在LCD顯示任意編碼的文本文件,類似電子書

怎樣在LCD上顯示文件:

 

需要哪幾個文件?

1.頂部文件

通過main.c分析命令行的操作,然後初始化各個管理文件下的結構體,比如DisplayInit();

然後進入draw.c,在draw.c里按順序調用3個管理文件,並控制顯示.

 

 

2. encoding_manager.c管理文件

管理4個編碼子文件:utf-8.c  utf-16be.c  utf-16le.c  ascii.c

比如utf-8.c:判斷某個文件是否以0xEF, 0xBB, 0xBF開頭,若是,則接下來通過utf-8規律,來轉換位元組編碼.

 

 

3. font_manager.c管理文件

管理3個字體子文件: ascii.c(英文點陣)  gbk.c(中文點陣)   freetype.c(矢量字體)

用來將獲取的字元編碼轉換為點陣信息.

 

4. disp_manager.c管理文件

管理2個顯示子文件:    fb.c(LCD顯示)    crt.c(串口顯示)

主要負責將點陣信息發送到顯存或串口上.

 

 

在3個管理.h頭文件里,聲明3個不同的結構體

T_DispOpr :顯示操作結構體

T_FontOpr:字體操作結構體

T_EncodingOpr:編碼操作結構體     

5.首先來寫顯示部分

fb.c需要用到fb初始化函數,以及顯示像素函數,當我們換頁時,還需要一個清屏函數,所以有個3個函數.

在disp_manager.h里的T_DispOpr結構體,聲明如下:

typedef struct DispOpr {
       char *name;
       int iXres;                      //x像素個數
       int iYres;                       //y像素個數
       int iBpp;                       //每個像素多少位
       int (*DeviceInit)(void);    //該函數對於fb.c,是用來打開/dev/fb0,獲取var和fix,然後mmap
       int (*ShowPixel)(int iPenX, int iPenY, unsigned int dwColor); //顯示一個像素點
       int (*CleanScreen)(void);                     //清屏
       struct DispOpr *ptNext;         //指向下一個註冊的T_DispOpr結構體
}T_DispOpr, *PT_DispOpr;

 

在disp_manager.c里

定義一個空鏈表: static PT_DispOpr g_ptDispOprHead = NULL;

寫一個RegisterDispOpr()函數, 子文件通過調用該函數來註冊到鏈表g_ptDispOprHead里

 

在disp_manager.c里

定義一個 DisplayInit()函數,用來被main.c初始化時調用。

 

在fb.c里

在fb.c里定義g_tFBOpr:

static T_DispOpr g_tFBOpr = {
       .name        = "fb",
       .DeviceInit  = FBDeviceInit,    //該函數打開/dev/fb0,然後獲取fix和var成員,來mmap()
       .ShowPixel   = FBShowPixel,     //該函數根據x,y,color這3個函數參數,來顯示一個像素點
       .CleanScreen = FBCleanScreen,   //該函數,通過memset來將顯存清0
};

並定義一個FBInit ()函數,將結構體g_tFBOpr註冊到g_ptDispOprHead鏈表裡:

int FBInit(void)
{
       return RegisterDispOpr(&g_tFBOpr);
}

由於FBInit()被disp_manager.c文件的DisplayInit()調用,所以不能寫static了.

 

6.寫字體部分

和顯示部分思路一樣,在fonts_manager.h里的聲明瞭兩個結構體,如下所示:

typedef struct FontBitMap {
       int iXLeft;         //文字最左邊X坐標
       int iYTop;         //文字最頂部Y坐標
       int iXMax;        //文字的一行像素有多大
       int iYMax;       //文字的一列像素有多大
       int iBpp;       //像素格式
       int iPitch;   /* 對於單色點陣圖, 兩行象素之間的跨度,比如8*16,則跨度是8(文字的一行像素有8位) */
       int iCurOriginX;    //當前原點x坐標
       int iCurOriginY;    //當前原點y坐標
       int iNextOriginX;   //下個文字的原點x坐標
       int iNextOriginY;   //下個文字的原點y坐標
       unsigned char *pucBuffer;   //存放文字的像素數據
}T_FontBitMap, *PT_FontBitMap;
typedef struct FontOpr {
       char *name;
       int (*FontInit)(char *pcFontFile, unsigned int dwFontSize);   //初始化字體文件
       int (*GetFontBitmap)(unsigned int dwCode, PT_FontBitMap ptFontBitMap);  //根據dwCode編碼獲取字體點陣圖,並將信息(坐標,數據,格式等)存到ptFontBitMap里
       struct FontOpr *ptNext;
}T_FontOpr, *PT_FontOpr;

 

在fonts_manager.c里

定義一個空鏈表:static PT_FontOpr g_ptFontOprHead = NULL;

寫一個RegisterFontOpr()函數, 子文件通過調用該函數來註冊到鏈表g_ptFontOprHead里

寫一個GetFontOpr()函數,用來獲取字體文件的name 

寫一個FontsInit ()函數,用來被main.c初始化時調用:

int FontsInit(void)
{
       int iError;
       iError = ASCIIInit();              //調用./fonts/ascii.c里的ASCIIInit()函數
       if (iError)
       {
              DBG_PRINTF("ASCIIInit error!\n");
              return -1;
       }

       iError = GBKInit();   //調用./fonts/gbk.c里的GBKInit ()函數
       if (iError)
       {
              DBG_PRINTF("GBKInit error!\n");
              return -1;
       }

       iError = FreeTypeInit();  //調用./fonts/freetype.c里的FreeTypeInit ()函數
       if (iError)
       {
              DBG_PRINTF("FreeTypeInit error!\n");
              return -1;
       }
       return 0;
}

寫一個GetFontOpr()函數,該函數被編碼文件調用,來使編碼文件與字體文件關聯起來,比如通過utf-8編碼找到對應的freetype字體.

 

寫字體文件,以freetype.c(矢量字體)為例

首先定義一個T_FontOpr結構體.

定義FreeTypeFontInit成員函數,初始化freetype庫,設置字體大小等

定義GetFontBitmap成員函數,FT_Load_Char()轉換點陣圖,保存在PT_FontBitMap里

具體內容如下:

#include <config.h>
#include <fonts_manager.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

static int FreeTypeFontInit(char *pcFontFile, unsigned int dwFontSize);
static int FreeTypeGetFontBitmap(unsigned int dwCode, PT_FontBitMap ptFontBitMap);

static T_FontOpr g_tFreeTypeFontOpr = {
       .name          = "freetype",
       .FontInit      = FreeTypeFontInit,
       .GetFontBitmap = FreeTypeGetFontBitmap,
};

static FT_Library g_tLibrary;
static FT_Face g_tFace;
static FT_GlyphSlot g_tSlot;

static int FreeTypeFontInit(char *pcFontFile, unsigned int dwFontSize)
{
       int iError;

       /* 顯示矢量字體 */
       iError = FT_Init_FreeType(&g_tLibrary );                       /* initialize library */
       /* error handling omitted */
       if (iError)
       {
              DBG_PRINTF("FT_Init_FreeType failed\n");
              return -1;
       }

       iError = FT_New_Face(g_tLibrary, pcFontFile, 0, &g_tFace); /* create face object */
       /* error handling omitted */
       if (iError)
       {
              DBG_PRINTF("FT_Init_FreeType failed\n");          
              return -1;
       }
       g_tSlot = g_tFace->glyph;
       iError = FT_Set_Pixel_Sizes(g_tFace, dwFontSize, 0);
       if (iError)
       {
              DBG_PRINTF("FT_Set_Pixel_Sizes failed : %d\n", dwFontSize);
              return -1;
       }
       return 0;
}

static int FreeTypeGetFontBitmap(unsigned int dwCode, PT_FontBitMap ptFontBitMap)
{
       int iError;
       int iPenX = ptFontBitMap->iCurOriginX;     //初始值為:0  dwFontSize
       int iPenY = ptFontBitMap->iCurOriginY;
#if 0
       FT_Vector tPen;
       tPen.x = 0;
       tPen.y = 0;

       /* set transformation */
       FT_Set_Transform(g_tFace, 0, &tPen);
#endif

       /* load glyph image into the slot (erase previous one) */
       //iError = FT_Load_Char(g_tFace, dwCode, FT_LOAD_RENDER );
       iError = FT_Load_Char(g_tFace, dwCode, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
       if (iError)
       {
              DBG_PRINTF("FT_Load_Char error for code : 0x%x\n", dwCode);
              return -1;
       }

       //DBG_PRINTF("iPenX = %d, iPenY = %d, bitmap_left = %d, bitmap_top = %d, width = %d, rows = %d\n", iPenX, iPenY, g_tSlot->bitmap_left, g_tSlot->bitmap_top, g_tSlot->bitmap.width, g_tSlot->bitmap.rows);
       /*笛卡爾坐標的左上角是(bitmap_left,bitmap_top),
          對應LCD的左上角是(Y+bitmap_left,Y-bitmap_top)*/
       ptFontBitMap->iXLeft    = iPenX + g_tSlot->bitmap_left;
       ptFontBitMap->iYTop     = iPenY - g_tSlot->bitmap_top;
       ptFontBitMap->iXMax     = ptFontBitMap->iXLeft + g_tSlot->bitmap.width;
       ptFontBitMap->iYMax     = ptFontBitMap->iYTop  + g_tSlot->bitmap.rows;
       ptFontBitMap->iBpp      = 1;
       ptFontBitMap->iPitch    = g_tSlot->bitmap.pitch;
       ptFontBitMap->pucBuffer = g_tSlot->bitmap.buffer;
       ptFontBitMap->iNextOriginX = iPenX + g_tSlot->advance.x / 64;
       ptFontBitMap->iNextOriginY = iPenY;
       //DBG_PRINTF("iXLeft = %d, iYTop = %d, iXMax = %d, iYMax = %d, iNextOriginX = %d, iNextOriginY = %d\n", ptFontBitMap->iXLeft, ptFontBitMap->iYTop, ptFontBitMap->iXMax, ptFontBitMap->iYMax, ptFontBitMap->iNextOriginX, ptFontBitMap->iNextOriginY);
       return 0;
}

int FreeTypeInit(void)
{
       return RegisterFontOpr(&g_tFreeTypeFontOpr);
}

 

7.寫編碼部分

在encoding_manager.h里的T_EncondingOpr結構體,聲明如下:

typedef struct EncodingOpr {
       char *name;
       int iHeadLen;                                       //文件以多少位元組開頭
       PT_FontOpr aptFontOprSupported[4]; //指針數組,用來存放支持該編碼的字體結構體,以後就通過這個來顯示文字
       int (*isSupport)(unsigned char *pucBufHead);  //該函數判斷要顯示的文件是否支持XX格式
       int (*GetCodeFrmBuf)(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode);             
//將文件里的位元組轉為編碼,存到*pdwCode里 struct EncodingOpr *ptNext; //鏈表 }T_EncodingOpr, *PT_EncodingOpr;

 

在encoding_manager.c里

定義一個空鏈表: static PT_EncodingOpr g_ptEncodingOprHead= NULL;

寫一個RegisterEncodingOpr()函數, 子文件通過調用該函數來註冊到鏈表g_ptEncodingOprHead里

寫一個SelectEncodingOprForFile()函數,,通過鏈表來找isSupport成員函數,判斷要顯示的文字支持哪種格式

寫一個EncodingInit()函數,調用每個編碼文件的init()函數,裡面會初始化編碼T_EncodingOpr結構體,並添加編碼所支持的文字結構體。

寫編碼文件,以utf-8.c為例

比如:

對於ansi.c(編碼文件),其實就是GBK編碼, ascii占1位元組,使用ascii點陣庫,漢字占2位元組,使用HZK16漢字型檔.

對於utf-8.c(編碼文件), ascii只占1位元組, 使用ascii點陣庫,而漢字占2~4位元組,由於freetype字型檔預設支持的是utf-16格式,所以需要utf-8轉換為utf-16後,再使用freetype字型檔,轉換如下圖所示:

 

8.寫draw.c

8.1首先定義一個T_PageDesc結構體

用來控制分頁換行用,需要用到雙向鏈表

typedef struct PageDesc {

       int iPage;                                                  //當前頁數

       unsigned char *pucLcdFirstPosAtFile;            //在LCD上第一個字元位置位於在文件哪個位置

       unsigned char *pucLcdNextPageFirstPosAtFile; //下一頁的LCD上第一個字元位置位於文件哪位置

       struct PageDesc *ptPrePage;     //上一頁鏈表,指向上一個T_PageDesc結構體

       struct PageDesc *ptNextPage;     //下一頁鏈表,指向下一個T_PageDesc結構體

} T_PageDesc, *PT_PageDesc;

8.2 寫一個OpenTextFile()函數

用來打開文本文件,然後mmap(),並判斷支持哪種編碼,並獲取文件第一個字元位置g_pucLcdFirstPosAtFile標誌量,該值被顯示下一頁函數使用

代碼如下:

static int g_iFdTextFile;                       //文件描述符
static unsigned char *g_pucTextFileMem;         //記憶體映射基地址
static unsigned char *g_pucTextFileMemEnd;      //記憶體映射結尾地址
static PT_EncodingOpr g_ptEncodingOprForFile;   //用來指向該文件支持的編碼EncodingOpr結構體

static unsigned char *g_pucLcdFirstPosAtFile;            //第一個字元位於文件的位置
int OpenTextFile(char *pcFileName)
{
      g_iFdTextFile = open(pcFileName, O_RDONLY);
      ... ...
       if(fstat(g_iFdTextFile, &tStat))
       {
              DBG_PRINTF("can't get fstat\n");
              return -1;
       }
g_pucTextFileMem = (unsigned char *)mmap(NULL , tStat.st_size, PROT_READ, MAP_SHARED, g_iFdTextFile, 0);
g_pucTextFileMemEnd = g_pucTextFileMem + tStat.st_size;   

       g_ptEncodingOprForFile = SelectEncodingOprForFile(g_pucTextFileMem); //獲取支持的編碼格式
       if (g_ptEncodingOprForFile)
       {
              g_pucLcdFirstPosAtFile = g_pucTextFileMem + g_ptEncodingOprForFile->iHeadLen; //去掉文件編碼首碼的開頭位置
              return 0;
       }
       else
       {
              return -1;
       }
}

 

8.3 寫一個ShowOnePage ()顯示一頁函數

首先設置原點xy為(0,fontsize),通過編碼結構體的成員函數獲取編碼,判斷編碼是否為\r \n \t,然後通過字體結構體的成員函數將編碼轉為點陣圖,然後判斷是否換行,滿頁,最後顯示

8.4 寫一個SetTextDetail()函數

通過支持的編碼,來設置HZK,freetype,ascii字體文件,以及文字大小,供給main.c調用

9.寫main.c

main.c主要用來通過main.c分析命令行的操作,然後初始化各個管理文件下的結構體,比如DisplayInit();

命令行:

./show_file   [-l] [-s Size] [-d Dispshow] [-f freetype_font_file] [-h HZK] <text_file>

//-l  :列出選項

//-s  :設置文字大小

//-d :選擇顯示到哪裡,是fb還是crt

//-f  :指定矢量文字文件位置

//-h  :指定漢字型檔文件位置

// text_file:指定要顯示哪個文件 

main.c流程:

1.通過getopt(argc,argv, "ls:f:h:d:");來解析命令行,獲取每個選項後的參數

2.然後調用管理文件的初始化函數,去初始化顯示文件fb.c,字體文件freetype.c,gbk.c等,以及添加鏈表

比如:       iError = DisplayInit();      //最終調用FBInit();->RegisterDispOpr(&g_tFBOpr);

3.因為optind等於<text_file>位置,所以通過optind打開<text_file>文件:

strncpy(acTextFile, argv[optind], 128);
       acTextFile[127] = '\0';
iError = OpenTextFile(acTextFile);        //裡面進行mmap(),並獲取該文件所支持的編碼結構體

4.設置文本細節(HZK庫,freetype庫,文字大小)

iError = SetTextDetail(acHzkFile, acFreetypeFile, dwFontSize);   //該函數位於draw.c

5.調用SelectAndInitDisplay()函數,通過[-d Dispshow]來從g_ptDispOprHead顯示鏈表裡,找到name相同的結構體,並放入g_ptDispOpr結構體,然後執行g_ptDispOpr->DeviceInit(); 來初始化LCD

iError = SelectAndInitDisplay(acDisplay);

6.調用ShowNextPage()顯示第一頁

7.然後進入while(1)里,通過getchar()來獲取命令行參數.

輸入n則調用ShowNextPage(),顯示下一頁

輸入u則調用ShowNextPage(),顯示上一頁

輸入q退出

 

10.在PC上顯示文本文件

輸入ctrl+alt+tab+F1~F6  進入tty1~6字元終端界面,如下圖所示,在tty1和tty2里登錄book用戶:

 

再次輸入ctrl+alt+tab+F7  則退出字元終端界面,進入圖形GUI界面

然後輸入ps -A,可以發現tty1和tty2顯示login登錄狀態,而其它tty顯示getty待機狀態:

 

接下來便通過svaglib庫,使在字元終端界面上顯示圖形,這樣就能顯示文本了

10.1安裝svgalib:

搜索ubuntu svgalib,找到下載地址https://launchpad.net/ubuntu/+source/svgalib/1:1.4.3-30:

svgalib_1.4.3.orig.tar.gz               //源碼

svgalib_1.4.3-30.debian.tar.gz        // 在其debian/patches目錄下有很多補丁文件

svgalib_1.4.3-30.dsc

打補丁:

tar xzf svgalib_1.4.3.orig.tar.gz

tar xzf svgalib_1.4.3-30.debian.tar.gz

cd svgalib-1.4.3.orig/

for file in ../debian/patches/*.patch; do patch -p1 < $file; done     

編譯安裝:

sudo make install   // 編譯出錯,需要安裝libx86

 

10.2 安裝libx86:

搜索ubuntu libx86,找到下載地址http://packages.ubuntu.com/lucid/libx86-1:

tar xzf libx86_1.1+ds1.orig.tar.gz 

gunzip libx86_1.1+ds1-6.diff.gz

cd libx86-1.1/

patch -p1 < ../libx86_1.1+ds1-6.diff 

make     // 出錯

修改lrmi.c,添加巨集, 參考561491.patch,添加如下代碼:

=======================================

#if defined(__linux__) && !defined(TF_MASK)

        #define TF_MASK X86_EFLAGS_TF

        #define IF_MASK X86_EFLAGS_IF

        #define VIF_MASK X86_EFLAGS_VIF

        #define IOPL_MASK X86_EFLAGS_IOPL

#endif

=======================================

make
sudo make install              //安裝成功

 

10.3 應用程式示例

參考:http://www.svgalib.org/jay/beginners_guide/beginners_guide.html

svgatext.c代碼如下:

#include "stdlib.h"
#include "vga.h"
#include "vgagl.h"

int main(void)
{
    int x, y;

    vga_init();

    vga_setmode(G320x200x256);     //解析度為320x200,24位解析度

    gl_setpalettecolor(4, 0xE7>>2, 0xDB>>2, 0xB5>>2);
              //將設置調色板第4格設為0xE7DBB5顏色 (泛黃色)

    vga_setcolor(4);           //使用調色板第4格的顏色

    for (x = 0; x < 320; x++)
        for (y = 0; y < 200; y++)
            vga_drawpixel(x, y);         //將整個屏設為調色板第4格的顏色

    sleep(5);                                
    vga_setmode(TEXT);                //返回到字元終端界面上
    return EXIT_SUCCESS;
}

編譯svgatext.c

gcc  -o svgatext  svgatext.c   -lvga  -lvgal

 

10.4 參考svgatext.c,在電子書項目里的./fonts目錄下寫crt.c顯示文件

 

11.自己寫電子書

思路如下:

字體文件只要一個freetype.c,用來顯示矢量字體

編碼文件只需要: utf-16be.c,utf-16le.c, utf-8,iconv_encoding.c

顯示文件就只要一個fb.c文件.

最後寫一個draw.c、main.c文件

iconv_encoding.c作用:

因為freetype只支持unicode,所以先判斷文本文件是否是GBK編碼,若是,則通過iconv_encoding.c,將整個文本文件轉換成utf-8編碼.

 

過程:

在arm板上使用iconv()函數時,發現調用
iconv_open("utf-8", " GBK")失敗,錯誤信息為“Invalid argument”.

後來才發現是libiconv庫和arm板上的C庫版本不同,參考: http://blog.csdn.net/love_life2011/article/details/7086910

進入http://ftp.gnu.org/gnu/libiconv/libiconv-1.14.tar.gz下載libiconv庫,重新交叉編譯

解壓進入libconv目錄:

$./configure --prefix=$PWD/out --host=arm-linux
$make
$make install

然後進入out子目錄,將編譯好的out/lib/目錄下的preloadable_libiconv.so拷貝到arm板的lib目錄下

再進入arm板,更新環境變數:

$ export LD_PRELOAD=/lib/preloadable_libiconv.so

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 小伙伴們, 大家好,我是Rector。 最近Rector忙於換工作,沒有太多時間來更新我們的ASP.NET MVC 5系列文章 [\[一步一步創建ASP.NET MVC5程式Repository+Autofac+Automapper+SqlSugar\]][4],直到現在才擠些時間趕緊更新一篇 ...
  • 刪除網站下的PrecompiledApp.config文件即可。 ...
  • 先決條件 本教程假定RabbitMQ已經安裝,並運行在 標準埠(5672)。如果你使用不同的主機、埠或證書,則需要調整連接設置。 從哪裡獲得幫助 如果您在閱讀本教程時遇到困難,可以通過郵件列表 "聯繫我們" 。 1.介紹 RabbitMQ是一個消息代理:它接受並轉發消息。您可以把它想象成一個郵局 ...
  • 在機房運行的四台伺服器中均出現了藍屏dmp文件,經過整理髮現CDMS主備伺服器最近(2018年1月開始)藍屏的dmp很多。經過自己的學習分析發現不足以找到先關的原因和處理方法,希望得到大牛們的幫助。以儘快解決此藍屏問題。 一、CDMS的兩台伺服器是現在網路運行中十分重要的伺服器,感謝廣大博友大牛們的 ...
  • 答案是我在這個網站上找到的: 執行 ~~~~~ xset dpms force off ~~~~~ 命令就可以解決掉這個問題。 再次運行 svgatest 程式,得到了預期的結果,perfect! ...
  • TFTP ...
  • 安裝時參考了https://www.jianshu.com/p/69a10d0a24b9 但由於版本不同,這裡主要記錄安裝包路徑, 一些註意事項,和基本過程。 CUDA8.0下載地址:https://developer.nvidia.com/cuda-80-ga2-download-archive ...
  • FTP相關介紹 FTP FTP雙通道協議:數據和命令連接 FTP的傳輸方式 FTP支持的模式 FTP的相關應用軟體程式 FTP用戶身份 FTP的狀態碼 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...