トップ回答者
VB6で作成したバイナリデータをC#で同じ値で読み込むには?

質問
-
こんにちは
VB6のバイナリデータをC#で読み込もうとしたのですが
違う値になってしまいます。
アップグレードウィザードで作成したVB.netだと同じです
ただしOpenMode.RandomをOpenMode.Binaryに変更すると違う値になります。
C#で同じ値になるようにアドバイスよろしくお願いします。
【環境】
WindowsXP+VS2008sp1 .NET Framework 2.0
【テスト結果】
要素番号 0 1 2 3 4 5 6 7 8 9 (VBは+1)
VB6 Prog: 1 1 0 0 0 0 0 0 0 0
VB Prog1: 1 1 0 0 0 0 0 0 0 0
VB Prog2: 1 0 0 0 0 0 0 0 0 0
C# Prog1: 1 0 0 0 0 0 0 0 0 0
C# Prog2: 1 0 0 0 0 0 0 0 0 0
----- VB6 Prog(○) -----
Public St(10) As Integer
Open "C:\StratUp.Dat" For Random As #3
Get #3, 1, St(1)
----- VB Prog1(○) -----
Public St(10) As Short
FileOpen(3, "C:\StratUp.Dat", OpenMode.Random)
FileGet(3, St(1), 1)
----- VB Prog2(×) -----
Public St(10) As Short
FileOpen(3, "C:\StratUp.Dat", OpenMode.Binary)
FileGet(3, St(1), 1)
----- C# Prog1(×) -----
using Microsoft.VisualBasic;
static public Int16[] intSt = new Int16[10];
FileSystem.FileOpen(3, "C:\\StratUp.Dat", OpenMode.Random,
OpenAccess.Read, OpenShare.Shared, 10);
for (int i = 0; i < 10; i++)
{
Microsoft.VisualBasic.FileSystem.FileGet(3, ref intSt[i], i+1);
}
----- C# Prog2(×) -----
static public Int16[] intSt = new Int16[10];
FileStream fs = new FileStream(
"C:\\StratUp.Dat", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
int intFileSize = (int)fs.Length;
byte[] buf1 = new byte[intFileSize];
int intRemainSize = intFileSize;
int intBufPos = 0;
int intBufSize = 1024;
try
{
while (intRemainSize > 0)
{
int intReadSize = fs.Read(buf1, intBufPos, Math.Min(intBufSize, intRemainSize));
intBufPos += intReadSize;
intRemainSize -= intReadSize;
}
fs.Dispose();
for (int i = 0; i < 10; i++)
{
intSt[i] = buf1[i];
}
}
catch (Exception ErrMsg)
{
MessageBox.Show(ErrMsg.Message);
}
回答
-
----- VB Prog1(○) -----
VisualBasic名前空間のクラスをよく知りませんが、VB.NETのFileOpen関数とC#のFileOpenメソッドではレコード長の指定が変わっていませんか?
Public St(10) As Short
FileOpen(3, "C:\StratUp.Dat", OpenMode.Random)
FileGet(3, St(1), 1)
(中略)
----- C# Prog1(×) -----
using Microsoft.VisualBasic;
static public Int16[] intSt = new Int16[10];
FileSystem.FileOpen(3, "C:\\StratUp.Dat", OpenMode.Random,
OpenAccess.Read, OpenShare.Shared, 10);
for (int i = 0; i < 10; i++)
{
Microsoft.VisualBasic.FileSystem.FileGet(3, ref intSt[i], i+1);
}
FileOpen関数では引数を省略した場合は -1 になるそうです。このあたりがぱっと見たところでの差でしょうか?
http://msdn.microsoft.com/ja-jp/library/afh37kh8.aspx
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。- 回答としてマーク aukty 2009年6月6日 11:26
-
> Seek関数の説明でRandomで開かれたときとBinary , Input , Output , Appendで開かれた時
> 動作が違いますね。この辺が怪しいのかなって思っているのですが。そのようです。OpenMode が Random で、RecordLength をデフォルト (-1) にすると、 Abstrakt さん
のレスにありますように、128 バイトおきにファイルのデータを読むようで、それゆえ結果が下記のよ
うになるのだと思います。VB6 Prog: 1 1 0 0 0 0 0 0 0 0
VB Prog1: 1 1 0 0 0 0 0 0 0 0VB6 は全くさわったことがなく、VB6 でのファイルアクセスの方法は知らなかったのですが、ちょっと
調べてみたところ、VB.NET とはずいぶん違うようですね。ファイル アクセスの種類と関数
http://msdn.microsoft.com/ja-jp/library/aa903295(VS.71).aspxバイナリファイルを読むなら OpenMode は Binary とするのが正解のようです。
というわけで、C# で VisualBasic 名前空間を使わずにやるとすると、128 バイトおきに読んでいく他
手はなさそうです。- 回答としてマーク aukty 2009年6月7日 1:26
すべての返信
-
----- VB Prog1(○) -----
VisualBasic名前空間のクラスをよく知りませんが、VB.NETのFileOpen関数とC#のFileOpenメソッドではレコード長の指定が変わっていませんか?
Public St(10) As Short
FileOpen(3, "C:\StratUp.Dat", OpenMode.Random)
FileGet(3, St(1), 1)
(中略)
----- C# Prog1(×) -----
using Microsoft.VisualBasic;
static public Int16[] intSt = new Int16[10];
FileSystem.FileOpen(3, "C:\\StratUp.Dat", OpenMode.Random,
OpenAccess.Read, OpenShare.Shared, 10);
for (int i = 0; i < 10; i++)
{
Microsoft.VisualBasic.FileSystem.FileGet(3, ref intSt[i], i+1);
}
FileOpen関数では引数を省略した場合は -1 になるそうです。このあたりがぱっと見たところでの差でしょうか?
http://msdn.microsoft.com/ja-jp/library/afh37kh8.aspx
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。- 回答としてマーク aukty 2009年6月6日 11:26
-
C:\StratUp.Dat ファイルの中身はどうなっているのでしょうか?
コードを見る限り、C# Prog2 は正しく、取得した内容も正しいはずですが、そうすると、そもそも
VB6 Prog では正しく取得できていなかったということになりますが、いかがですか?その場合は、VB6 Prog と C# Prog2 の結果が同じ値になるようにすることはできないですね。
> -1に変更したところ上手くいきました。C# Prog1 の結果が VB6 Prog の結果と同じになったということでしょうか?
以下のコードで試してみましたが、正しくデータを取得するには OpenMode は Binary、intSt は
byte[] とする必要があるようです。引数 RecordLength は 10 でも -1 でも結果は同じで、正し
くデータを取得できました。お試しください。byte[] data = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a }; using (FileStream fileStream = File.Create(@"c:\temp\StartUp.dat")) { fileStream.Write(data, 0, data.Length); fileStream.Close(); } byte[] intSt = new byte[10]; Microsoft.VisualBasic.FileSystem.FileOpen(3, @"c:\temp\StartUp.dat", Microsoft.VisualBasic.OpenMode.Binary, Microsoft.VisualBasic.OpenAccess.Read, Microsoft.VisualBasic.OpenShare.Shared, 10); for (int i = 0; i < 10; i++) { Microsoft.VisualBasic.FileSystem.FileGet(3, ref intSt[i], i + 1); } Microsoft.VisualBasic.FileSystem.FileClose(new Int32[] { 3 }); foreach (Byte b in data) { Console.Write("{0:X2} ", b); } Console.WriteLine(""); foreach (Byte b in intSt) { Console.Write("{0:X2} ", b); } Console.WriteLine(""); using (FileStream fileStream = File.Open(@"c:\temp\StartUp.dat", FileMode.Open, FileAccess.Read)) { fileStream.Read(intSt, 0, intSt.Length); fileStream.Close(); } foreach (Byte b in intSt) { Console.Write("{0:X2} ", b); }
結果は以下の通りです。01 02 03 04 05 06 07 08 09 0A
01 02 03 04 05 06 07 08 09 0A
01 02 03 04 05 06 07 08 09 0A -
C# Prog2のコードと、SurferOnWwwさんが書かれているコードは1バイト毎に1個のデータが前提となっていますよね?
VB6のコード、VB.NET Prog1のコード、C# Prog1のコードはshort型(Int16型)ベースであるからこそ、うまく動いているのだと推測しています。
(実際にファイルにはどのように書かれているかは、検討・確認していませんが…)
C# Prog2のコードで問題点があるとすれば、1バイトずつshort(Int16)型にキャストしているところでしょうか。
ただ、実行結果の「C# Prog2: 1 0 0 0 0 0 0 0 0 0」が気になります。どこかにもう1個以上、1になっている箇所はありませんか?
ないとすると、まだ何か問題が埋もれているということに…。
解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。 -
SurferOnWwwさん、こんばんは。
>>C:\StratUp.Dat ファイルの中身はどうなっているのでしょうか?
バイナリエディタで確認したところ
00を省略して書くと次の通り。
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
000| 01
001|
002|
003|
004|
005|
006|
007|
008| 01
009|
途中省略
600| 01
>>コードを見る限り、C# Prog2 は正しく、取得した内容も正しいはずですが、そうすると、そもそも
>>VB6 Prog では正しく取得できていなかったということになりますが、いかがですか?おっしゃるように、バイナリで読み込むとVB Prog2/VC Prog2が正しく、バイナリエディタと一致します。
正しい、正しくないは別としても、現状VB6Progは動いていて、設定を変更すると、想定している設定に変わります。
引き続き調べていたのですが
Seek関数の説明でRandomで開かれたときとBinary , Input , Output , Appendで開かれた時
動作が違いますね。この辺が怪しいのかなって思っているのですが。
http://msdn.microsoft.com/ja-jp/library/7af2feyt.aspx
> -1に変更したところ上手くいきました。
>>C# Prog1 の結果が VB6 Prog の結果と同じになったということでしょうか?
>>以下のコードで試してみましたが、正しくデータを取得するには OpenMode は Binary、intSt は
>>byte[] とする必要があるようです。引数 RecordLength は 10 でも -1 でも結果は同じで、正し
>>くデータを取得できました。お試しください。ありがとうございます。試してみました。
ややこしくなったので、ちょっと整理しますね
【VB6と一致(全てOpenMode:Random )】
VB6 Prog/ VB Prog1/ VC Prog1(-1)
【バイナリエディタと一致(OpenMode: Binary / VC Prog1のみRandom )】
SurferOnWwwさんのサンプル/ VB Prog2/ VC Prog1(10)/ VC Prog2
ちょっと変な感じですがこんな感じです。
-
short型は怪しいと思いますよね
最初intで作ったけど、上手くいかないので、VB6のソース(int)をVS2008でアップグレードウィザードしたら
int16になっていたので、合わせたのですが、intでも動くようになればに戻そうかなと思います。
1が次に出てくるのは
80番目その次が600番目です。VBで変更して何が変わるかバイナリエディタで確認したほうがいいのかも
しれないですね。
試してみますと下記ながら試しました。
1をon アドレス000が01
2をon アドレス080が01
3をon アドレス100が01
VC Prog1(-1)では
1 1 1 0 0 0 0 0 0 0
VC Prog1(10)では
1 0 0 0 0 0 0 0 0 0
どっちも正解というか、理屈が少し分かりました
ありがとうございます。 -
> Seek関数の説明でRandomで開かれたときとBinary , Input , Output , Appendで開かれた時
> 動作が違いますね。この辺が怪しいのかなって思っているのですが。そのようです。OpenMode が Random で、RecordLength をデフォルト (-1) にすると、 Abstrakt さん
のレスにありますように、128 バイトおきにファイルのデータを読むようで、それゆえ結果が下記のよ
うになるのだと思います。VB6 Prog: 1 1 0 0 0 0 0 0 0 0
VB Prog1: 1 1 0 0 0 0 0 0 0 0VB6 は全くさわったことがなく、VB6 でのファイルアクセスの方法は知らなかったのですが、ちょっと
調べてみたところ、VB.NET とはずいぶん違うようですね。ファイル アクセスの種類と関数
http://msdn.microsoft.com/ja-jp/library/aa903295(VS.71).aspxバイナリファイルを読むなら OpenMode は Binary とするのが正解のようです。
というわけで、C# で VisualBasic 名前空間を使わずにやるとすると、128 バイトおきに読んでいく他
手はなさそうです。- 回答としてマーク aukty 2009年6月7日 1:26