固定長の読込について2


相原  2007-01-28 03:12:03  No: 135034

先日質問させていただきました。相原です。
固定長の読込について教えていただき実際テストしてみたのですが、
うまくいかないので再度質問させていただきます。

Public Class Form1

    Structure DataCell
        <VBFixedArray(1)> Public a() As Byte
        <VBFixedArray(1)> Public b() As Byte
        <VBFixedArray(1)> Public c() As Byte
        <VBFixedArray(1)> Public kaigyou() As Byte
    End Structure

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim I As Integer
        Dim FileNum As Integer = FileSystem.FreeFile
        FileSystem.FileOpen(FileNum, "c:\test.txt", OpenMode.Random, , , Len(New DataCell()))

        Dim pos() As DataCell

        I = 0
        Do While Not EOF(FileNum)
            ReDim pos(I)
            FileSystem.FileGet(FileNum, pos(I))
            I = I + 1
        Loop

        FileSystem.FileClose()
    End Sub

End Class

読み込むデータは
------------
SSKKJJ
AABBCC
IIFFSS
------------
の3行とします。

この場合、読み込んだ後、pos(0).bには"KK"が入っていてほしいの
ですが、結果はNOTHINGになってしまいます。
一応、分からないなりに本やWEBをみながらやっているのですが、
本当に分からなくて困っています。
宜しくお願いいたします。


大吉末吉  2007-01-28 03:57:44  No: 135035

> 結果はNOTHINGになってしまいます。
>             ReDim pos(I)

前回の魔界の仮面弁士  さんのアドバイス
http://madia.world.coocan.jp/cgi-bin/VBBBS/wwwlng.cgi?print+200701/07010039.txt

---------------------------------------------------------
> >> ReDim pos(I)
> 配列確保時に Preserve していないので、これだと、
> ループのたびに配列の内容がクリアされてしまいますよ。
---------------------------------------------------------

に対して、

---------------------------------------------------------
> また、ReDimの件など、ご指摘頂き、大変助かりました。
---------------------------------------------------------

と返答されていたんじゃないんですか?

ひょっとして、理解できなかったんですか?
#だったら、「どういう意味でしょう」と尋ねるのが普通では・・・


大吉末吉  2007-01-28 04:15:17  No: 135036

追記

それとも、「Preserveはやってみたが、それでも上手くいかなかった。」
ってことでしょうか?
#それで、とりあえず「Preserveは外してみた」とか?

> 結果はNOTHINGになってしまいます
は、どうやって確認しました?

別のプロシージャから参照しようとしているのだとすると、変数のスコープの問題かもしれませんね。

どういうことかというと、
>         Dim pos() As DataCell
は、プロシージャ「Sub Button1_Click」の中で宣言されていので、「プロシージャ スコープ 」になります。
「ローカル変数」は、プロシージャが終了すると破棄されてしまいますし、他のプロシージャからは参照できません。
その場合は「モジュール スコープ 」の変数にしてください。

「スコープのレベル」
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/vbcn7/html/vbconscopelevels.asp

#ちなみに「Preserve」は絶対に必要ですよ。


相原  2007-01-28 05:14:12  No: 135037

すみません。ReDimを理解していなかったわけではないのですが、
いろいろ試していて、最終的にReDimを付け加えるのを忘れていました。
申し訳ありません。以後、気をつけたいと思います。

ところで、もう一点、あつかましいとは思いますが、教えていただけないでしょうか?

構造体の入れ子についてです。たとえば固定長を読み込んで、その1行が
ヘッダと明細になっているものとします。
--------------------------------
00001000020000001000030000005
00002000040000005000050000007
--------------------------------

ヘッダのコードが5バイト、その中に明細のコードが5バイトと数量7バイトが
2つ書かれているものとします。

Public Class Form1

    Structure DataCell
        <VBFixedArray(4)> Public code() As Byte
        <VBFixedArray(11)> Public DataCell_Meisai() As Byte
        <VBFixedArray(1)> Public kaigyou() As Byte
    End Structure

    Structure DataCell_Meisai
        <VBFixedArray(4)> Public code() As Byte
        <VBFixedArray(6)> Public suryo() As Byte
    End Structure

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim I As Integer
        Dim FileNum As Integer = FileSystem.FreeFile
        FileSystem.FileOpen(FileNum, "c:\test.txt", OpenMode.Random, , , Len(New DataCell()))

        Dim pos() As DataCell

        I = 0
        Do While Not EOF(FileNum)
            ReDim pos(I)
            FileSystem.FileGet(FileNum, pos(I))
            I = I + 1
        Loop

        FileSystem.FileClose()
    End Sub

End Class

この場合、
pos(0).DataCell_Meisai(0).codeに00002が入ってほしいのですが、
'code'は'Byte'のメンバーではありませんというエラーが出てしまいます。

正しい記述を教えていただけないでしょうか?


相原  2007-01-28 05:29:34  No: 135038

すみません。ReDimはちゃんとつけてます・・・・


モーヲタ  2007-01-28 06:24:43  No: 135039

>pos(0).DataCell_Meisai(0).codeに00002が入ってほしいのですが、
>'code'は'Byte'のメンバーではありませんというエラーが出てしまいます。
当然でしょうね。構造体DataCellに"構造体のDataCell_Meisai"が
宣言されていませんから。
pos(0).DataCell_Meisai(0).codeとしたいなら

Structure DataCell
    <VBFixedArray(4)> Public code() As Byte
    <VBFixedArray(11)> Public DataCell_Meisai() As Byte
    <VBFixedArray(1)> Public kaigyou() As Byte
Wnd Structure

ではなく、

Structure DataCell
    <VBFixedArray(4)> Public code() As Byte
    <VBFixedArray(11)> Public 変数名() As DataCell_Meisai '←ココ
    <VBFixedArray(1)> Public kaigyou() As Byte
Wnd Structure

としないといけません。

>すみません。ReDimはちゃんとつけてます・・・・
確かについてますが、Preserveが無いので毎回ループする際に
初期化されてます。また、Redimはループの中でなくて外で
確保した方が処理が高速になります。


相原  2007-01-30 01:41:12  No: 135040

モーヲタさんありがとうございます。
お蔭様で、'code'は'Byte'のメンバーではありませんというエラーは
なくなりました。
しかし、どうしても正常に通りません。
FileSystem.FileGet(FileNum, pos(I))のところで以前と同じように

配列のオフセットおよび長さが範囲を超えているか、カウンタがソース コレクションのインデックスから最後までの要素の数より大きい値です。

というエラーが出てしまいます。どこの配列が足りないのか
分からなくて途方にくれています。
ご教授いただけないでしょうか?
あと、以前からご指摘いただいているReDimをループの外に出すには
どのようにすればよいでしょうか?

読込データ
--------------------------------
00001000020000001000030000005
00002000040000005000050000007
--------------------------------

Public Class Form1

    Structure DataCell_Meisai
        <VBFixedArray(4)> Public code() As Byte
        <VBFixedArray(6)> Public suryo() As Byte
    End Structure

    Structure DataCell
        <VBFixedArray(4)> Public code() As Byte
        <VBFixedArray(23)> Public Meisai() As DataCell_Meisai
        <VBFixedArray(0)> Public kaigyou() As Byte
    End Structure

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim I As Integer
        Dim FileNum As Integer = FileSystem.FreeFile
        FileSystem.FileOpen(FileNum, "c:\test.txt", OpenMode.Random, , , Len(New DataCell()))

        Dim pos() As DataCell

        I = 0
        Do While Not EOF(FileNum)
            ReDim Preserve pos(I)
            ReDim Preserve pos(I).Meisai(1)

            FileSystem.FileGet(FileNum, pos(I))
            I = I + 1
        Loop

        FileSystem.FileClose()
    End Sub

End Class


大吉末吉  2007-01-30 02:15:24  No: 135041

>         <VBFixedArray(0)> Public kaigyou() As Byte
何故、「0」なんでしょう?


大吉末吉  2007-01-30 02:20:33  No: 135042

それから、
>         <VBFixedArray(23)> Public Meisai() As DataCell_Meisai
VBFixedArrayなのに、何故、

>            ReDim Preserve pos(I).Meisai(1)
ここで、ReDimするんでしょう??

少なくとも、
>         FileSystem.FileOpen(FileNum, "c:\test.txt", OpenMode.Random, , , Len(New DataCell()))
のタイミングでは、Meisaiは、24個確保されますから、

サイズは、
>     Structure DataCell_Meisai
>         <VBFixedArray(4)> Public code() As Byte
>         <VBFixedArray(6)> Public suryo() As Byte
>     End Structure
は、Byte型5個(5バイト)+7個(7バイト)で12バイト。

>     Structure DataCell
>         <VBFixedArray(4)> Public code() As Byte
>         <VBFixedArray(23)> Public Meisai() As DataCell_Meisai
>         <VBFixedArray(0)> Public kaigyou() As Byte
>     End Structure
は、Byte型型5個(5バイト)+DataCell_Meisai型24個(12*24=288バイト)+Byte型1個(1バイト)

なので、1行(1データ)294バイト固定出なければならないのでは?


相原  2007-01-30 02:22:14  No: 135043

大吉末吉さん、おせわになります。
実際のBYTE数-1と解釈してたんですが、違いますでしょうか?


大吉末吉  2007-01-30 02:25:09  No: 135044

> 実際のBYTE数-1
そうですよ?

-1して0ってことは、1バイトデータを読み込むってことですか?

てっきり、複改行コード2バイトを収めるのかと思いましたが・・・違うんですか?
#今まで私が提示したコード、貴方が提示したコード、全部そうなってましたよね?


相原  2007-01-30 02:33:38  No: 135045

お世話になります。

要素数や長さが違う旨のエラーが出ていたので、いろいろと
試していました。
それで、間違っているところが改行コードのところかと思い
<VBFixedArray(0)>にしたものです。
すみません。
<VBFixedArray(1)>でも試してみたのですが、やはり同じエラーが
消えなくて困っております・・・・


モーヲタ  2007-01-30 08:07:15  No: 135046

>配列のオフセットおよび長さが範囲を超えているか、
>カウンタがソース コレクションのインデックスから最後までの
>要素の数より大きい値です。
>というエラーが出てしまいます。どこの配列が足りないのか
>分からなくて途方にくれています。

う〜ん、基本から勉強し直した方がよろしいかも・・・
まずはデバッグの仕方を覚えてください。
ステップ実行して何処がおかしくなっているのか調べてください。
あと、大吉末吉さんも指摘されてますが、
>ReDim Preserve pos(I).Meisai(1)
は明らかにおかしい記述してますよね?
Meisai(1)←この部分ね。誤解の無いように書いておきますが、
文法的に間違っている訳ではなく、アルゴリズム的に
間違っているという事ですよ。

>以前からご指摘いただいているReDimをループの外に出すには
>どのようにすればよいでしょうか?
読んで字のごとくですが・・・ループの外でRedimするだけです。
これ以外に表現の方法が思い浮かびません。
今回はファイルがEOFまでなのでPreserveでReDim確保しても良いですが、
ループに入る前に最大値が分かっているならループの外で一気に
確保した方が高速だという意味です。

相原さんの書き込みを見てると自分で何をしているのか
自分自身が分からない様な状態に陥っているように見えます。
ここは一端落ち着いて自分の記述したコードを1ステップずつ
良く見て、かつステップ実行してどの様に処理が動いているのかを
じっくりゆっくり見ていった方が良いと思います。


相原  2007-01-30 18:27:41  No: 135047

お世話になります。相原です。
いろいろと基本的なことから教えていただきありがとうございます。

>少なくとも、
>>         FileSystem.FileOpen(FileNum, "c:\test.txt", >OpenMode.Random, , , Len(New DataCell()))
>のタイミングでは、Meisaiは、24個確保されますから、

大吉末吉さんにご指摘いただきました、この辺の理解ができていなかったらしく
DataCell_Meisai型24個を
 <VBFixedArray(23)> Public Meisai() As DataCell_Meisai
で宣言しないといけないと思っていました。
自分なりに解釈して修正し、

    Structure DataCell_Meisai
        <VBFixedArray(4)> Public code() As Byte
        <VBFixedArray(6)> Public suryo() As Byte
    End Structure

    Structure DataCell
        <VBFixedArray(4)> Public code() As Byte
        <VBFixedArray(1)> Public Meisai() As DataCell_Meisai
        <VBFixedArray(1)> Public kaigyou() As Byte
    End Structure

ということにたどり着きました。
が、どうしても、2行目(最後の1行)で

配列のオフセットおよび長さが範囲を超えているか、カウンタがソース コレクションのインデックスから最後までの要素の数より大きい値です。

のエラーが出てしまいます。
たびたびの質問で恐縮ではございますが、どうかご教授いただけないでしょうか?


大吉末吉  2007-01-30 21:54:10  No: 135048

デバッグしてみました。

結論
「Structure の入れ子の場合、Len関数が期待した値を返さない」
の様です。

実際に実行してみると、
> Len(New DataCell())
の値が「7」になる様で( code+kaigyou?)、Meisai分が反映されません。

ですから、1レコード7バイトと解釈されます。
実際には(期待しているサイズは)、31バイトですが、
1レコード7バイトとして動作するので、
1回目で、7バイトx5レコード=35バイト分読み込まれ、
2回目では、36バイト目(2行目の5文字目)から読み込みが行われるようです。
その為、サイズが足らなくなって、上記のエラーになるようです。

明示的に、
>          FileSystem.FileOpen(FileNum, "c:\test.txt", 
> OpenMode.Random, , , 31)
とすると、ちゃんと動きますが・・・

サイズを正しく計算する方法は・・・申し訳ありませんが、分かりません。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加