アプリ版:「スタンプのみでお礼する」機能のリリースについて

以下のコードを実行する度に、カウンター i の値がリセット(開放)されずに積算されて困っています。なぜか教えて下さい。宜しくお願い致します。

以下のコードは、簡単に言えばcsvファイルをカウンター i で数えています。したがって、少なくともCSVファイルを一つ作成して実行して下さい。

Option Explicit
Dim FiName As String, FoName As String
Dim EachFiName As String
Dim i As Integer
Sub Test()
MsgBox i '二回目にこのコードを実行するとiが積算されます。
FiName = Application.GetOpenFilename
If FiName = "False" Then
Exit Sub
Else
If Right(FiName, 3) <> "csv" Then
MsgBox "Chose a CSV file."
Exit Sub
End If
End If

FoName = Left(FiName, InStrRev(FiName, "\", -1, vbTextCompare))
EachFiName = Dir(FoName & "*.csv")
Do While EachFiName <> ""
i = i + 1
EachFiName = Dir()
Loop
End Sub

A 回答 (6件)

ご質問のコードの中には、i=0という記述が見当たりません。

function()が無いので、カウンタiがsub()以外のどこで使用されているかわかりませんが、リセットしたいイベント(タイミング)でゼロを代入してはいかがでしょうか。
    • good
    • 0

こんばんは。



理屈抜きに、i は、ローカル変数のカウンターだと考えて、モジュールレベル変数にしないのが、ふつうではありませんか?もし、残したかったら、別の変数に渡します。

それから、EachFiName,FiName,FoNameも、同じく、使用状況からするとローカル変数のようです。最終値が決まったら、必要に応じて、別のスコープの長い変数に渡します。

最初の、GetOpenFilename は、一応、こういうことでしょう。

 FiName = Application.GetOpenFilename("CSV ファイル(*.csv),*.csv")
  If FiName = "False" Then
   Exit Sub
  End If

>したがって、少なくともCSVファイルを一つ作成して実行して下さい。
なければ、CSVは、0 と出なくてはならないと思います。

だから、CSVの数を数えるということで、簡単に考えてみましたが、

Sub CSVFilesCounter()
  Dim myFolder As Object
  Dim FolderName As String
  Dim FileName As String
  Dim i As Long
  'デフォルト・パス
  Const DEF_FOLDER As String = "C:\"
  'フォルダ選択
  Set myFolder = CreateObject("Shell.Application"). _
  BrowseForFolder(0, "フォルダを選択してください", 0, DEF_FOLDER)
  If Not myFolder Is Nothing Then
      FolderName = myFolder.Items.Item.Path
   Else
     Exit Sub
  End If
 
  FileName = Dir(FolderName & "\" & "*.csv")
  Do While FileName <> ""
   i = i + 1
   FileName = Dir()
  Loop
 
  MsgBox FolderName & "\には、" & vbCrLf & i & " 個のCSVファイルがありました。", 64
End Sub
    • good
    • 0

MsgBox i '二回目にこのコードを実行するとiが積算されます。


        ↓
j = MsgBox(i & vbCrLf & "初期化しますか?",vbYesNo)
If j = vbYes Then i = 0
    • good
    • 0

Dim i As Integer'モジュールレベル変数



Sub Test()'テストプロシージャ
  ・・・・・・・
End Sub

この状態では、テストプロシージャを抜けても、モジュールレベル変数は開放されません。
開放されないと言うことは、設定された値が保持され続けると言うことです。

特に規約等の問題がない限りですが、カウンター値のような変数は、最小のスコープ(参照可能範囲)で宣言することが良いとされています。(個人的にはカウンター値以外にも、可能な限り最小スコープで宣言すべきと思っています)
具体例では、下記です。

↓削除でも構わないが、コメントアウトにしてみました
'Dim i As Integer

Sub Test()'テストプロシージャ
  Dim i As Integer  'カウンタ変数
  ・・・・・・・
End Sub

こうすると、テストプロシージャに入った時点で初めて、変数iが作成されVBA(VB)では、0に初期化されます。(.NETでは明示的に初期化が必要)
テストプロシージャを抜けた瞬間に、変数iはメモリ上から開放され、そのとき保持していた値は発散します。
読み込んだファイル数を保存する必要があり、発散されては困る、ということであれば(というより、わざわざ数えているのですからそうなのでしょうが)以下のように書き換えられます。

↓ファイル数を保存するという意味で、勝手に変数名を作成しました
Dim FileCount As Integer'発見したファイル数を保持する変数

Sub Test()'テストプロシージャ
  Dim i As Integer  'カウンタ変数
  ・・・・・・・
  FileCount = i    '発見したファイル数を退避させる
End Sub

プログラムがわかっている人から見れば、iが実は不要だ、とすぐにわかると思います。それでは試して見ましょう。

Dim FileCount As Integer'発見したファイル数を保持する変数

Sub Test()'テストプロシージャ
  FileCount = 0    'ファイル数をこれから確認するため、
 'その前0に初期化
  ・・・・・・・
  Do ・・・
    FileCount = FileCount + 1 'ファイルが見つかったため+1する
Loop
End Sub

最後のコードは元のコードと違う部分は、初期化しているかしていないか
他には変数名が変わっている、という違いです。
今回の初期化忘れというポカミスの原因は、小生の個人的意見ですが、変数名iが一番の原因であると思われるため、わざわざ回りくどく書きました。
ちなみに、ファイル数の確認だけであれば、小生はSubで書かずにFunctionで書いて、ファイル数を返り値として返す、というつくりにします。
    • good
    • 0

(1)i の初期化がないですね


(2)If FiName = "False" Thenは「えっ」と思ったが、 FiName が文字列の場合は、正しいらしいですね。
http://www.officetanaka.net/excel/vba/file/file0 …
(3)If FiName = "False" Then
Exit Sub
If FiName = "False" Then
Exit Sub
はこれで完結してますね。EndIfが要らないという意味で。
 そこで
Else
End If
End If
の位置付けはどうなっているのでしょうか。
誰もご指摘ないので、私の勘違いでしょうか。
If FiName = "False" Then Exit Sub
If Right(FiName, 3) <> "csv" Then 
MsgBox "Chose a CSV file."
Exit Sub
Else
End If
のように、Else が要りませんか。
私の普通やる書き方と違うので。
現状が正しく動くのなら、すみません。
    • good
    • 0

Dim 文をSub の中にいれて、


(いれなくても)Subの頭書で、i=0 とかしたりして
MsgBox i
を頭でなく最後にもってきたらどうでしょうか
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています