0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

用于管理文件方法和數(shù)據(jù)結(jié)構(gòu)案例分析

UtFs_Zlgmcu7890 ? 來(lái)源:未知 ? 作者:劉勇 ? 2018-08-03 09:28 ? 次閱讀

本文導(dǎo)讀

文件系統(tǒng)是在存儲(chǔ)設(shè)備中(SD Card、NAND Flash…)組織文件的方法和數(shù)據(jù)結(jié)構(gòu),用于管理文件。AWorks定義了文件系統(tǒng)的通用接口,例如,打開(kāi)、讀/寫、關(guān)閉文件等等。文件系統(tǒng)的具體實(shí)現(xiàn)可以自由選擇,例如,F(xiàn)AT、UFFS、YAFFS2 等等。

本文為《面向AWorks框架和接口編程》第三部分軟件篇——第11章文件系統(tǒng)——第1~5小節(jié):文件系統(tǒng)簡(jiǎn)介、設(shè)備掛載管理、文件基本操作、目錄基本操作和微型數(shù)據(jù)庫(kù)。

本章導(dǎo)讀

文件系統(tǒng)是用于管理文件的方法和數(shù)據(jù)結(jié)構(gòu),文件和文件系統(tǒng)相關(guān)的數(shù)據(jù)存儲(chǔ)在實(shí)際的物理介質(zhì)中,例如,NAND FLASH,Nor FLASH或SD Card等。AWorks定義了文件系統(tǒng)的通用接口,無(wú)論底層使用何種文件系統(tǒng),比如常見(jiàn)的FAT16/32、UFFS或YAFFS2等,均可使用同一套接口進(jìn)行文件相關(guān)的操作。

11.1 文件系統(tǒng)簡(jiǎn)介

在文件系統(tǒng)中,存儲(chǔ)數(shù)據(jù)的基本單位是文件,即數(shù)據(jù)是按照一個(gè)一個(gè)文件的方式進(jìn)行組織的。當(dāng)文件較多時(shí),將導(dǎo)致文件繁多、不易分類、重名等問(wèn)題,為此,在文件的基礎(chǔ)上,提出了目錄的概念,相當(dāng)于Windows系統(tǒng)中的文件夾,一個(gè)目錄中,可以包含多個(gè)文件。特別地,一個(gè)目錄中,除包含文件外,還可以包含子目錄,子目錄可以繼續(xù)包含子目錄。最上層的目錄被稱為根目錄,示意圖詳見(jiàn)圖11.1。

圖11.1 目錄結(jié)構(gòu)示意圖

圖中的目錄名和文件名僅用作示例,與實(shí)際系統(tǒng)的目錄樹(shù)結(jié)構(gòu)并不存在任何關(guān)聯(lián)。在AWorks中,根目錄使用斜杠(即:"/")表示,應(yīng)注意與反斜杠(即:"")進(jìn)行區(qū)分,不可混用。存于根目錄中的文件,其完整路徑直接使用“斜杠 + 文件名”的形式表示,如圖11.1中的test1.txt文件,其路徑為"/test1.txt",若一個(gè)文件所在目錄不是根目錄時(shí),則多個(gè)目錄之間要使用斜杠(即:"/")分隔,比如,test5.txt文件對(duì)應(yīng)的完整路徑應(yīng)表示為"/usr/base/test5.txt"。

AWorks中分隔符使用"/",這與UNIX/Linux的風(fēng)格是完全相同的,而與Windows則不相同,Windows中使用反斜杠""作為分隔符。

11.2 設(shè)備掛載管理

在圖11.1中,為用戶展示了一個(gè)目錄樹(shù)結(jié)構(gòu),圖中的每個(gè)文件都存放在相應(yīng)的目錄中,目錄是一個(gè)虛擬的邏輯概念,便于用戶按照邏輯路徑訪問(wèn)各個(gè)文件。而實(shí)質(zhì)上,文件數(shù)據(jù)是存放在物理存儲(chǔ)介質(zhì)中的,例如,NAND FLASH,Nor FLASH或SD Card等。為此,就需要在系統(tǒng)中將目錄與某一物理存儲(chǔ)介質(zhì)相關(guān)聯(lián),用戶存放在某一目錄下的文件都自動(dòng)保存到對(duì)應(yīng)的物理存儲(chǔ)介質(zhì)中,這種關(guān)聯(lián)操作可以通過(guò)“設(shè)備掛載”來(lái)實(shí)現(xiàn)?!霸O(shè)備掛載”用于將物理存儲(chǔ)介質(zhì)掛載到某一目錄,使該物理存儲(chǔ)介質(zhì)與該目錄對(duì)應(yīng),后續(xù)所有在該目錄下的文件(或子目錄)實(shí)際上都存儲(chǔ)到了與之對(duì)應(yīng)的存儲(chǔ)介質(zhì)中。

在一個(gè)系統(tǒng)中,往往存在多種存儲(chǔ)介質(zhì),例如,NAND FLASH,SD Card或外接的U盤等,無(wú)論存在多少存儲(chǔ)介質(zhì),對(duì)于用戶來(lái)講,其都是使用圖11.1所示的一個(gè)目錄樹(shù)來(lái)進(jìn)行文件的管理,根目錄只會(huì)有一個(gè),不會(huì)因?yàn)榫哂卸鄠€(gè)存儲(chǔ)介質(zhì)而產(chǎn)生多個(gè)根目錄。

實(shí)際應(yīng)用中,為了方便管理,可以進(jìn)行更細(xì)的劃分,將一個(gè)硬件存儲(chǔ)介質(zhì)分成多個(gè)區(qū),此時(shí),每個(gè)分區(qū)可以看作一個(gè)獨(dú)立的存儲(chǔ)介質(zhì),掛載到某一目錄。例如,一個(gè)SD卡的容量是2G,可以分成大小不同的4個(gè)分區(qū),例如,SD_S0(1G)、SD_S1(512M)、SD_S2(256M)、SD_S3(256M)。此時(shí),4個(gè)分區(qū)可以當(dāng)作4個(gè)獨(dú)立的存儲(chǔ)介質(zhì),分別掛載到不同的目錄。

對(duì)于一個(gè)物理存儲(chǔ)介質(zhì),需要使用某一具體的文件系統(tǒng)對(duì)其中的文件數(shù)據(jù)進(jìn)行管理,比如常見(jiàn)的FAT16/32、UFFS或YAFFS2等,它們各有優(yōu)缺點(diǎn),針對(duì)特定的存儲(chǔ)介質(zhì),可以選擇合適的文件系統(tǒng)。如FAT16/32常用于U盤、SD卡中,UFFS和YAFFS2常用于NAND FLASH中。同一系統(tǒng)中,不同的物理存儲(chǔ)介質(zhì)可以使用不同的文件系統(tǒng)。一般來(lái)講,初次使用某一硬件存儲(chǔ)介質(zhì)時(shí),需要進(jìn)行格式化操作,指定使用的文件系統(tǒng),存儲(chǔ)一些與文件系統(tǒng)相關(guān)的初始數(shù)據(jù)。格式化后,才可將該設(shè)備掛載到目錄樹(shù)中。通常情況下,存儲(chǔ)設(shè)備掉電不會(huì)丟失數(shù)據(jù),因此,格式化操作僅需執(zhí)行一次,不需要每次上電都執(zhí)行。

AWorks提供了抽象的文件系統(tǒng)接口和框架,即使系統(tǒng)中不同存儲(chǔ)介質(zhì)使用了不同的文件系統(tǒng),對(duì)于用戶來(lái)講,仍然可以使用相同的接口進(jìn)行文件相關(guān)的操作。

AWorks提供了管理硬件存儲(chǔ)設(shè)備的接口,相關(guān)接口的函數(shù)原型詳見(jiàn)表11.1。

表11.1 存儲(chǔ)設(shè)備管理相關(guān)接口(fs/aw_mount.h)

1. 格式化存儲(chǔ)設(shè)備

格式化存儲(chǔ)設(shè)備,以指定使用的文件系統(tǒng),并存儲(chǔ)一些與文件系統(tǒng)相關(guān)的初始數(shù)據(jù)。其函數(shù)原型為:

其中,dev_name為存儲(chǔ)設(shè)備的名字,fs_name為使用的文件系統(tǒng)的名字,fmt_arg為格式化相關(guān)的附加信息。返回值為標(biāo)準(zhǔn)的錯(cuò)誤號(hào),返回AW_OK時(shí),表示格式化成功,否則,表示格式化失敗,可能是由于硬件設(shè)備不存在或文件系統(tǒng)不支持造成的。

存儲(chǔ)設(shè)備的名字與具體的物理存儲(chǔ)介質(zhì)相關(guān)。例如,常見(jiàn)的SD卡設(shè)備,其對(duì)應(yīng)的設(shè)備名為:/dev/sdx,其中,x為SD卡所處的SDIO總線序號(hào),比如:0、1、2等。為便于敘述,這里將SD卡和TF卡統(tǒng)稱為SD卡存儲(chǔ)設(shè)備,SD卡就是常見(jiàn)的大卡,常用于相機(jī)中,如圖11.2(a)所示。

TF卡又稱Micro SD卡,體積比SD卡小,很多手機(jī)都配備了TF卡接口,用于擴(kuò)展存儲(chǔ)容量,如圖11.2(b)所示。除了體積大小的區(qū)別外,SD卡在左側(cè)還有一個(gè)LOCK開(kāi)關(guān),用于鎖定SD卡,從硬件上開(kāi)啟寫保護(hù),避免數(shù)據(jù)損壞。

圖11.2 SD卡與TF卡

在i.MX28x硬件平臺(tái)中,僅在SDIO0總線上設(shè)置了一個(gè)TF卡卡槽,因而僅能插入一張TF卡,不能插入SD卡。若正確插入了TF卡,則該TF卡對(duì)應(yīng)的設(shè)備名為"/dev/sd0"。為便于驗(yàn)證后續(xù)程序,讀者可以準(zhǔn)備一張TF卡。

除使用TF卡外,還可以使用U盤進(jìn)行測(cè)試,在i.MX28x平臺(tái)中設(shè)置了USB接口,默認(rèn)情況下,USB HOST1接口用于外接USB設(shè)備,USB HOST0接口用于外接USB主機(jī),將自身模擬為一個(gè)USB設(shè)備??梢酝ㄟ^(guò)USB HOST1接口外接U盤,U盤在系統(tǒng)中對(duì)應(yīng)的存儲(chǔ)設(shè)備名為"/dev/ms0-ud0"。

在編程上,不同的物理存儲(chǔ)設(shè)備僅僅是設(shè)備名發(fā)生了變化,沒(méi)有其它任何區(qū)別,U盤和TF卡的具體細(xì)節(jié)差異用戶無(wú)需關(guān)心。為便于敘述,后文統(tǒng)一使用TF卡存儲(chǔ)設(shè)備進(jìn)行舉例說(shuō)明,若讀者使用的是U盤,僅需將范例程序中出現(xiàn)的TF卡設(shè)備名修改為"/dev/ms0-ud0"。

fs_name為文件系統(tǒng)的名字,比如:"vfat"、"uffs"、"yaffs"等,其代表了此硬件設(shè)備使用的具體文件系統(tǒng)。如使用FAT,則文件系統(tǒng)名為"vfat",其會(huì)自動(dòng)根據(jù)存儲(chǔ)器特性選擇使用合適的FAT文件系統(tǒng):FAT12、FAT16或FAT32。

fmt_arg為格式化相關(guān)的信息,不同文件系統(tǒng)使用的信息可能會(huì)不同,其類型struct aw_fs_format_arg (fs/aw_fs_type.h)定義如下:

對(duì)于FAT文件系統(tǒng), 其管理的一個(gè)存儲(chǔ)設(shè)備或分區(qū)稱之為“卷”(volume),vol_name即為該卷指定一個(gè)卷名,當(dāng)前系統(tǒng)中,卷名僅作標(biāo)識(shí),未用作其它特殊用途,可任意指定一個(gè)合理的名字,比如:"awdisk"。

在FAT文件系統(tǒng)中,存儲(chǔ)設(shè)備是以“分配單元”(allocation unit)為單位進(jìn)行數(shù)據(jù)管理的, unit_size指定了每個(gè)分配單元的大小,分配單元在FAT中又被稱為“簇”(cluster)。

在允許范圍內(nèi),分配單元大小設(shè)置越大,讀寫速度越快,反之則越慢。但是,需要注意的是,分配單元越大,也越有可能造成空間的浪費(fèi),因?yàn)榧幢阋粋€(gè)文件的大小遠(yuǎn)遠(yuǎn)小于分配單元大小,也會(huì)占用一個(gè)完整的分配單元。unit_size必須為硬件存儲(chǔ)設(shè)備扇區(qū)大小(通常固定為512)的整數(shù)倍,且倍數(shù)必須是2的冪,比如:1、2、4、8等,可以將unit_size設(shè)置為4096(512×8),通常情況下,unit_size的有效范圍為:512 ~ 32768。為了便于使用,避免設(shè)置錯(cuò)誤,也可以將該值設(shè)置為0,系統(tǒng)將自動(dòng)根據(jù)存儲(chǔ)器容量選擇一個(gè)合適的值。

FAT文件系統(tǒng)又可以細(xì)分為FAT12、FAT16、FAT32,它們最明顯的區(qū)別就是對(duì)分配單元進(jìn)行尋址的位數(shù)不同,分別為12位、16位、32位。例如,對(duì)于FAT12,其使用12位地址對(duì)分配單元進(jìn)行尋址,因此,理論上最大只能管理212=4096個(gè)分配單元(實(shí)際上,部分地址用作它用,管理的分配單元要略小于該值),若每個(gè)分配單元的大小為32K,則FAT12管理存儲(chǔ)設(shè)備的最大容量為:32K*4096 = 128M。同理,可得到FAT16管理的存儲(chǔ)設(shè)備最大容量為2G,雖然FAT32理論上可以管理的容量達(dá)到T級(jí)別,但實(shí)際中,當(dāng)存儲(chǔ)設(shè)備的容量超過(guò)32G時(shí),不再建議使用FAT,例如,在Windows中,可以使用NTFS等其它文件系統(tǒng)。用戶無(wú)需明確指定使用何種FAT文件系統(tǒng),系統(tǒng)將根據(jù)設(shè)備容量自動(dòng)進(jìn)行選擇。

對(duì)于FAT文件系統(tǒng),flags標(biāo)志未使用,設(shè)置為0即可?;诖?,格式化TF卡的范例程序詳見(jiàn)程序清單11.1。

程序清單11.1 式化范例程序

若未插入TF卡或剛插入TF卡但還未初始化完成,則"/dev/sd0"設(shè)備是不存在的,此時(shí),aw_make_fs()函數(shù)將返回錯(cuò)誤號(hào):-AM_ENODEV。

由于程序在系統(tǒng)啟動(dòng)后將立即執(zhí)行,TF卡可能還未及時(shí)插入或初始化完成。因此,程序中,當(dāng)格式化函數(shù)的返回值為-AM_ENODEV時(shí),繼續(xù)重試。為便于測(cè)試,用戶應(yīng)盡快插入TF卡。格式化操作通常比較費(fèi)時(shí),作者在使用程序清單11.1所示程序格式化一張8G的TF卡時(shí),耗時(shí)約8秒。

格式化僅需執(zhí)行一次,若本次格式化成功,則后續(xù)再進(jìn)行其它操作時(shí),無(wú)需再格式化。特別地,格式化操作會(huì)刪除存儲(chǔ)設(shè)備上所有的原始數(shù)據(jù),應(yīng)謹(jǐn)慎使用。

在程序清單11.1中,若TF卡還未準(zhǔn)備就緒(TF卡未插入或剛插入但還未初始化完成),則不斷重試。為了避免不斷重試,使程序邏輯更加清晰易懂,可以在上電后等待設(shè)備就緒后再執(zhí)行格式化操作,等待設(shè)備就緒的函數(shù)原型為(fs/aw_blk_dev.h):

該接口是用于等待一個(gè)塊設(shè)備準(zhǔn)備就緒,常見(jiàn)的U盤、SD卡、TF卡等都屬于塊設(shè)備(即在物理操作上,數(shù)據(jù)是以塊為單位,比如:512字節(jié),進(jìn)行數(shù)據(jù)的寫入和讀取的,而不是以單個(gè)字節(jié)為單位)。其中p_name為設(shè)備名,例如,"/dev/sd0",timeout用于指定超時(shí)時(shí)間(單位為系統(tǒng)節(jié)拍)。

若設(shè)備已就緒,則直接返回AW_OK;若設(shè)備未就緒,則具體的行為與timeout的值相關(guān)。若timeout的值為AW_WAIT_FOREVER。則程序會(huì)阻塞于此,永久等待,直到設(shè)備準(zhǔn)備就緒;若值為AW_NO_WAIT,則不會(huì)阻塞,立即返回錯(cuò)誤號(hào)-AW_EAGAIN;若值為一個(gè)正整數(shù),則表示最長(zhǎng)的等待時(shí)間(單位為系統(tǒng)節(jié)拍),在超時(shí)時(shí)間內(nèi)設(shè)備就緒則返回AW_OK,否則,返回-AW_ETIME表示超時(shí)。

優(yōu)化程序清單11.1,避免不斷重試,僅當(dāng)設(shè)備就緒后再執(zhí)行格式化操作。范例程序詳見(jiàn)程序清單11.2。

程序清單11.2 格式化范例程序(設(shè)備就緒后再執(zhí)行格式化操作)

2. 掛載設(shè)備

為了使用目錄樹(shù)結(jié)構(gòu)管理文件,并將文件保存到存儲(chǔ)設(shè)備(如TF卡)中,必須將存儲(chǔ)設(shè)備掛載到某一目錄。掛載操作的函數(shù)原型為:

其中,mnt為掛載點(diǎn),其為新建的一個(gè)目錄結(jié)點(diǎn),使用全路徑表示,比如:"/test",其表示在根目錄下創(chuàng)建了一個(gè)名為test的掛載點(diǎn),后續(xù)訪問(wèn)"/test "目錄即表示訪問(wèn)本次掛載的存儲(chǔ)設(shè)備;dev為存儲(chǔ)設(shè)備的名字,如果使用TF卡,則對(duì)應(yīng)的設(shè)備名為"/dev/sd0";fs為存儲(chǔ)設(shè)備使用的文件系統(tǒng)名,如果使用FAT文件系統(tǒng),則文件系統(tǒng)名為"vfat";flags為掛載時(shí)的一些選項(xiàng)標(biāo)識(shí),當(dāng)前無(wú)可用標(biāo)識(shí),預(yù)留給后續(xù)擴(kuò)展使用,設(shè)置為0即可。返回值為標(biāo)準(zhǔn)的錯(cuò)誤號(hào),返回AW_OK時(shí),表示掛載成功,否則,表示掛載失敗。掛載TF卡的范例程序詳見(jiàn)程序清單11.3。

程序清單11.3 掛載TF卡范例程序

注意,當(dāng)前掛載信息不會(huì)保存到存儲(chǔ)設(shè)備中,相關(guān)信息僅保留在內(nèi)存中,因此,每次重新上電時(shí),都應(yīng)該執(zhí)行掛載操作。

掛載完畢后,即在根目錄下創(chuàng)建了一個(gè)test掛載點(diǎn),對(duì)于用戶來(lái)講,后續(xù)即可在該目錄下進(jìn)行文件相關(guān)的操作,例如,創(chuàng)建文件、讀取文件、寫入文件等操作。此外,還可以在該目錄下創(chuàng)建子目錄,這些文件和子目錄信息都存儲(chǔ)在TF卡中,掉電不會(huì)丟失。

3. 取消掛載

當(dāng)設(shè)備不再使用時(shí),可以取消該設(shè)備的掛載,掛載點(diǎn)將刪除,用戶不可再訪問(wèn)該目錄。取消掛載的函數(shù)原型為:

其中,path為路徑名,可以是設(shè)備名(比如:"/dev/sd0"),也可以是掛載點(diǎn)(即掛載時(shí)指定的mnt參數(shù),比如:"/test")。flags為掛載時(shí)的一些選項(xiàng)標(biāo)識(shí),當(dāng)前無(wú)可用標(biāo)識(shí),預(yù)留給后續(xù)擴(kuò)展使用,設(shè)置為0即可。返回值為標(biāo)準(zhǔn)的錯(cuò)誤號(hào),返回AW_OK時(shí),表示取消掛載成功,否則,表示取消掛載失敗。取消掛載的范例程序詳見(jiàn)程序清單11.4。

程序清單11.4 取消掛載范例程序

由于在掛載設(shè)備時(shí),已經(jīng)將掛載點(diǎn)和設(shè)備名進(jìn)行了關(guān)聯(lián),因此,在取消掛載時(shí),只要知道掛載點(diǎn)和設(shè)備名中任何一個(gè)信息,均可得到完整的掛載信息,然后取消掛載。在程序清單11.4中,是通過(guò)掛載時(shí)使用的掛載點(diǎn)取消掛載,也可以通過(guò)設(shè)備名取消掛載,例如,將第19行代碼中的"/test"修改為"/dev/sd0"。

11.3 文件基本操作

文件相關(guān)的操作主要包括打開(kāi)文件(創(chuàng)建文件)、關(guān)閉文件、讀取文件數(shù)據(jù)、寫入數(shù)據(jù)等。相關(guān)接口的原型詳見(jiàn)表11.2。

表11.2 文件基本操作相關(guān)接口

1.打開(kāi)文件

打開(kāi)或創(chuàng)建一個(gè)文件的函數(shù)原型為:

其中,path為包含文件名的完整路徑,如需在test目錄下創(chuàng)建一個(gè)fs_test.txt文件,則path應(yīng)為"/test/fs_test.txt",文件名建議使用8.3格式,即主文件名長(zhǎng)度不超過(guò)8,擴(kuò)展名長(zhǎng)度不超過(guò)3。因?yàn)椴糠治募到y(tǒng)不支持更長(zhǎng)的文件名,使用8.3格式的文件名兼容性更好。

oflag指定打開(kāi)文件的方式,當(dāng)前支持的打開(kāi)方式詳見(jiàn)表11.3。

表11.3 打開(kāi)文件方式(io/aw_fcntl.h)

mode用于控制訪問(wèn)權(quán)限,其類型為mode_t,mode_t是一個(gè)整數(shù)類型,實(shí)際類型與具體平臺(tái)相關(guān),通常情況下,其為32位無(wú)符號(hào)整數(shù)。在當(dāng)前系統(tǒng)中,mode為與POSIX標(biāo)準(zhǔn)接口兼容的參數(shù),目前沒(méi)有使用,可以設(shè)置為0。在支持該參數(shù)的平臺(tái)中,其用于控制用戶訪問(wèn)文件的權(quán)限,僅當(dāng)創(chuàng)建文件時(shí)有效,有效位共計(jì)9位,每3位為1組,共計(jì)3組。3組分別控制3類用戶的權(quán)限:當(dāng)前用戶、組用戶、其它用戶。每組3位分別控制3種權(quán)限:讀、寫、執(zhí)行,相應(yīng)位為1,表明該類用戶具有相應(yīng)的權(quán)限。各組用戶權(quán)限的控制位詳見(jiàn)表11.4。

表11.4 權(quán)限控制

由于mode中每3位為一組,而3位二進(jìn)制數(shù)據(jù)恰好可以使用1位八進(jìn)制數(shù)據(jù)(0 ~ 7)表示。因此,為了便于閱讀,mode的值往往使用八進(jìn)制表示。如0777(在C語(yǔ)言中,數(shù)據(jù)前加0表示八進(jìn)制數(shù)據(jù)),表示所有用戶都具有讀、寫、執(zhí)行的權(quán)限。為了使應(yīng)用程序更具有兼容性,可以將mode的值設(shè)置為0777。

若文件打開(kāi)成功,則返回文件的句柄,后續(xù)使用該句柄進(jìn)行文件的讀寫操作。特別地,若返回值為-1,則表示打開(kāi)文件失敗。如打開(kāi)test目錄下的fs_test.txt文件(若不存在該文件,則創(chuàng)建該文件)的范例程序詳見(jiàn)程序清單11.5。

程序清單11.5 打開(kāi)文件范例程序

2. 創(chuàng)建文件

創(chuàng)建文件的函數(shù)原型為:

其中,path為包含文件名的完整路徑,注意,創(chuàng)建文件時(shí),需要保證path指定的路徑是有效的,若其父文件夾不存在,則會(huì)創(chuàng)建失敗。mode為文件的模式。其本質(zhì)上等效于:

由此可見(jiàn),其是以只寫方式打開(kāi)文件的,若文件不存在,由于使用了O_CREAT標(biāo)識(shí),則創(chuàng)建文件,若文件已穿在,由于使用了O_TRUNC標(biāo)識(shí),則會(huì)將原文件的內(nèi)容清空,長(zhǎng)度截?cái)酁?,相當(dāng)于創(chuàng)建了一個(gè)新文件。

若文件創(chuàng)建成功,則返回文件的句柄,后續(xù)使用該句柄進(jìn)行文件的讀寫操作。特別地,若返回值為-1,則表示創(chuàng)建文件失敗。如在test目錄下創(chuàng)建一個(gè)fs_test2.txt文件的范例程序詳見(jiàn)程序清單11.6。

程序清單11.6 創(chuàng)建文件范例程序

3. 關(guān)閉文件

文件打開(kāi)或創(chuàng)建后,若不再需要使用文件,則必須關(guān)閉該文件,文件關(guān)閉后,文件相關(guān)的數(shù)據(jù)才會(huì)被可靠的寫回硬件存儲(chǔ)設(shè)備。關(guān)閉文件的函數(shù)原型為:

其中,filedes為待關(guān)閉文件的句柄,其值是打開(kāi)文件或創(chuàng)建文件時(shí)返回的文件句柄。返回值為錯(cuò)誤號(hào),若返回AW_OK,則表示關(guān)閉文件成功,否則,表示關(guān)閉文件失敗。范例程序詳見(jiàn)程序清單11.7。

程序清單11.7 關(guān)閉文件范例程序

4. 寫入數(shù)據(jù)

文件打開(kāi)后,可以寫入數(shù)據(jù)至文件中,其函數(shù)原型為:

其中,filedes為文件句柄,buf為待寫入數(shù)據(jù)的緩沖區(qū),nbytes為寫入數(shù)據(jù)的字節(jié)數(shù)。返回值為成功寫入的字節(jié)數(shù),特別地,若返回值為負(fù)值,則表示寫入數(shù)據(jù)失敗,可能是由于打開(kāi)文件的方式不對(duì)造成的,例如,打開(kāi)文件時(shí),使用了只讀的方式打開(kāi)文件;若返回值小于nbytes,則可能是由于存儲(chǔ)設(shè)備容量不足造成的。

對(duì)于每個(gè)打開(kāi)的文件,系統(tǒng)中都使用了一個(gè)與其關(guān)聯(lián)的整數(shù)變量來(lái)表示該文件的讀寫位置,其值為相對(duì)于文件起始位置的偏移量。文件讀寫位置將決定下一次讀/寫數(shù)據(jù)時(shí)的位置。打開(kāi)文件時(shí),若未指定O_APPEND標(biāo)志,則讀寫位置初始為0,否則,讀寫位置在文件結(jié)尾,例如,文件大小為10,則讀寫位置的值即為10。每次寫入數(shù)據(jù)完畢后,都將自動(dòng)更新讀寫位置至本次寫入數(shù)據(jù)的尾部,例如,寫入10個(gè)數(shù)據(jù),則讀寫位置的值將自動(dòng)增加10,以便下次寫入數(shù)據(jù)時(shí),緊接著尾部繼續(xù)寫入。

例如,打開(kāi)文件,寫入一串字符串,最后再關(guān)閉文件的完整范例程序詳見(jiàn)程序清單11.8。

程序清單11.8 寫入數(shù)據(jù)范例程序

若程序運(yùn)行成功,則在TF卡中創(chuàng)建了一個(gè)fs_test.txt文件,同時(shí),在文件中寫入了字符串"just for test:0123456789"。為了驗(yàn)證操作是否成功,可以拔下TF卡,將TF卡通過(guò)讀卡器連接到PC上(Windows系統(tǒng)),通過(guò)PC查看TF卡中的內(nèi)容,可以看到TF卡目錄內(nèi)容和fs_test.txt文件內(nèi)容詳見(jiàn)圖11.3。

圖11.3 通過(guò)PC查看TF卡的內(nèi)容(1)

5. 讀取數(shù)據(jù)

文件打開(kāi)后,可以從文件中讀取數(shù)據(jù),其函數(shù)原型為:

其中,filedes為文件句柄,buf為保存讀取數(shù)據(jù)的緩沖區(qū),nbytes為讀取數(shù)據(jù)的字節(jié)數(shù)。返回值為成功讀取的字節(jié)數(shù),特別地,若返回值為負(fù)值,則表示讀取數(shù)據(jù)失敗,可能是由于打開(kāi)文件的方式不對(duì)造成的,例如,打開(kāi)文件時(shí),使用了只寫的方式打開(kāi)文件;若返回值不小于0,但小于nbytes,則表示文件數(shù)據(jù)不足,已經(jīng)讀取至文件結(jié)尾。

每次讀取數(shù)據(jù)完畢后,都將自動(dòng)更新讀寫位置至本次讀取數(shù)據(jù)的尾部,例如,讀取10個(gè)數(shù)據(jù),則讀寫位置的值將自動(dòng)增加10,以便下次讀取數(shù)據(jù)時(shí),緊接著尾部繼續(xù)讀取。

例如,以只讀方式打開(kāi)之前創(chuàng)建的/test/fs_test.txt文件,讀取文件內(nèi)容,以判斷讀寫是否正確的范例程序詳見(jiàn)程序清單11.9。

程序清單11.9 讀取數(shù)據(jù)范例程序

6. 改變文件讀寫位置

對(duì)于每個(gè)打開(kāi)的文件,都有一個(gè)“讀寫位置(相對(duì)于文件起始位置的偏移量)”來(lái)表示下一次讀/寫數(shù)據(jù)時(shí)的起始位置,其值除在每次讀/寫數(shù)據(jù)時(shí)自動(dòng)更新外,還可以使用aw_lseek()函數(shù)手動(dòng)改變,aw_lseek()的函數(shù)原型為:

其中,filedes為文件句柄,offset為設(shè)置的偏移量,whence指定offset偏移量的基準(zhǔn)位置。返回值為新的“讀寫位置”。

若whence的值為SEEK_SET,表示offset偏移量是以文件起始位置為基準(zhǔn),就相當(dāng)于直接設(shè)置“讀寫位置”的值為offset。使用SEEK_SET的范例程序詳見(jiàn)程序清單11.10。

程序清單11.10 SEEK_SET范例程序

若whence的值為SEEK_CUR,表示offset偏移量是以當(dāng)前“讀寫位置”為基準(zhǔn),即將“讀寫位置”的值加上offset作為新的“讀寫位置”,offset可正可負(fù),為正時(shí),增大“讀寫位置”的值,表示“讀寫位置”向文件尾部方向移動(dòng),為負(fù)時(shí),減小“讀寫位置”的值,表示“讀寫位置”向文件頭部方向移動(dòng)。使用SEEK_CUR的范例程序詳見(jiàn)程序清單11.11。

程序清單11.11 SEEK_CUR范例程序

若whence的值為SEEK_END,表示offset偏移量是以文件尾部為基準(zhǔn),即將“讀寫位置”的值設(shè)置為文件大小加上offset作為新的“讀寫位置”。使用SEEK_END的范例程序詳見(jiàn)程序清單11.12。

程序清單11.12 SEEK_END范例程序

值得注意的是,若移動(dòng)后的“讀寫位置”大于當(dāng)前文件大小,則移動(dòng)的結(jié)果將與具體的文件系統(tǒng)相關(guān)。通常情況下,“讀寫位置”被重置為當(dāng)前文件大小,即原文件尾部,部分特殊情況下,也可能會(huì)擴(kuò)充文件的大小??梢酝ㄟ^(guò)返回值判斷當(dāng)前實(shí)際的“讀寫位置”。出于兼容性考慮,不建議將“讀寫位置”移動(dòng)至當(dāng)前文件的有效范圍之外。

可以修改程序清單11.9所示的程序,在讀取數(shù)據(jù)前,設(shè)定“讀寫位置”為14,然后讀取10個(gè)字符,即可僅讀取出字符串:"0123456789",范例程序詳見(jiàn)程序清單11.13。

程序清單11.13 讀取指定位置數(shù)據(jù)段的范例程序

7. 截?cái)辔募?/strong>

用于將文件截?cái)酁橹付ㄩL(zhǎng)度,超出長(zhǎng)度的內(nèi)容將被刪除,一般情況下,都通過(guò)文件描述符filedes指定要截?cái)嗟奈募?,其函?shù)原型如下:

其中,filedes為文件句柄,length為新的文件長(zhǎng)度,如果length小于原文件長(zhǎng)度,文件將被截?cái)?。返回值為AW_OK時(shí),表示截?cái)喑晒?,否則,表示截?cái)嗍?。如將fs_test.txt文件長(zhǎng)度截?cái)酁?4,以刪除結(jié)尾的字符串:"0123456789",則范例程序詳見(jiàn)程序清單11.14。

程序清單11.14 截?cái)辔募独绦?/span>

在程序清單11.14中,截?cái)嘁粋€(gè)文件主要分為3步:打開(kāi)文件、截?cái)辔募?、關(guān)閉文件。為了簡(jiǎn)化截?cái)辔募牟僮?,AWorks提供了另外一個(gè)功能相同的接口,但其通過(guò)文件名指定要截?cái)嗟奈募?,使用起?lái)更加便捷,其函數(shù)原型為:

其中,path為文件的路徑,length為新的文件長(zhǎng)度。用戶無(wú)需在截?cái)辔募按蜷_(kāi)文件,該函數(shù)將在內(nèi)部打開(kāi)文件,截?cái)嗪箨P(guān)閉文件。如使用該接口,則一行代碼即可實(shí)現(xiàn)與程序清單11.14相同的功能,即:

8. 修改文件名

該函數(shù)用于修改指定文件的文件名,函數(shù)原型為:

其中,oldpath為原文件名,newpath為新文件名。返回值為AW_OK時(shí)表示更名成功,否則表示更名失敗。修改"/test/fs_test.txt"為"/test/fs_test3.txt"的范例程序詳見(jiàn)程序清單11.15。

程序清單11.15 修改文件名范例程序

注意,若newpath指定的文件已存在,則該文件將會(huì)被覆蓋。特別地,若newpath與oldpath相同,則函數(shù)不做任何處理,直接返回成功。

9. 同步文件

通常情況下,在操作文件的過(guò)程中,文件相關(guān)的數(shù)據(jù)并不會(huì)立即寫入到存儲(chǔ)設(shè)備中,而是保存在內(nèi)存中,這樣可以在一定程度上提高數(shù)據(jù)讀寫的效率。在關(guān)閉文件時(shí),再將該文件相關(guān)的所有數(shù)據(jù)保存到存儲(chǔ)設(shè)備中。在一些比較耗時(shí)的文件操作過(guò)程中,為了避免中途突然掉電導(dǎo)致數(shù)據(jù)丟失,也可以通過(guò)aw_fsync()函數(shù)立即執(zhí)行回寫操作,使文件相關(guān)的數(shù)據(jù)保存到存儲(chǔ)設(shè)備中。這就類似于在編寫一個(gè)Word文檔的過(guò)程中,需要時(shí)常點(diǎn)擊保存按鈕,避免突然掉電導(dǎo)致部分?jǐn)?shù)據(jù)丟失。其函數(shù)原型為:

其中,filedes為文件句柄。返回值為AW_OK時(shí)表示同步成功,否則,表示同步失敗。范例程序詳見(jiàn)程序清單11.16。

程序清單11.16 同步文件范例程序

10. 刪除文件

當(dāng)一個(gè)文件不再使用,可以刪除該文件,刪除指定文件的函數(shù)原型為:

其中,path為文件的路徑。返回值為AW_OK時(shí)表示刪除成功,否則,表示刪除失敗。范例程序詳見(jiàn)程序清單11.17。

程序清單11.17 刪除文件范例程序

11. 獲取文件狀態(tài)信息

對(duì)于一個(gè)文件,除基本數(shù)據(jù)外(使用讀寫接口操作的數(shù)據(jù)),還具有一些與文件相關(guān)的其它信息,比如:文件實(shí)際大小、文件占用大小、修改時(shí)間、訪問(wèn)權(quán)限等。這些信息統(tǒng)一被稱為狀態(tài)信息,可以通過(guò)aw_fstat()接口獲取文件的狀態(tài)信息,其函數(shù)原型為:

其中,fildes為文件句柄,buf為文件狀態(tài)信息的緩存。返回值為AW_OK時(shí)表示獲取成功,否則,表示獲取失敗。文件狀態(tài)信息的類型為struct aw_stat,其完整定義如下(io/sys/aw_stat.h):

其中的絕大部分成員在當(dāng)前系統(tǒng)中并未使用,預(yù)留給后續(xù)擴(kuò)展。這里僅簡(jiǎn)要介紹幾個(gè)常用的數(shù)據(jù)成員:st_mode、st_size、st_atim、st_mtim和st_ctim。

st_mode包含了文件類型及權(quán)限相關(guān)的信息,權(quán)限相關(guān)信息與創(chuàng)建文件時(shí)指定的mode參數(shù)一致。

st_size表示文件的實(shí)際長(zhǎng)度。通常情況下,文件占用的磁盤空間會(huì)大于該值。如在FAT文件系統(tǒng)中,存儲(chǔ)文件的基本單元為“簇”,即使文件小于基本的存儲(chǔ)單元大小,也會(huì)占用一個(gè)完整的存儲(chǔ)單元。文件占用的磁盤空間可由st_blksize和st_blocks獲得,st_blksize表示存儲(chǔ)單元的大小,st_blocks表示文件占用的存儲(chǔ)單元個(gè)數(shù),兩者的乘積則表示文件占用的空間大小。

st_atim、st_mtim、st_ctim表示文件相關(guān)的時(shí)間,st_atim為最后訪問(wèn)文件的時(shí)間,st_mtim為最后修改文件內(nèi)容的時(shí)間,st_ctim為最后修改文件狀態(tài)的時(shí)間。在部分平臺(tái)中,可能沒(méi)有嚴(yán)格細(xì)分這些時(shí)間,而是統(tǒng)一的使用一個(gè)時(shí)間表示,此時(shí),各個(gè)時(shí)間的值將是相同的。這些時(shí)間的類型為struct timespec,其表示精確日歷時(shí)間,即:

精確日歷時(shí)間中包含了秒和納秒信息??梢酝ㄟ^(guò)將該時(shí)間轉(zhuǎn)換為細(xì)分時(shí)間,得到年、月、日、時(shí)、分、秒等信息。獲取文件狀態(tài)信息的范例程序詳見(jiàn)程序清單11.18。

程序清單11.18 獲取文件狀態(tài)信息的范例程序

和截?cái)辔募愃?,AWorks也提供了另外一個(gè)功能相同的接口,可以通過(guò)文件名指定要獲取狀態(tài)信息的文件,使用起來(lái)更加便捷,其函數(shù)原型為:

其中,path為文件路徑,buf為文件狀態(tài)信息的緩存。返回AW_OK時(shí)表示獲取成功,否則,表示獲取失敗??梢允褂迷摻涌诤?jiǎn)化程序清單11.18的第21、22、29共計(jì)3含代碼,使用一行代碼代替,即:

12. 修改文件時(shí)間

一個(gè)文件的存取和修改時(shí)間可以用 aw_utime() 函數(shù)更改,其函數(shù)原型為:

其中,path為文件的路徑,times為設(shè)置的時(shí)間。struct aw_utimbuf類型的定義(io/aw_utime.h)如下:

其中,actime表示文件最近一次的訪問(wèn)時(shí)間,modtime表示文件最近一次的內(nèi)容修改時(shí)間,它們的類型均為time_t,time_t是日歷之間類型,即actime和modtime均使用日歷時(shí)間表示。返回AW_OK時(shí),表示時(shí)間設(shè)置成功,否則,表示時(shí)間設(shè)置失敗。如設(shè)置文件訪問(wèn)時(shí)間和文件修改時(shí)間均為2016年8月26日09:32:30,則范例程序詳見(jiàn)程序清單11.19。

程序清單11.19 修改文件時(shí)間的范例程序

程序中,首先使用aw_utime()修改了文件時(shí)間,然后使用aw_stat()獲取文件的狀態(tài)信息,以查看時(shí)間是否設(shè)置成功。

11.4 目錄基本操作

目錄相關(guān)的操作主要包括創(chuàng)建目錄、打開(kāi)目錄、讀取目錄、關(guān)閉目錄、刪除目錄等。相關(guān)接口的原型詳見(jiàn)表11.5。

表11.5 目錄基本操作相關(guān)接口

1. 創(chuàng)建目錄

創(chuàng)建一個(gè)空目錄,其函數(shù)原型為:

其中,path是待創(chuàng)建目錄的完整路徑,包括待創(chuàng)建目錄的父目錄和新目錄的名字,如需在"/test"目錄下創(chuàng)建一個(gè)"newdir"目錄,則path為"/test/newdir",注意,必須保證父目錄已存在,且父目錄下不存在即將創(chuàng)建的同名目錄。mode指定目錄相關(guān)的權(quán)限,默認(rèn)使用0777。

返回值為標(biāo)準(zhǔn)的錯(cuò)誤號(hào),若返回AW_OK,表示新目錄創(chuàng)建成功,否則,表示新目錄創(chuàng)建失敗。如在"/test"目錄下創(chuàng)建一個(gè)"newdir"目錄,則范例程序詳見(jiàn)程序清單11.20。

程序清單11.20 創(chuàng)建目錄范例程序

若程序運(yùn)行成功,則在TF卡中創(chuàng)建了一個(gè)newdir目錄。為了驗(yàn)證操作是否成功,可以拔下TF卡,將TF卡通過(guò)讀卡器連接到PC上(Windows系統(tǒng)),通過(guò)PC查看TF卡中的內(nèi)容,TF卡目錄的內(nèi)容詳見(jiàn)圖11.4 (a),其中新增了newdir目錄,且newdir當(dāng)前是一個(gè)空目錄,詳見(jiàn)圖11.4(b)。

圖11.4 通過(guò)PC查看TF卡的內(nèi)容(2)

可以嘗試在newdir目錄中新建文件,例如:

2. 打開(kāi)目錄

在目錄操作中,遍歷已存在的一個(gè)目錄是一種常見(jiàn)的操作,即遍歷一個(gè)目錄下所有的子項(xiàng)(包括文件和子目錄)。遍歷過(guò)程主要分為3個(gè)步驟:打開(kāi)目錄、讀取目錄、關(guān)閉目錄。

在遍歷一個(gè)目錄前,首先需要打開(kāi)該目錄,其函數(shù)原型為:

其中,dirname為目錄名,如需打開(kāi)根目錄下的test目錄,則其值為"/test"。返回值為指向一個(gè)目錄對(duì)象的指針,目錄類型struct aw_dir 在io/aw_dirent.h文件中定義,其具體定義用戶無(wú)需掌握,僅需保存下該指針,后續(xù)使用該指針代表打開(kāi)的目錄即可,特別地,若返回值為NULL,則表示目錄打開(kāi)失敗。打開(kāi)目錄的范例程序詳見(jiàn)程序清單11.21。

程序清單11.21 打開(kāi)目錄范例程序

3. 讀取目錄

打開(kāi)目錄后,即可依次讀取該目錄中的各個(gè)子項(xiàng)(文件或子目錄),獲得它們的名字等信息,其函數(shù)原型為:

其中,dirp為指向目錄對(duì)象的指針,可通過(guò)打開(kāi)目錄獲得。返回值為目錄項(xiàng)指針,即為本次讀取的一條目錄項(xiàng),其類型struct aw_dirent的定義如下:

其中,d_ino為項(xiàng)目序列號(hào),其值為一個(gè)整數(shù),每個(gè)子項(xiàng)都有一個(gè)對(duì)應(yīng)的序列號(hào),在一個(gè)目錄中,若共計(jì)有10個(gè)子項(xiàng),則各子項(xiàng)的序列號(hào)依次為0 ~ 9。d_name為該子項(xiàng)的名字。

打開(kāi)目錄后首次調(diào)用讀取目錄接口,獲得的子項(xiàng)序列號(hào)為0,要獲取一個(gè)目錄下所有的子項(xiàng),可以多次調(diào)用讀取目錄接口,每次調(diào)用結(jié)束后,都會(huì)將序列號(hào)加1,下次讀取時(shí)將讀取到下一個(gè)子項(xiàng)。特別地,若讀取目錄的返回值為NULL,表示讀取結(jié)束。讀取一個(gè)目錄下所有子項(xiàng)的范例程序詳見(jiàn)程序清單11.22。

程序清單11.22 讀取目錄范例程序(1)

aw_readdir()接口通過(guò)返回值返回一個(gè)指向讀取目錄子項(xiàng)的指針,該指針指向的實(shí)際內(nèi)存是由系統(tǒng)內(nèi)部分配的靜態(tài)內(nèi)存,在多任務(wù)環(huán)境中,這份內(nèi)存是共享的,因此,該接口不是線程安全的,例如,在一個(gè)任務(wù)中讀取了一次目錄,則靜態(tài)內(nèi)存中存放了本次讀取的結(jié)果,其地址返回給用戶,用戶通過(guò)指針訪問(wèn)讀取目錄的結(jié)果。若在這個(gè)過(guò)程中,另外一個(gè)任務(wù)也讀取了一次目錄,則內(nèi)存中的數(shù)據(jù)將發(fā)生改變,這將覆蓋前一個(gè)任務(wù)讀取目錄的結(jié)果。由此可見(jiàn),當(dāng)多個(gè)任務(wù)同時(shí)訪問(wèn)一個(gè)目錄時(shí),必須使用互斥機(jī)制。

為此,AWorks提供了另外一個(gè)線程安全的接口:aw_readdir_r(),它們?cè)诠δ苌鲜峭耆粯拥?,唯一的不同是,使用該接口讀取目錄時(shí),讀取結(jié)果存儲(chǔ)在用戶提供的一段內(nèi)存中,其原型為:

其中, dirp為指向目錄對(duì)象的指針,可通過(guò)打開(kāi)目錄獲得;entry為存儲(chǔ)讀取結(jié)果的緩存,result為一個(gè)二維指針,即一個(gè)指針的地址,程序執(zhí)行結(jié)束后,指針的值即被設(shè)置為指向本次讀取目錄的結(jié)果。

若返回值為AW_OK,則讀取成功,否則,讀取失敗。值得注意的是,當(dāng)目錄讀取未達(dá)結(jié)尾,成功讀取到一個(gè)子項(xiàng)時(shí),由于讀取的結(jié)果存儲(chǔ)在entry指向的內(nèi)存中,因此,result的值被設(shè)置為entry(即:*result=entry),當(dāng)目錄讀取達(dá)到結(jié)尾時(shí),result的值將被設(shè)置為NULL(即:*result=NULL)。范例程序詳見(jiàn)程序清單11.23。

程序清單11.23 讀取目錄范例程序(2)

4. 關(guān)閉目錄

若讀取目錄完畢,或不再需要讀取目錄時(shí),則可以關(guān)閉目錄,其函數(shù)原型為:

其中,dirp為指向目錄對(duì)象的指針,可通過(guò)打開(kāi)目錄獲得。返回值為AW_OK時(shí)表示關(guān)閉成功,否則,表示關(guān)閉失敗。

綜合打開(kāi)目錄、讀取目錄、關(guān)閉目錄三個(gè)接口,遍歷一個(gè)目錄下所有子項(xiàng)的范例程序詳見(jiàn)程序清單11.24。

程序清單11.24 遍歷目錄范例程序

5. 刪除目錄

當(dāng)一個(gè)目錄不再使用,可以刪除該目錄,刪除指定目錄的函數(shù)原型為:

其中,path為目錄的路徑。返回值為AW_OK時(shí)表示刪除成功,否則,表示刪除失敗。該函數(shù)僅可用于刪除一個(gè)空目錄,若目錄非空,則刪除失敗。范例程序詳見(jiàn)程序清單11.25。

程序清單11.25 刪除目錄范例程序

11.5 微型數(shù)據(jù)庫(kù)

AWorks提供了一個(gè)基于文件系統(tǒng)實(shí)現(xiàn)的微型數(shù)據(jù)庫(kù),用以管理信息記錄,每條記錄由“關(guān)鍵字”和“值”兩部分構(gòu)成,關(guān)鍵字可用于記錄的查找、刪除等。微型數(shù)據(jù)庫(kù)是基于哈希表原理實(shí)現(xiàn)的,具有簡(jiǎn)潔、高效的特點(diǎn)。為了便于理解,本節(jié)首先對(duì)哈希表進(jìn)行簡(jiǎn)要介紹,然后再介紹微型數(shù)據(jù)庫(kù)的各個(gè)接口。

11.5.1 哈希表

在數(shù)據(jù)存儲(chǔ)應(yīng)用中,存儲(chǔ)的記錄往往都具有唯一的關(guān)鍵字,以便于管理。例如,為了管理學(xué)生信息(包含姓名、性別、身高、體重等),會(huì)為每個(gè)學(xué)生分配一個(gè)學(xué)號(hào),通過(guò)學(xué)號(hào)就可以唯一的定位一個(gè)學(xué)生,這里的學(xué)號(hào)即為關(guān)鍵字。常見(jiàn)的身份證號(hào)也具有類似的作用。

假設(shè)需要設(shè)計(jì)一個(gè)信息管理系統(tǒng),用于管理學(xué)生信息,可以將每條學(xué)生信息看作一條記錄。

一條記錄包含學(xué)號(hào)、姓名、性別、身高、體重等信息,可定義與學(xué)生記錄對(duì)應(yīng)的結(jié)構(gòu)體類型,詳見(jiàn)程序清單11.26。

程序清單11.26 學(xué)生信息類型定義

作為一個(gè)信息管理系統(tǒng),首先要能夠?qū)崿F(xiàn)學(xué)生記錄的存儲(chǔ),基于文件系統(tǒng)接口可以很容易實(shí)現(xiàn):直接將記錄寫入到文件中即可。增加一條學(xué)生記錄的范例程序詳見(jiàn)程序清單11.27。

程序清單11.27 增加一條學(xué)生記錄

程序中,假定了存儲(chǔ)學(xué)生記錄的文件名為:"/test/students.txt",這就要求系統(tǒng)中,將/test目錄掛載到特定的存儲(chǔ)器,比如SD卡或U盤等。增加一條記錄的實(shí)現(xiàn)非常簡(jiǎn)單,僅僅是將p_info指向的學(xué)生記錄順序的存入了文件尾部,因此,使用這種方法增加學(xué)生記錄的效率還是比較高的。

如果使用student_add()函數(shù)增加了若干學(xué)生記錄,將學(xué)生記錄存儲(chǔ)在了文件中,接下來(lái),最常見(jiàn)的操作就是根據(jù)學(xué)號(hào)查詢學(xué)生信息。基于學(xué)生信息的存儲(chǔ)方式,可以實(shí)現(xiàn)一個(gè)學(xué)生信息查詢函數(shù),范例程序詳見(jiàn)程序清單11.28。

程序清單11.28 根據(jù)學(xué)號(hào)查詢學(xué)生記錄

由此可見(jiàn),程序僅僅從文件頭部順序讀取文件學(xué)生記錄,逐一與待查找的學(xué)號(hào)進(jìn)行比對(duì),直到查找到與學(xué)號(hào)完全一致的學(xué)生記錄。

上述簡(jiǎn)單的范例程序?qū)崿F(xiàn)了記錄的添加和查找。由于查找學(xué)生記錄是采用順序查找的方式,隨著學(xué)生記錄的增加,查找效率將逐步降低。例如,一所大學(xué)往往有幾萬(wàn)學(xué)生,則使用該系統(tǒng)管理學(xué)生記錄時(shí),一次簡(jiǎn)單的查找則可能要順序?qū)Ρ壬先f(wàn)次學(xué)號(hào),顯然,效率不高。

如何以更高的效率實(shí)現(xiàn)查找呢?在查找算法中,非常經(jīng)典高效的算法是“二分法查找”,按10000條記錄算,最多也只需要比較14次(log210000)。但是,使用“二分法查找”的前提是信息必須有序排列,即要求學(xué)生記錄必須按照學(xué)號(hào)從大到小或從小到大的順序進(jìn)行存儲(chǔ),這就導(dǎo)致在添加學(xué)生信息時(shí),必須將學(xué)生記錄按照學(xué)號(hào)順序,插入到指定位置,而不能像程序清單11.27那樣,簡(jiǎn)單的將信息添加至文件尾部。對(duì)于文件操作來(lái)講,插入操作是非常繁瑣的,若已經(jīng)有大量學(xué)生記錄按學(xué)號(hào)順序存儲(chǔ)在文件中,在此基礎(chǔ)上再插入一條記錄到這些記錄的中間某個(gè)位置,則需要將其后的所有記錄后移,以預(yù)留出一條記錄的存儲(chǔ)空間,這意味著需要將后續(xù)所有記錄讀出,再重新寫入到其后的地址中。由此可見(jiàn),雖然使用這種方法可以提高查找效率,卻犧牲了添加信息的效率。

“順序查找”管理方式犧牲了查找記錄的效率,“二分法查找”犧牲了寫入記錄的效率。能否將二者折中一下呢?“二分法查找”的本質(zhì)是每次縮小一半的查找范圍,基于縮小查找范圍的思想,可以嘗試縮小每次“順序查找”的范圍。同樣以10000條記錄為例,為了縮小每次“順序查找”的范圍,將記錄分為兩個(gè)部分,例如,制定以下規(guī)則:學(xué)號(hào)小于某一值時(shí),作為第一部分存儲(chǔ)在某一文件中;反之,作為第二部分存儲(chǔ)在另外一個(gè)文件中。

如此一來(lái),在寫入記錄時(shí),只需要多一條判斷語(yǔ)句,對(duì)性能并沒(méi)太大影響。而在查找時(shí),只要根據(jù)學(xué)號(hào)判斷出記錄應(yīng)存儲(chǔ)在哪一個(gè)文件中,然后按照順序查找的方式進(jìn)行查找即可。此時(shí),若用于分界的學(xué)號(hào)選擇恰當(dāng),使兩個(gè)部分的學(xué)生記錄數(shù)量基本相同,則順序查找需要比較的次數(shù)就從最大的10000次降低到了約5000次。由此可見(jiàn),通過(guò)一個(gè)簡(jiǎn)單的方法,將信息分別存儲(chǔ)在兩個(gè)文件中,就可以明顯地提高查找效率。

為了繼續(xù)提高查找的效率,還可以將記錄分為更多的部分,比如,分成250個(gè)部分,序號(hào)為0~ 249,若劃分規(guī)則恰當(dāng),使各個(gè)部分的學(xué)生記錄數(shù)量基本相同,則每個(gè)部分的記錄數(shù)目就約為40條,此時(shí),順序查找需要比較的次數(shù)就僅需約40次即可!示意圖詳見(jiàn)圖11.5。

圖11.5 將記錄分為多個(gè)部分

圖11.5可以看作大小為250的“哈希表”,“哈希表”的每個(gè)表項(xiàng)對(duì)應(yīng)了一部分記錄。哈希表的核心思想是將一個(gè)很大范圍的關(guān)鍵字空間(例如,學(xué)號(hào)為6字節(jié),6字節(jié)數(shù)據(jù)共計(jì)48位,其表示的數(shù)值空間大小為:248,約280萬(wàn)億,是一個(gè)相當(dāng)大的范圍),映射到一個(gè)較小的空間(范圍序號(hào):0 ~ 249,大小為250)。由于是大范圍映射到小范圍,因此可能有一部分關(guān)鍵字(學(xué)號(hào))映射到同一個(gè)表項(xiàng)中,也就是每個(gè)表項(xiàng)可能包含多條記錄。

哈希表的關(guān)鍵是確定映射關(guān)系,即如何將關(guān)鍵字(學(xué)號(hào))映射到表項(xiàng)的序號(hào),也就是將所有記錄劃分為多個(gè)部分的具體規(guī)則。當(dāng)寫入或查找一條記錄時(shí),可以通過(guò)映射關(guān)系確定該記錄屬于哪一部分。這個(gè)映射關(guān)系對(duì)應(yīng)的函數(shù)即為“哈希函數(shù)”,其作用就是將學(xué)號(hào)轉(zhuǎn)換為哈希表的表項(xiàng)序號(hào)。例如,假定學(xué)號(hào)是均勻分布的,則可以將6字節(jié)學(xué)號(hào)直接求和再對(duì)250取余,進(jìn)而得到一個(gè)0 ~ 249的數(shù),范例程序詳見(jiàn)程序清單11.29。

程序清單11.29 映射關(guān)系——通過(guò)學(xué)號(hào)得到分組索引

db_id_to_idx()函數(shù)就是“哈希函數(shù)”,哈希函數(shù)的結(jié)果(分組索引)稱之為“哈希值”。

“哈希函數(shù)”是整個(gè)哈希表的關(guān)鍵,哈希函數(shù)應(yīng)盡可能確保記錄均勻的分布到各個(gè)表項(xiàng)中,不能差異太大,極端地,若哈希函數(shù)選擇有誤,將所有記錄分布到了一個(gè)表項(xiàng)中,那這樣的哈希表將沒(méi)有任何意義,因?yàn)槊看尾檎矣涗浻只氐搅俗畛醯臓顟B(tài):遍歷所有記錄。

實(shí)際應(yīng)用中,記錄往往是動(dòng)態(tài)管理的,可以隨時(shí)動(dòng)態(tài)添加、刪除。因此,每一部分(哈希表的表項(xiàng))包含的記錄數(shù)也會(huì)動(dòng)態(tài)增加或減少。為了便于動(dòng)態(tài)管理每一部分的記錄,各部分可以使用鏈表管理該部分中可能存在的多條記錄,示意圖詳見(jiàn)圖11.6,圖中所示的鏈?zhǔn)焦1斫Y(jié)構(gòu)就是AWorks中微型數(shù)據(jù)庫(kù)原理。

圖11.6 鏈?zhǔn)焦1斫Y(jié)構(gòu)

11.5.2 微型數(shù)據(jù)庫(kù)接口

前面簡(jiǎn)要介紹了哈希表的原理,AWorks提供了一個(gè)基于哈希表思想實(shí)現(xiàn)的微型數(shù)據(jù)庫(kù),提供了增加、刪除、查找等接口,相關(guān)接口的原型詳見(jiàn)表11.6。

表11.6 微型數(shù)據(jù)庫(kù)接口(aw_db_micro_hash_kv.h)

微型數(shù)據(jù)庫(kù)相關(guān)的文件和接口以“aw_db_micro_hash_kv”作為命名空間,其中,“aw_”表示AWorks,“db”表示數(shù)據(jù)庫(kù)(data base),“micro”表示微型,hash_kv表示基于的是hash關(guān)鍵字和值的思想。

1. 定義數(shù)據(jù)庫(kù)實(shí)例

所有接口的第一個(gè)參數(shù)均為aw_db_micro_hash_kv_t類型的指針,用于指向待操作的數(shù)據(jù)庫(kù)實(shí)例。該類型的具體定義(如具體包含哪些成員)用戶無(wú)需關(guān)心,僅需在使用微型數(shù)據(jù)庫(kù)前,使用該類型定義一個(gè)數(shù)據(jù)庫(kù)實(shí)例即可,例如:

其中,students_db的地址即可作為各個(gè)接口p_db參數(shù)的實(shí)參傳遞。

2. 初始化

在使用數(shù)據(jù)庫(kù)前,需要完成數(shù)據(jù)庫(kù)的初始化,以指定哈希表大小、關(guān)鍵字長(zhǎng)度、值長(zhǎng)度以及存儲(chǔ)整個(gè)數(shù)據(jù)庫(kù)的文件名等信息。其函數(shù)原型為:

其中,p_db指向待初始化的數(shù)據(jù)庫(kù)實(shí)例。size表示哈希表的大小,即表項(xiàng)的數(shù)目,如需設(shè)計(jì)圖11.6所示的哈希表,由于其哈希表的大小為250,則該值應(yīng)設(shè)置為250。key_size為關(guān)鍵字長(zhǎng)度,例如,以學(xué)號(hào)為關(guān)鍵字,由于學(xué)號(hào)的長(zhǎng)度為6字節(jié),則該值應(yīng)設(shè)置為6。

value_size表示記錄中值的長(zhǎng)度,以學(xué)生記錄為例,一條學(xué)生記錄包含學(xué)號(hào)、姓名、性別、身高、體重等信息。最初的學(xué)生記錄對(duì)應(yīng)的結(jié)構(gòu)體類型詳見(jiàn)程序清單11.26。在使用微型數(shù)據(jù)庫(kù)時(shí),關(guān)鍵字和值是不同的兩個(gè)部分,均會(huì)被存儲(chǔ)到文件中。因此,可以將關(guān)鍵字學(xué)號(hào)分離出來(lái),剩余的信息作為一條學(xué)生記錄的“值”。詳見(jiàn)程序清單11.30。

程序清單11.30 學(xué)生記錄信息類型(不包括關(guān)鍵字——學(xué)號(hào))

基于此,value_size的值則應(yīng)設(shè)置為:sizeof(student_t)。

pfn_hash用于指定一個(gè)哈希函數(shù),其作用是將關(guān)鍵字轉(zhuǎn)換為一個(gè)哈希值,哈希值即為哈希表的索引。其類型aw_db_micro_hash_kv_func_t定義如下:

該類型為一個(gè)函數(shù)指針類型,其指向函數(shù)的形參為關(guān)鍵字,返回值為哈希值(類型為無(wú)符號(hào)整數(shù)),哈希值將作為哈希表的索引。通過(guò)對(duì)哈希表的介紹可知,哈希函數(shù)的選擇直接決定了記錄的分布,必須盡可能地確保所有記錄均勻地分布在各個(gè)表項(xiàng)中。不同的關(guān)鍵字?jǐn)?shù)據(jù)具有不同的分布特性,因此,哈希函數(shù)需要由用戶根據(jù)實(shí)際情況提供,簡(jiǎn)單的實(shí)現(xiàn)可以將關(guān)鍵字按字節(jié)求和后再對(duì)哈希表大小取余,詳見(jiàn)程序清單11.31。

程序清單11.31 簡(jiǎn)易的哈希函數(shù)實(shí)現(xiàn)

其中,函數(shù)名hash_func_id_to_idx即可作為pfn_hash的實(shí)參傳遞。

file_name用于指定存儲(chǔ)該數(shù)據(jù)庫(kù)信息及所有記錄的文件名,若一個(gè)系統(tǒng)中存在多個(gè)數(shù)據(jù)庫(kù)(定義了多個(gè)數(shù)據(jù)庫(kù)實(shí)例),則在初始化各個(gè)數(shù)據(jù)庫(kù)時(shí),為各個(gè)數(shù)據(jù)庫(kù)指定的文件名應(yīng)該不同,以使各個(gè)數(shù)據(jù)庫(kù)使用不同的文件存儲(chǔ)數(shù)據(jù)。在程序清單11.27和程序清單11.28所示的簡(jiǎn)易范例程序中,每次寫入記錄或查找記錄前,都會(huì)執(zhí)行一次打開(kāi)文件操作,并在寫入或查找結(jié)束后關(guān)閉文件。在實(shí)際應(yīng)用中,可能會(huì)頻繁的執(zhí)行寫入、查找等操作,這樣就會(huì)導(dǎo)致頻繁的打開(kāi)、關(guān)閉文件,降低了程序運(yùn)行的效率,為此,AWorks提供的數(shù)據(jù)庫(kù)僅僅在初始化時(shí)打開(kāi)文件,后續(xù)其它操作均無(wú)需再執(zhí)行打開(kāi)文件操作。若初始化時(shí)指定的文件名對(duì)應(yīng)文件已經(jīng)存在,則僅僅打開(kāi)該文件,然后再該文件的基礎(chǔ)上進(jìn)行記錄的管理(添加、刪除等);若文件名對(duì)應(yīng)文件不存在,則創(chuàng)建該文件,以建立一個(gè)全新的數(shù)據(jù)庫(kù)(數(shù)據(jù)庫(kù)中沒(méi)有任何有效記錄)。初始化數(shù)據(jù)庫(kù)的范例程序詳見(jiàn)程序清單11.32。

程序清單11.32 初始化數(shù)據(jù)庫(kù)范例程序

3. 增加一條記錄

該函數(shù)用于向數(shù)據(jù)庫(kù)中增加一條記錄,其函數(shù)原型為:

其中,p_db指向已經(jīng)初始化的數(shù)據(jù)庫(kù)實(shí)例。p_key指向本次增加記錄的關(guān)鍵字,其長(zhǎng)度必須與初始化指定的key_size一致。p_value指向本次增加記錄的具體“值”。例如,待增加一條學(xué)生記錄,其各項(xiàng)信息詳見(jiàn)表11.7。

表11.7 待增加的學(xué)生信息舉例

則向數(shù)據(jù)庫(kù)中增加該學(xué)生記錄的范例程序詳見(jiàn)程序清單11.33。

程序清單11.33 增加記錄范例程序

4. 根據(jù)關(guān)鍵字查找記錄

向數(shù)據(jù)庫(kù)中添加記錄后,可以根據(jù)關(guān)鍵字查找記錄的詳細(xì)信息,查找記錄的函數(shù)原型為:

其中,p_db指向數(shù)據(jù)庫(kù)實(shí)例。p_key為輸入?yún)?shù),指向本次查找記錄的關(guān)鍵字,關(guān)鍵字長(zhǎng)度必須與初始化時(shí)指定的key_size一致。p_value為輸出參數(shù),返回本次查找到的記錄。

例如,若使用程序清單11.33所示的范例程序增加了一條學(xué)生記錄,作為測(cè)試,可以使用查找記錄接口查找學(xué)號(hào)為201644700239的記錄,以查看其對(duì)應(yīng)的“值”信息是否與寫入的信息一致。范例程序詳見(jiàn)程序清單11.34。

程序清單11.34 根據(jù)關(guān)鍵字查找記錄的范例程序

程序中,為了避免使用aw_kprintf()打印浮點(diǎn)數(shù),將身高和體重分為整數(shù)部分和小數(shù)部分打印,最終等效于保留2位小數(shù)的浮點(diǎn)數(shù)打印效果。

5. 刪除一條記錄

通過(guò)該接口可以刪除數(shù)據(jù)庫(kù)中的一條記錄,其函數(shù)原型為:

其中,p_db指向數(shù)據(jù)庫(kù)實(shí)例。p_key指向本次需要?jiǎng)h除記錄的關(guān)鍵字,關(guān)鍵字長(zhǎng)度必須與初始化時(shí)指定的key_size一致。

例如,若使用程序清單11.33所示的范例程序增加了一條學(xué)生記錄,作為測(cè)試,可以將學(xué)號(hào)為201644700239的記錄刪除。范例程序詳見(jiàn)程序清單11.35。

程序清單11.35 根據(jù)關(guān)鍵字刪除記錄的范例程序

使用程序清單11.35所示程序刪除記錄后,若再查找學(xué)號(hào)為201644700239的記錄,將會(huì)查找失敗。

6. 解初始化

與數(shù)據(jù)庫(kù)初始化函數(shù)對(duì)應(yīng)。當(dāng)暫時(shí)不使用一個(gè)數(shù)據(jù)庫(kù)時(shí),可以執(zhí)行該函數(shù),以釋放相關(guān)資源。注意,解初始化后,數(shù)據(jù)庫(kù)中已經(jīng)存儲(chǔ)的內(nèi)容保持不變。解初始化函數(shù)的原型為:

其中,p_db指向數(shù)據(jù)庫(kù)實(shí)例。例如,在一次應(yīng)用中,添加了100個(gè)學(xué)生記錄,添加結(jié)束后,暫時(shí)不再使用該數(shù)據(jù)庫(kù),則可以解初始化該數(shù)據(jù)庫(kù),范例程序詳見(jiàn)程序清單11.36。

程序清單11.36 解初始化范例程序

在初始化函數(shù)的介紹中提到,為了避免頻繁的打開(kāi)文件和關(guān)閉文件,在初始化時(shí)打開(kāi)了文件,使得在添加記錄、刪除記錄、查找記錄時(shí),無(wú)需再打開(kāi)文件。與初始化函數(shù)對(duì)應(yīng),在解初始化函數(shù)中,關(guān)閉了文件。關(guān)閉文件后,文件中的內(nèi)容保持不變。如需再次使用該數(shù)據(jù)庫(kù),則應(yīng)該重新執(zhí)行一次初始化操作。

上面介紹了各個(gè)接口的使用方法,基于這些接口,可以實(shí)現(xiàn)一個(gè)學(xué)生記錄管理的綜合范例程序,詳見(jiàn)程序清單11.37。

程序清單11.37 微型數(shù)據(jù)庫(kù)綜合范例程序

測(cè)試程序主要由test_db_micro_hash_kv()完成,在aw_min()主程序中,僅僅是簡(jiǎn)單調(diào)用了該函數(shù)。在test_db_micro_hash_kv()函數(shù)中,首先初始化了一個(gè)數(shù)據(jù)庫(kù),然后向其中添加了100個(gè)學(xué)生記錄(為了快捷產(chǎn)生這些記錄,以隨機(jī)數(shù)的方式自動(dòng)生成,隨機(jī)數(shù)無(wú)實(shí)際意義,僅供測(cè)試使用。同時(shí),為了保證添加的學(xué)生學(xué)號(hào)唯一,在添加記錄前,通過(guò)搜索接口查看是否存在該學(xué)號(hào)的學(xué)生,若存在,則不再重復(fù)添加)。接著測(cè)試了查找接口,查找最后添加的學(xué)生記錄。然后測(cè)試刪除接口,刪除了最后添加的學(xué)生記錄,刪除成功后,再次查找將會(huì)失敗。最后,所有操作執(zhí)行完畢,解初始化數(shù)據(jù)庫(kù)。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11171

    瀏覽量

    208478
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    569

    瀏覽量

    40063
  • AWorks
    +關(guān)注

    關(guān)注

    1

    文章

    16

    瀏覽量

    5674

原文標(biāo)題:AWorks軟件篇 — 文件系統(tǒng)

文章出處:【微信號(hào):Zlgmcu7890,微信公眾號(hào):周立功單片機(jī)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    嵌入式常用數(shù)據(jù)結(jié)構(gòu)有哪些

    在嵌入式編程中,數(shù)據(jù)結(jié)構(gòu)的選擇和使用對(duì)于程序的性能、內(nèi)存管理以及開(kāi)發(fā)效率都具有重要影響。嵌入式系統(tǒng)由于資源受限(如處理器速度、內(nèi)存大小等),因此對(duì)數(shù)據(jù)結(jié)構(gòu)的選擇和使用尤為關(guān)鍵。以下是嵌入式編程中常用的幾種
    的頭像 發(fā)表于 09-02 15:25 ?309次閱讀

    探索編程世界的七大數(shù)據(jù)結(jié)構(gòu)

    樹(shù)結(jié)構(gòu)就像是一顆倒掛的小樹(shù),有根、有枝、有葉。它是一種非線性的數(shù)據(jù)結(jié)構(gòu),以層級(jí)的方式存儲(chǔ)數(shù)據(jù),頂部是根節(jié)點(diǎn),底部是葉節(jié)點(diǎn)。
    的頭像 發(fā)表于 04-16 12:04 ?318次閱讀

    TASKING編譯器是否可以將數(shù)據(jù)結(jié)構(gòu)設(shè)置為 \"打包\"?

    TASKING 編譯器是否可以將數(shù)據(jù)結(jié)構(gòu)設(shè)置為 \"打包\"? GCC 很早以前就提供了這種可能性,可以將__attribute__((packed))與對(duì)齊指令結(jié)合使用。 對(duì)于
    發(fā)表于 03-05 06:00

    矢量與柵格數(shù)據(jù)結(jié)構(gòu)各有什么特征

    矢量數(shù)據(jù)結(jié)構(gòu)和柵格數(shù)據(jù)結(jié)構(gòu)是地理信息系統(tǒng)(GIS)中最常用的兩種數(shù)據(jù)結(jié)構(gòu)。它們?cè)诖鎯?chǔ)和表示地理要素上有著不同的方法和特征。在接下來(lái)的文章中,我們將詳細(xì)介紹這兩種
    的頭像 發(fā)表于 02-25 15:06 ?2025次閱讀

    區(qū)塊鏈?zhǔn)鞘裁礃拥?b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)組織

    區(qū)塊鏈?zhǔn)且环N特殊的數(shù)據(jù)結(jié)構(gòu),它以分布式、去中心化的方式組織和存儲(chǔ)數(shù)據(jù)。區(qū)塊鏈的核心原理是將數(shù)據(jù)分布在網(wǎng)絡(luò)的各個(gè)節(jié)點(diǎn)上,通過(guò)密碼學(xué)算法保證數(shù)據(jù)的安全和可靠性。在區(qū)塊鏈上,
    的頭像 發(fā)表于 01-11 10:57 ?1571次閱讀

    C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之跳表詳解

    大家好,今天分享一篇C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)相關(guān)的文章--跳表。
    的頭像 發(fā)表于 12-29 09:32 ?765次閱讀
    C語(yǔ)言<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>之跳表詳解

    redis數(shù)據(jù)結(jié)構(gòu)的底層實(shí)現(xiàn)

    Redis是一種內(nèi)存鍵值數(shù)據(jù)庫(kù),常用于緩存、消息隊(duì)列、實(shí)時(shí)數(shù)據(jù)分析等場(chǎng)景。它的高性能得益于其精心設(shè)計(jì)的數(shù)據(jù)結(jié)構(gòu)和底層實(shí)現(xiàn)。本文將詳細(xì)介紹Redis常用的
    的頭像 發(fā)表于 12-05 10:14 ?555次閱讀

    不同數(shù)據(jù)結(jié)構(gòu)的定義代碼

    數(shù)據(jù)結(jié)構(gòu)是相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。
    的頭像 發(fā)表于 11-29 14:13 ?584次閱讀

    python列表和數(shù)組的區(qū)別

    Python是一種功能強(qiáng)大的編程語(yǔ)言,為開(kāi)發(fā)者提供了許多數(shù)據(jù)結(jié)構(gòu)來(lái)處理和操作數(shù)據(jù)。其中,列表和數(shù)組是常用的數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)和組織一系列元素
    的頭像 發(fā)表于 11-21 15:13 ?2112次閱讀

    redis的數(shù)據(jù)結(jié)構(gòu)一般分為哪幾種?

    緩存、計(jì)數(shù)器、分布式鎖等。字符串類型支持很多操作,如設(shè)置、獲取、刪除、追加等。 哈希表(Hashes): 哈希表是 Redis 提供的一個(gè)鍵值對(duì)的數(shù)據(jù)結(jié)構(gòu),它類似于一個(gè)字典,可以存儲(chǔ)多個(gè)字段和值的映射關(guān)系。哈希表適用于存儲(chǔ)對(duì)象,每個(gè)字段代表對(duì)象的一個(gè)屬性,而值則存
    的頭像 發(fā)表于 11-16 11:19 ?390次閱讀

    redis的五種數(shù)據(jù)類型底層數(shù)據(jù)結(jié)構(gòu)

    Redis是一種內(nèi)存數(shù)據(jù)存儲(chǔ)系統(tǒng),支持多種數(shù)據(jù)結(jié)構(gòu)。這些數(shù)據(jù)結(jié)構(gòu)不僅可以滿足常見(jiàn)的存儲(chǔ)需求,還能夠通過(guò)其底層數(shù)據(jù)結(jié)構(gòu)提供高效的操作和查詢。以下是Redis中常用的五種
    的頭像 發(fā)表于 11-16 11:18 ?648次閱讀

    無(wú)鎖CAS如何實(shí)現(xiàn)各種無(wú)鎖的數(shù)據(jù)結(jié)構(gòu)

    ,可用于在多線程編程中實(shí)現(xiàn)不被打斷的數(shù)據(jù)交換操作,從而避免多線程同時(shí)改寫某?數(shù)據(jù)時(shí)由于執(zhí)行順序不確定性以及中斷的不可預(yù)知性產(chǎn)?的數(shù)據(jù)不一致問(wèn)題 有了CAS,我們就可以用它來(lái)實(shí)現(xiàn)各種無(wú)鎖
    的頭像 發(fā)表于 11-13 15:38 ?687次閱讀
    無(wú)鎖CAS如何實(shí)現(xiàn)各種無(wú)鎖的<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>

    ringbuffer數(shù)據(jù)結(jié)構(gòu)介紹

    最近在研究srsLTE的代碼,其中就發(fā)現(xiàn)一個(gè)有意思的數(shù)據(jù)結(jié)構(gòu)------ringbuffer。 雖然,這是一個(gè)很基本的數(shù)據(jù)結(jié)構(gòu),但時(shí),它在LTE這種通信協(xié)議棧系統(tǒng)中卻大行其道,也是很容易被協(xié)議
    的頭像 發(fā)表于 11-13 10:44 ?1432次閱讀
    ringbuffer<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>介紹

    epoll的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

    一、epoll的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu) 在開(kāi)始研究源代碼之前,我們先看一下 epoll 中使用的數(shù)據(jù)結(jié)構(gòu),分別是 eventpoll、epitem 和 eppoll_entry。 1、eventpoll 我們
    的頭像 發(fā)表于 11-10 10:20 ?707次閱讀
    epoll的基礎(chǔ)<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>

    Linux內(nèi)核中使用的數(shù)據(jù)結(jié)構(gòu)

    Linux內(nèi)核代碼中廣泛使用了數(shù)據(jù)結(jié)構(gòu)和算法,其中最常用的兩個(gè)是鏈表和紅黑樹(shù)。 鏈表 Linux內(nèi)核代碼大量使用了鏈表這種數(shù)據(jù)結(jié)構(gòu)。鏈表是在解決數(shù)組不能動(dòng)態(tài)擴(kuò)展這個(gè)缺陷而產(chǎn)生的一種數(shù)據(jù)結(jié)構(gòu)。鏈表所
    的頭像 發(fā)表于 11-09 14:24 ?415次閱讀
    Linux內(nèi)核中使用的<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>