■閉鎖した昔のブログの記事復活
[2025/05/12] VB.NET:スレッドタイマ(System.Threading.Timer)を使った割込み処理について (No.408)
[2025/05/12] SQL Server:BCPでUnicode文字形式を使用したデータのインポート及びエクスポート(SQL Server)について (No.407)
[2025/05/12] VB.NET:配列は参照型?について (No.406)
[2025/05/12] VB.NET:値型と参照型について (No.405)
[2025/05/12] VB.NET:文字列型(String)について (No.404)
[2025/05/12] SQL Server:BCPでUnicode文字形式を使用したデータのインポート及びエクスポート(SQL Server)について (No.407)
[2025/05/12] VB.NET:配列は参照型?について (No.406)
[2025/05/12] VB.NET:値型と参照型について (No.405)
[2025/05/12] VB.NET:文字列型(String)について (No.404)
-
VB.NETのコンソールプログラムでのタイマ割込み処理を行う場合、 スレッドタイマ(System.Threading.Timer)を使った方法があります。
フォームを持ったプログラムの場合には、Windowsタイマ(System.Windows.Forms.Timer)を 使えば簡単に割込み処理ができます。フォームにWindowsタイマのコントロールを張り付けて 各種のプロパティを設定すればOKです。
ただ、コンソールプログラムではフォームが無い場合が普通です。 そのため、タイマコントロールとは違う、スレッドタイマを使います。 以下のソースを見てください。
Main関数の処理の最初で、タイマイベント用の関数を宣言しています。 この関数はタイマ割込みが発生した時に実行する関数で、
次の行で生成されるタイマスレッドから実行されるデリゲートです。 タイマの間隔は1000msecに設定しています。
タイマイベントの関数では、タイマ割込みが在った証拠のフラグをONしているだけで、 メイン側ではそのフラグのONを見て、対応する処理を行っています。 例としては、現在時刻を表示しているだけです。
無限ループの中で、Sleep関数で待ち時間を使っています。 このSleep関数の行が無い状態でこのプログラムを実行すると、 CPU時間が非常に多く割かれてしまいます。 Sleepを入れることで、CPU時間はほぼ0%に近くなるはずです。
Module Test 'タイマ処理フラグ Private mblnTimning As Boolean = False 'タイマ Private mTimer As System.Threading.Timer ' 値渡し・参照渡しのテスト Public Sub Main() 'タイマイベントの関数 Dim timerDelegate As System.Threading.TimerCallback = _ New System.Threading.TimerCallback(AddressOf TimerEvent) 'タイマの生成と開始(1000msec毎のイベント呼び出し) mTimer = New System.Threading.Timer(timerDelegate, Nothing, 0, 1000) '無限ループ While True 'タイマ処理フラグONの確認 If mblnTimning = True Then 'タイマ処理フラグOFF mblnTimning = False '処理の例として時刻表示 Console.WriteLine(String.Format("Time = {0}", Now.ToString)) End If '10msecの待ち処理(システムに処理を返す) System.Threading.Thread.Sleep(10) End While End Sub ' タイマイベント Public Sub TimerEvent(ByVal aobj As Object) 'タイマ処理フラグON mblnTimning = True End Sub End Module
このソースは無限ループの処理になっていて、無限ループを抜ける処理については 考えていませんので、何か対策が必要です。
無限ループの方法はあまりスマートでは無いのですが、常駐させる様なプログラムでは有効ではないでしょうか。
=====
2016/02/23:の時の情報
PR -
以前の記事の中で「SQL Server」の「BCP」コマンドを取り上げましたが、 その時のコマンドは以下の様になっていました。 このコマンドは出力されるファイルが文字形式として書き込まれます。 (データベースの中のネイティブ形式ではないということです)
bcp TEST.dbo.TABLE_A out "table_a.txt" -c -Slocalhost\SQLEXPRESS -T
このコマンドで出力されるテキストファイルのコードは「Shift-JIS」形式になるはずです。
これに対応するインポートコマンドは同様に「-c」オプションをつけて以下の様になります。bcp TEST.dbo.TABLE_A in "table_a.txt" -c -Slocalhost\SQLEXPRESS -T
今回はUnicodeでのインポート・エクスポートの必要がありましたので、「-c」オプションを「-w」に変えて行います。
以下はエキスポートコマンドです。bcp TEST.dbo.TABLE_A out "table_a.txt" -w -Slocalhost\SQLEXPRESS -T
このコマンドで出力されるテキストファイルのコードがUnicodeとなります。
以下はインポートコマンドです。bcp TEST.dbo.TABLE_A in "table_a.txt" -w -Slocalhost\SQLEXPRESS -T
=====
2016/02/17:の時の情報
-
「VB.NETの値型と参照型について」の記事で「参照型」には「配列」があると触れましたが、 今回はそのことを詳しく見ていきます。
まずは配列の宣言方法ですが、以下の様に定義できます。
Dim 配列名(指標上限値) As 各要素のデータ型
配列宣言の例としては以下の様になります。
3,4行目の配列の初期化を含む宣言の場合、「指標上限値」は省略する必要があります。
Dim intArr(4) As Integer Dim lngArr(5) As Long, dblArr(10) As Double, strArr(20) As String Dim nArr() As Integer = {1, 2, 3, 4, 5} '{}で括り初期値リストを記述(Integer型) Dim sArr() As String = {"AAA", "BBB", "CC"} '{}で括り初期値リストを記述(String型)
通常配列を扱う場合は、配列の添え字を指定して各要素のデータにアクセスします。 例えば以下の様な感じです。'配列宣言 Dim intArr(4) As Integer '各要素に適当な値を入れる intArr(0) = 1 intArr(3) = 2 '指標=3の要素を表示する Console.WriteLine(String.Format("intArr(3) = {0}", intArr(3))) 'intArrの要素を各指標値に設定する For i As Integer = LBound(intArr) To UBound(intArr) intArr(i) = i Next
「LBound」「UBound」は配列の指標の最小値及び最大値を返す関数です。 配列の全てを処理する場合、この関数を使うほうがバグが出にくいと思います。
そこで参照型であることを説明するために以下のソースを見てください。
'配列宣言(指標MAX指定) Dim intArr(4) As Integer 'intArrの要素を各指標値に設定する For i As Integer = LBound(intArr) To UBound(intArr) intArr(i) = i Next '配列宣言(指標指定無し) Dim intArr2() As Integer '配列の参照の枠のみ intArr2 = intArr '配列の参照コピー For i As Integer = LBound(intArr2) To UBound(intArr2) Console.WriteLine(String.Format("intArr2(" & i & ") = {0}", intArr2(i))) Console.WriteLine(String.Format("intArr (" & i & ") = {0}", intArr(i))) Next
このソースで表示される結果からわかるように、 「intArr2」と「intArr」が示すデータは全く同じものになります。 「intArr2」に「intArr」をコピーしているので当然なのですが、 「intArr」の配列の実体は5個のInteger型のデータの並びなのですが、 それを参照しているものが「intArr」の変数の中身なのです。 図で示すと以下の様な感じです。
更に以下のソースを見てください。 「intArr」を宣言後、要素にデータを設定し、その後で「intArr」に「Nothing」を入れています。
'配列宣言(指標MAX指定) Dim intArr(4) As Integer 'intArrの要素を各指標値に設定する For i As Integer = LBound(intArr) To UBound(intArr) intArr(i) = i Next '参照をクリアする intArr = Nothing 'エラーが発生する部分 Console.WriteLine(String.Format("intArr(0) = {0}", intArr(0)))
これを実行すると最後のコンソール出力の行でエラーが発生します。 「intArr」が指し示していた内容がクリアされたため、 最初に宣言したときの配列の実体への参照が出来なくなっているからです。
このことから、配列の変数も、クラス変数と同様な感じが分かると思います。
=====
2016/01/30:の時の情報
-
VB.NETで変数として宣言できるデータ型は大きく分けて「値型」と「参照型」に分けられます。 「参照型」は、初めてVB.NETを使い始めた方にとっては、なかなか理解しにくい部分でもあります。 かく言う私もそのひとりではありますが。
「値型」は変数としてよく使う、Integer、Double、Decimal、DateTime及び構造体、列挙型などで、 「参照型」はクラス、配列などです。
「値型」のInteger、Doubleなどは直感的に分かりやすいのですが、 「参照型」の実際はどうなのか理解しにくいものです。
「値型」とは変数を保持しているメモリ上に直接データをアクセスできるもので、 「参照型」とはその変数に保持しているのは、参照型データの実体を指し示すポインタ的なものです。
言葉で説明すると何のことか分かりにくいので 「値型」と「参照型」を比較する為、構造体とクラスで説明します。
以下の様な構造体とクラスを宣言します。
'テスト用構造体宣言 Structure StrucTest Public nTest As Integer 'Publicなメンバ変数 End Structure 'テスト用クラス宣言 Class ClassTest Public nTest As Integer 'Publicなメンバ変数 End Class
このテスト用構造体を以下の様に使います。 このソースを適当なところで入力し、デバッグモードで1行ずつ実行させると分かりやすいです。
'構造体のテスト Dim ST1 As StrucTest '構造体「ST1」の宣言 ST1.nTest = 1 'メンバ変数「nTest」に1を設定 Dim ST2 As StrucTest '構造体「ST2」の宣言 ST2 = ST1 '「ST1」の内容を「ST2」にコピー ST2.nTest = 2 'メンバ変数「nTest」に2を設定 'クラスのテスト Dim CT1 As ClassTest 'クラス「CT1」の宣言 CT1 = New ClassTest 'クラスの実体を生成し「CT1」に代入 CT1.nTest = 1 'メンバ変数「nTest」に1を設定 Dim CT2 As ClassTest 'クラス「ST2」の宣言 CT2 = CT1 '「CT1」の内容を「CT2」にコピー CT2.nTest = 2 'メンバ変数「nTest」に2を設定
構造体のテストでは、1行目で構造体「ST1」の宣言をしていますが、この時点で「ST1」の実体がメモリに確保されます。 宣言の後で直接「ST1」のメンバ変数「nTest」に1を設定します。
その後で構造体「ST2」の宣言し、「ST2」に「ST1」を代入していますが、 「ST2」に割り当てられた実体に「ST1」の全てがまるまるコピーされます。
「ST2」と「ST1」の実体は全く別の独立したメモリ領域に存在していますので、 「ST2」のメンバ変数「nTest」に2を設定しても、「ST1.nTest」および「ST2.nTest」は異なる値を保持しています。
クラスのテストでは、1行目でクラス「CT1」の宣言をしていますが、この時点ではCT1には実体は設定しておらず、 値的には「Nothing」になっています。尚、値が「Nothing」である参照型の変数のメソッドやプロパティにアクセスしても エラーが発生します。
その後の「New」を行うことで、「ClassTest」の実体がメモリに確保され、その参照が「CT1」に代入されます。 参照とはメモリに確保された「ClassTest」の入れ物を指し示すポインタの様なものです。
この時点で「CT1」のメンバ変数にアクセスが可能になります。
クラスのテストでは、4行目でクラス「CT2」の宣言を行いますが、当然「CT2」の中身は「Nothing」のままです。 ここで5行目で「CT2」に「CT1」の値をコピーしています。 値のコピーと言っても、中身は「ClassTest」の実体メモリへの参照する値です。
(「ClassTest」の入れ物を指し示すポインタのコピー)
最後の行で「CT2」を使って「CT2.nTest」へ2を設定しています。 ここで「CT1」の値をデバッガ等でみますと「2」になっているはずです。 参照型を初めて見る方にとっては、おやと思うでしょうが、 「CT2」も「CT1」もメモリ上の同じ場所を指し示しているので、 「CT1.nTest」で見ても「CT2.nTest」で見ても同じ値になります。
尚、クラス宣言と実体生成を以下の様に記述できます。 「CT2」もNewで生成すれば、全く別のクラス領域を指し示すことになりますので、 「CT1.nTest」と「CT2.nTest」は別の値になります。
'クラスのテスト2 Dim CT1 As New ClassTest 'クラス「CT1」の実体を生成し「CT1」に代入 CT1.nTest = 1 'メンバ変数「nTest」に1を設定 Dim CT2 As New ClassTest 'クラス「CT2」の実体を生成し「CT2」に代入 CT2.nTest = 2 'メンバ変数「nTest」に2を設定
=====
2016/01/28:の時の情報
-
プログラミングにおいて文字列型「String」はいろんな場面で使います。 名前を表示する時に使ったり、数値を文字列型で退避したりと枚挙に暇がありません。
この「String」ですがよく使う数値型のInteger型やDouble型、Decimal型などとは性格が異なり内部的には「クラス」の扱いなのです。 「クラス」は変数を宣言してもその変数を初期化(インスタンス化)しないと、その「クラス」のプロパティやメソッドが使えません。 使えないというか、インスタンス化されていない「クラス」のプロパティにアクセスするとその時点でエラーが発生します。 以下はエラーの発生するソースの例です。
Dim str As String Dim nLen As Integer nLen = str.Length 'エラーが発生します
変数 str を初期化せずにString型のLengthプロパティを使うとエラーが発生します。 「NullReferenceException」エラーが発生します。(NULLであるオブジェクトを参照したというエラー)
このエラーを回避するには、文字列型の宣言するところで初期化(空文字を代入する)を行ってから、プロパティやメソッドを使います。 また、文字列長のみ知りたいのであれば、標準で備わっている「Len」関数を使います。
Dim str As String Dim nLen As Integer nLen = Len(str) 'Microsoft.VisualBasic.Stringsモジュール内関数 Dim str2 As String = "" '文字列の初期化 nLen = str2.Length 'エラーは発生しません
Microsoft.VisualBasic.Stringsモジュールには昔のBasicを引きずった関数がいろいろありますが、 その関数を使うか、文字列のクラスのメソッドを使うかは好みの問題かと思います。 今後は「String」クラスの「Substring」メソッドを使うのが主流になるとは思います。
但し、「Left」「Right」「Mid」の関数は昔から便利だったので結構使いたくなります。 これらの関数の「String」クラスの「Substring」メソッドでの方法を以下に記します。
Dim str As String = "0123456789" Dim str2 As String = "" 'Microsoft.VisualBasicモジュール関数 str2 = Microsoft.VisualBasic.Left(str, 2) '"01" str2 = Microsoft.VisualBasic.Right(str, 2) '"89" str2 = Microsoft.VisualBasic.Mid(str, 2, 3) '"123" 'Substringメソッド使用 str2 = str.Substring(0, 2) 'Left(str, 2) str2 = str.Substring(str.Length - 2, 2) 'Right(str, 2) str2 = str.Substring(1, 3) 'Mid(str, 2, 3)
=====
2016/01/28:の時の情報