在我的第一套VBA教程《VBA代碼解決方案》中曾經講過一個準數據庫的操作,那里曾經將txt文件作為一個數據庫的文件給大家講解。確實,在實際的工作中很多場合都會利用到txt文件。這種文件很小但功能強大。很多格式的文件都可以利用這種文件進行打開、編輯。這也給我們編程人員以很多的遐想空間。比如這講,我們就將把一些EXCEL數據輸出到txt中,為什么要輸出到這種文件類型中呢?我們知道在電子表格文件中,默認是有表格的,而在txt中沒有這種表格,從而有利于我們對文本的操作。
從excel中的數據輸出,我在第一套教程中也有講解,那時的講解是面向初級人員的,對于代碼,對于邏輯的嚴謹性沒有更高的要求,這套教程的內容是面向中、高級人員的,同樣的過程,實現的方式要有所提高。
為了實現數據的輸出,我在上一講專門講解了必要的知識點。我們這講就將把這些知識點串起來。要實現文件的輸出在這講中將利用一個自定義函數來實現,這個函數中將包含我們需要的一些設置。
1) 文件名,輸出后形成一個什么名字的文件,這個文件保存在哪里,需要指定。
2) 分隔符號,由于在電子表格中,數據是有行列定位的,而在txt文件中只有行的顯示,列的分隔符號需要用戶提供。
3) 輸出的范圍,是整個文檔還是選擇的區域要求用戶指定。
4) 輸出的時候,對于指定的文件是追加數據還是將原有數據去除也是需要用戶來設置的。
有了這些參數的設置后,我們定義的函數就可以實現了。
首先是要對導出區域進行判斷;然后是對輸出文件是否是追加寫入的判斷;最后從數據區域中提取數據進行數據的輸出。
為了實現上述思路,我給出我的代碼:
Public Sub ExportToTextFile(FName As String, Sep As String, SelectionOnly As Boolean, AppendData As Boolean)
Application.ScreenUpdating=False
'FreeFile返回一個Integer,代表下一個可供OPEN語句使用的文件號可獲得尚未被占用的文件號中的頭一個,
'參數范圍可以是0或1,也可以省略
FNum=FreeFile
'選擇區域的導出
If SelectionOnly=True Then
With Selection
StartRow=.Cells(1).Row
StartCol=.Cells(1).Column
EndRow=.Cells(.Cells.Count).Row
EndCol=.Cells(.Cells.Count).Column
End With
Else
'使用區域的導出
With ActiveSheet.UsedRange
StartRow=.Cells(1).Row
StartCol=.Cells(1).Column
EndRow=.Cells(.Cells.Count).Row
EndCol=.Cells(.Cells.Count).Column
End With
End If
'追加寫入
If AppendData=True Then
Open FName For Append Access Write As #FNum
Else
'新文件寫入
Open FName For Output Access Write As #FNum
End If
For RowNdx=StartRow To EndRow
'每一行數據的提取
WholeLine=""
For ColNdx=StartCol To EndCol
If Cells(RowNdx, ColNdx).Value="" Then
CellValue=Chr(34) &Chr(34)
Else
CellValue=Cells(RowNdx, ColNdx).Value
End If
WholeLine=WholeLine&CellValue& Sep
Next
WholeLine=Left(WholeLine, Len(WholeLine) - Len(Sep))
'行數據寫入
Print #FNum, WholeLine
Next
Application.ScreenUpdating=True
Close #FNum
End Sub
Sub mynzA()
Sheets("Sheet2").Select
ExportToTextFileFName:=ThisWorkbook.Path& "文本輸出.txt", Sep:=";", _
SelectionOnly:=False, AppendData:=True
'ExportToTextFileFName:=ThisWorkbook.Path& "文本輸出.txt", Sep:=";", _
SelectionOnly:=True, AppendData:=True
MsgBox ("輸出OK!")
End Sub
代碼的部分截圖:
代碼講解:
1)FNum=FreeFile
代碼FreeFile函數返回一個Integer,代表下一個可供OPEN語句使用的文件號可獲得尚未被占用的文件號中的頭一個,此函數的參數范圍可以是0或1,也可以省略,這里是省略的。
2)If SelectionOnly=True Then
With Selection
StartRow=.Cells(1).Row
StartCol=.Cells(1).Column
EndRow=.Cells(.Cells.Count).Row
EndCol=.Cells(.Cells.Count).Column
End With
如果是選擇區域的數據導出設置導出的范圍
3)'使用區域的導出
With ActiveSheet.UsedRange
StartRow=.Cells(1).Row
StartCol=.Cells(1).Column
EndRow=.Cells(.Cells.Count).Row
EndCol=.Cells(.Cells.Count).Column
End With
End If
如果是整個文件的導出,給出上述的區域范圍
4)'追加寫入
If AppendData=True Then
Open FName For Append Access Write As #FNum
Else
'新文件寫入
Open FName For Output Access Write As #FNum
End If
以上代碼根據用戶指定的AppendData給出Open 語句的寫法。
5)For RowNdx=StartRow To EndRow
'每一行數據的提取
WholeLine=""
For ColNdx=StartCol To EndCol
If Cells(RowNdx, ColNdx).Value="" Then
CellValue=Chr(34) &Chr(34)
Else
CellValue=Cells(RowNdx, ColNdx).Value
End If
WholeLine=WholeLine&CellValue& Sep
Next
WholeLine=Left(WholeLine, Len(WholeLine) - Len(Sep))
'行數據寫入
Print #FNum, WholeLine
Next
以上代碼是將數據導出,這里要注意利用的語句是Print #FNum, WholeLine這句的意義我們在上一講已經講解過來。在每個單元格的值利用了Sep進行分隔,同時將每行最后的分隔符進行了去除。
6)
ExportToTextFileFName:=ThisWorkbook.Path& "文本輸出.txt", Sep:=";", _
SelectionOnly:=False, AppendData:=True
'ExportToTextFileFName:=ThisWorkbook.Path& "文本輸出.txt", Sep:=";", _
SelectionOnly:=True, AppendData:=True
在主代碼過程中上述語句實現了不同參數的測試過程,當然用戶也可以選擇讓用戶自己在程序的運行中輸入參數來解決。代碼在更改的時候利用的是inputbox語句即可實現。
例如:
FileName=Application.GetSaveAsFilename(InitialFileName:=vbNullString, FileFilter:="Text Files (*.txt),*.txt")
If FileName=False Then
Msgbox"請指定文件"
Exit Sub
End If
Sep=Application.InputBox("請錄入分隔符號", Type:=2)
If Sep=vbNullString Then
Msgbox"請指定間隔符號"
Exit Sub
End If
ExportToTextFileFName:=CStr(FileName), Sep:=CStr(Sep),SelectionOnly:=False, AppendData:=True
我們先看看工作表中的數據截圖:
然后點擊運行按鈕:
這樣就實現了將EXCEL中的信息輸出到文本文件的目的。
本節知識點回向:
1 如何實現數據的文本輸出?
② 對于自定義參數的設置還有什么方法?
本講代碼參考文件:016工作表.xlsm
在我的系列書籍中一直在強調"搭積木"的編程思路,這也是學習利用VBA的主要方法,特別是職場人員,更是要采用這種方案。其主要的內涵:
1 代碼不要自己全部的錄入。你要做的是把積木放在合適的位置然后去修正代碼,一定要拷貝,從你的積木庫中去拷貝,然后修正代碼,把時間利用到高效的思考上。
2 建立自己的"積木庫"。平時在學習過程中,把自己認為有用的代碼放在一起,多積累,在用到的時候,可以隨時拿來。你的積木庫資料越多,你做程序的思路就會越廣。
VBA是利用Office實現個人小型辦公自動化的有效手段(工具)。這是我對VBA的應用界定。在取代OFFICE新的辦公軟件沒有到來之前,誰能在數據處理方面做到極致,誰就是王者。其中登峰至極的技能非VBA莫屬!
我記得20年前自己初學VBA時,那時的資料甚少,只能看源碼自己琢磨,真的很難。20年過去了,為了不讓學習VBA的朋友重復我之前的經歷,我根據自己多年VBA實際利用經驗,推出了六部VBA專門教程,目前教程均通過32位和64位兩種OFFICE系統測試。
第一套:VBA代碼解決方案 是VBA中各個知識點的講解,教程共147講,覆蓋絕大多數的VBA知識點,提供的程序文件更是一座不可多得的代碼寶庫,是初學及中級人員必備教程;目前這套教程提供的版本是修訂第二版,程序文件通過32位和64位兩種OFFICE系統測試。
第二套:VBA數據庫解決方案 數據庫是數據處理的專業利器,教程中詳細介紹了利用ADO連接ACCDB和EXCEL的方法和實例操作,適合中級人員的學習。目前這套教程提供的是修訂第一版教程,程序文件通過32位和64位兩種OFFICE系統測試。
第三套:VBA數組與字典解決方案 數組和字典是VBA的精華,字典是VBA代碼水平提高的有效手段,值得深入的學習,是初級及中級人員代碼精進的手段。目前這套教程提供的版本是修訂第一版,程序文件通過32位和64位兩種OFFICE系統測試。
第四套:VBA代碼解決方案之視頻 是專門面向初學者的視頻講解,可以快速入門,更快的掌握這門技能。這套教程是第一套教程(修訂一版)的視頻講解,聽元音更易接受。這套教程還會額外提供通過32位和64位兩種OFFICE系統測試的程序文件。
第五套:VBA中類的解讀和利用 這是一部高級教程,講解類的虛無與肉身的度化,類的利用雖然較少,但仔細的學習可以促進自己VBA理論的提高。這套教程的領會主要是讀者的領悟了,領悟一種佛學的哲理。目前這套教程提供的版本是修訂第一版,程序文件通過32位和64位兩種OFFICE系統測試。
第六套教程:《VBA信息獲取與處理》,這是一部高級教程,涉及范圍更廣,實用性更強,面向中高級人員。教程共二十個專題,包括:跨應用程序信息獲得、隨機信息的利用、電子郵件的發送、VBA互聯網數據抓取、VBA延時操作,剪切板應用、Split函數擴展、工作表信息與其他應用交互,FSO對象的利用、工作表及文件夾信息的獲取、圖形信息的獲取以及定制工作表信息函數等等內容。程序文件通過32位和64位兩種OFFICE系統測試。
上述教程的學習順序:1→3→2→6→5或者4→3→2→6→5。提供的程序文件更是一座巨大的代碼庫,供讀者使用,如需要可以WeChat: NZ9668
"眾鳥高飛盡,孤云獨去閑。相看兩不厭,只有敬亭山"。學習的過程也是修心的過程,修一個平靜的心。在代碼的世界中,心平靜了,心情好了,身體自然而然就好。心靜則正,內心里沒有那么多邪知邪見,也就沒有那么多妄想。利人就是利己。我的教程助力給正在努力的朋友。
"水善利萬物而不爭",綿綿密密,微則無聲,巨則洶涌。學習亦如此,知道什么是自己所需要的,不要蜷縮在一小塊自認為天堂的世界里,待到暮年時再去做自欺欺人的言論。要努力提高自己,用一顆充滿生機的心靈,把握現在,這才是進取。越是有意義的事情,困難會越多。愿力決定始終,智慧決定成敗。不管遇到什么,都是風景。看淡紛爭,看輕得失。學習時微而無聲,利用時則巨則洶涌。"路漫漫其修遠兮,吾將上下而求索"
每一分收獲都是成長的記錄,怎無憑,正是這種執著,成就了朝霞的燦爛。最后將一闕詞送給致力于VBA學習的朋友,讓大家感受一下學習過程的枯燥與執著:
浮云掠過,暗語無聲,
唯有清風,驚了夢中啼鶯。
望星,疏移北斗,
奈將往事雁同行。
阡陌人,昏燈明暗,
忍顧長亭。
多少VBA人,
暗夜中,悄聲尋夢,盼卻天明。
怎無憑!
分享我多年工作實際經驗的成果,隨喜這些有用的東西,給確實需要利用VBA的同路人。回向學習利用VBA的歷歷往事,不勝感慨,謹以這些文字以紀念,
分享成果,隨喜正能量
開始 RT-Thread 內核學習之前,先來體驗一下 RT-Thread。
要體驗 RT-Thread,首先需要具備運行環境或者實驗環境。RT-Thread 不僅可以在實際硬件平臺上運行,也可以在虛擬環境下實驗運行。
如果只是為了學習內核知識,并配合練習實驗,虛擬環境就可以了。如果有實際的硬件環境,當然會更好。
官方的學習資料中,介紹了兩種虛擬環境:
下面分別以這兩種環境體驗一下 RT-Thread 運行。
接著介紹了一下 RT-Thread 內核對象模型架構的基礎知識。
RT-Thread 提供了 QEMU 模擬的 ARM vexpress A9 開發板的板級支持包 (BSP)。
在 Windows 平臺即可運行 qemu-vexpress-a9 BSP 工程,但是需要先搭建 Env 開發環境,可以參考:
RT-Thread 學習-Env開發環境搭建
(備注:此處示例的源碼版本為 v4.0.2)
QEMU 模擬的 ARM vexpress A9 開發板的板級支持包 (BSP) 位于 RT-Thread 源碼 BSP 目錄下的 qemu-vexpress-a9 文件夾,其內容如下圖所示:
qemu-vexpress-a9 BSP 主要文件及目錄描述如下所示:
文件 / 目錄 | 描述 |
.vscode | vscode 配置文件 |
applications | 用戶應用代碼目錄 |
drivers | RT-Thread 提供的底層驅動 |
qemu.bat | Windows 平臺運行腳本文件 |
qemu.sh | Linux 平臺運行腳本文件 |
qemu-dbg.bat | Windows 平臺調試腳本文件 |
qemu-dbg.sh | Linux 平臺調試腳本文件 |
README.md | BSP 說明文件 |
rtconfig.h | BSP 配置頭文件 |
編譯運行
進入 bsp\qemu-vexpress-a9 文件夾,打開 Env 工具,輸入 scons 指令,開始編譯,編譯成功后如下圖:
編譯成功后,輸入qemu.bat,運行程序
Env 命令界面顯示 RT-Thread 系統過程中打印的信息,包括初始化信息和版本號信息等。
RT-Thread 支持 Finsh 功能,用戶調試和查看系統信息,用戶可以使用命令進行操作。輸入 help 或者按 tab 鍵可以查看系統支持的命令:
我們嘗試輸入指令 list_thread,顯示系統當前正在運行的線程,以及線程狀態和堆棧大小等信息:
Finsh 具有自動補全功能,輸入命令的部分字符,按下 Tab 鍵盤,則系統會根據當前已經輸入的字符,從系統中查找已經注冊好的相關命令。這個功能與 Linux 下的命令終端非常相似。
MDK-ARM 軟件中的軟件仿真模擬器,采用完全軟件模擬方式解釋執行 ARM 的機器指令,并實現外圍的一些外設邏輯,從而構成一套完整的虛擬硬件環境,使得用戶能夠不借助真實的硬件平臺就能夠在電腦上執行相應的目標程序。
RT-Thread 官方提供了一個示例工程,可以在模擬 STM32F103 的軟件仿真環境下運行。工程下載鏈接如下(由于微信不能添加外部鏈接,需要復制到瀏覽器打開):
https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/quick-start/stm32f103-simulator/stm32f103-simulator
下載完成后,解壓完成的目錄結構如下:
各個目錄所包含的文件類型的描述如下表所示:
目錄名 | 描述 |
applications | RT-Thread 應用程序文件。 |
rt-thread | RT-Thread 的源文件。 |
- components | RT-Thread 的各個組件目錄。 |
- include | RT-Thread 內核的頭文件。 |
- libcpu | 各類芯片的移植代碼,此處包含了 STM32 的移植文件。 |
- src | RT-Thread 內核的源文件。 |
- tools | RT-Thread 命令構建工具的腳本文件。 |
drivers | RT-Thread 的驅動,不同平臺的底層驅動具體實現。 |
Libraries | ST 的 STM32 固件庫文件。 |
kernel-sample-0.1.0 | RT-Thread 的內核例程。 |
雙擊 project.uvprojx 打開工程:
此示例工程,示例工程實現了一個模擬 LED 閃爍的功能函數,并用 RT-Thread 的宏 MSH_CMD_EXPORT 導出一個指令 led。在控制終端輸入 led ,可以運行這個函數。
編譯完成后,我們可以通過 MDK-ARM 的模擬器來仿真運行 RT-Thread,如下圖:
進入仿真頁面后,再按 F5 開始運行;然后點擊工具欄中的按鈕,或者選擇菜單欄中的“View→Serial Windows→UART#1”,打開串口 1 窗口,可以看到串口的輸出只顯示了 RT-Thread 的 LOGO,這是因為用戶代碼是空的,其模擬運行的結果如圖所示:
在提示符 msh> 后輸入 led,執行 LED 模擬閃爍的函數:
在以上兩種模擬運行 RT-Thread 實驗中,均提到了 FinSH。 那么 FinSH 到底是什么呢?
在此,只做簡單的介紹,達到了解的程度即可。隨著學習的深入,后期可以自己詳細地學習一下。
FinSH 是 RT-Thread 的命令行組件,類似于 Linux 下的 shell,提供了一套供用戶在命令行調用的操作接口,主要用于調試或查看系統信息,它可以使用串口、網口、USB 等與 PC 進行通信。
當使用串口連接設備與控制終端時,FinSH 命令的執行流程如圖:
用戶在控制終端輸入命令,控制終端通過串口、 USB、網絡等方式將命令傳給設備里的 FinSH, FinSH 會讀取設備輸入命令,解析并自動掃描內部函數表,尋找對應函數名,執行函數后輸出回應,回應通過原 路返回,將結果顯示在控制終端上 。
FinSH 支持自動補全、查看歷史命令等功能,通過鍵盤上的按鍵可以很方便的使用這些功能 。
為了方便學習 RT-Thread,我們下載標準版源碼。官方提供了源碼下載通道:
https://www.rt-thread.org/page/download.html
下載完成后,源碼目錄如下(注意,源碼存放路徑位置不能存在中文):
RT-Thread 源代碼目錄結構如下所示:
名稱 | 描述 |
BSP | Board Support Package(板級支持包)基于各種開發板的移植 |
components | RT-Thread 的各個組件代碼,例如 finsh,gui 等。 |
documentation | 相關文檔,如編碼規范等 |
examples | 相關示例代碼 |
include | RT-Thread 內核的頭文件。 |
libcpu | 各類芯片的移植代碼。 |
src | RT-Thread 內核的源文件。 |
tools | RT-Thread 命令構建工具的腳本文件。 |
RT-Thread 內核采用面向對象的設計思想進行設計,系統級的基礎設施都是一種內核對象,例如線程,信號量,互斥量,定時器等。
內核對象分為兩類:靜態內核對象和動態內核對象,靜態內核對象通常放在RW 段和 ZI 段中,在系統啟動后在程序中初始化;動態內核對象則是從內存堆中創建的,而后手工做初始化。
靜態對象會占用 RAM 空間,不依賴于內存堆管理器,內存分配時間確定。動態對象則依賴于內存堆 管理器,運行時申請 RAM 空間,當對象被刪除后,占用的 RAM 空間被釋放。
關于動態對象和靜態對象的創建,后面會進行介紹。
內核對象管理
RT-Thread 內核對象包括:線程,信號量,互斥量,事件,郵箱,消息隊列和定時器,內存池,設備 驅動等。對象容器中包含了每類內核對象的信息,包括對象類型,大小等。
對象容器給每類內核對象分配了一個鏈表,所有的內核對象都被鏈接到該鏈表上,如圖 RT-Thread 的內核對象容器及鏈表如下圖所示:
每一種具體的內核對象和對象控制塊,除了基本的結構外,還有自己的擴展屬性。
例如,對于線程控制塊,在基類對象基礎上進行擴展,增加了線程狀態、優先級等屬性。這些屬性在基類對象的操作中不會用到,只有在與具體線程相關的操作中才會使用。
從面向對象的角度來看,每一種具體對象是抽象對象的派生,繼承了基本對象的屬性,并在此基礎上擴展了與自己相關的屬性。 如下圖所示,各類內核對象的派生和繼承關系:
在對象管理模塊中,定義了通用的數據結構,用來保存各種對象的共同屬性,各種具體對象只需要在 此基礎上加上自己的某些特別的屬性,就可以清楚的表示自己的特征 。
這種設計方法的優點有:
(1)提高了系統的可重用性和擴展性,增加新的對象類別很容易,只需要繼承通用對象的屬性再加少 量擴展即可。
(2)提供統一的對象操作方式,簡化了各種具體對象的操作,提高了系統的可靠性。
OK,今天先到這,下次繼續。加油~