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

VBAを使って、
10MByteのバイナリファイルがあり、
これの1MByte~1.1MByteの領域のデータを書き換えたいとします。

いままでは

Open ファイル名 For Binary As #ファイル番号

でデータを書き換えていたのですが

http://officetanaka.net/excel/vba/file/file08.htm


Random、ランダムアクセスモードというものもあることに気がつきました。

RandomとBinaryモードの違いについて教えてください。

名前から判断すると
Randomモードはファイルの途中からでも読み書きができるのに対し
Binaryモードは最初からしか読み書きができないので
ファイルの途中のデータを書き換えたい場合には
Randomモードの方が高速のような気がするのですが
本当にそうなのでしょうか?

散々調べてみたのですが
違いおよび使い分け方が分からなかったので教えてください。

質問者からの補足コメント

  • ありがとうございます。

    しかし理解できていないのですが
    つまりrandomモードはテキストファイルを読み書きするモードということでしょうか?
    それだとfor inputやfor outputとどう違うのでしょうか?

    自分でもrandomモードを使ってみたのですが
    例えば4バイトのデータをファイルの途中に書き込もうとしようとすると
    その後にゼロでーたが大量に生成して元のファイルよりも
    大きなサイズのファイルを生成されてしまうのですが
    なぜでしょうか?
    使い方がよく分からないのですが
    教えていただけないでしょうか?

    No.2の回答に寄せられた補足コメントです。 補足日時:2015/12/05 16:44
  • ありがとうございます。
    やはりまだ理解できていないのですが

    質問1
    binaryモードで開くとシーケンシャルで読み書きするということなのですが
    数GBある大きなファイルの最後の方を書き換える場合には
    時間がかかるのでしょうか?


    質問2
    Put intFileNumber, 2000, xxx
    Put intFileNumber, 2001, yyy
    ・・・

    とやると2000バイト目を書き込んだ後に
    最初から読み直して2001バイト目に達してから
    書き込んでという操作になるのでしょうか?


    この方法よりも
    Put intFileNumber, 2000, xxx
    Put intFileNumber, , yyy
    ・・・
    のようにするとして書き込んだ方が高速でしょうか?

    No.3の回答に寄せられた補足コメントです。 補足日時:2015/12/05 22:21
  • 質問3
    ただ、二つ目の方法は書き込むデータがsingleやdoubleなどの非配列であれば
    うまくいくのですが、バイト型の配列を書き込もうとするとうまくいきません。
    それで一つ目の方法を使う必要があります。

    どうすれば二つ目の方法でバイト型配列を使うことができますか?

      補足日時:2015/12/05 22:21
  • ありがとうございます。

    Put intFileNumber, 2000, xxx
    Put intFileNumber, 2001, yyy
    ・・・

    という操作は
    Seek intFileNumber, 2000
    Put intFileNumber, , xxx
    Seek intFileNumber, 2000
    Put intFileNumber, , yyy


    という操作と同じなのでしょうか?
    後者は毎回最初から読み出しているかも知れませんが
    前者は順番に書き込んでいるということはありませんか?

    ていうかそれが本当か確かめるには計算時間を比較するしかないでしょうか?

    No.4の回答に寄せられた補足コメントです。 補足日時:2015/12/06 00:13
  • ありがとうございます。

    何が正しいのか確かめるために、いろいろな書き出し方法の計算速度の比較を行ってみたのですが
    いずれも大きな差異は見られませんでした。
    もっとも高速なのは最初に大きな配列を生成してから、一度に書き込む方法です。
    しかし要素ごとに書き込んでも、毎回アドレスを指定する方法などもほんの5以下程度しか
    計算速度に違いは見られませんでした。


    それで理由を考えてみたのですが
    テキストファイルの場合だと最初から呼んでいかないと行やファイルの終端がどこにあるか分からないので任意の場所にランダムにアクセスすることができないのに対し、
    バイナリファイルの場合だとアドレスで指定できるので
    そもそもシーケンシャルやランダムといった分類が存在しないのではないでしょうか?

    No.5の回答に寄せられた補足コメントです。 補足日時:2015/12/06 13:42
  • シーケンシャルやランダムといった用語はメモリで使われますが
    いまデータはHDDに保存されているので
    バイナリデータを扱う場合には常にランダムアクセスしているのではないでしょうか?

    自分なりの結論は出ているのですが
    検索などして調べてもその辺りが明確に書かれているページなどが見つからなかったので
    できればご意見いただけないでしょうか?

      補足日時:2015/12/06 13:43

A 回答 (7件)

>もっとも高速なのは最初に大きな配列を生成してから、一度に書き込む方法です。


メソッドを呼び出すのにも時間がかかります。
なので、メソッドの呼び出し回数を減らせば速度はアップします。

>いまデータはHDDに保存されているので
HDDのアクセスが早いので、シーケンシャルでもランダムでも速度差を感じなくなっているのです。
しかし、この考え方がなくなっているわけではありません。


すみません。何かおかしいと最初から読み直したのですが、基本が間違っていました。
1:「TEXTファイル」を「シーケンシャルアクセス」
Append、Input、Output
2:「TEXTファイル」を「ランダムアクセス」
Random
3:「Binaryファイル」を「シーケンシャルアクセス」←「ランダムアクセス」
Binary

>テキストファイルの場合だと最初から呼んでいかないと行やファイルの終端がどこにあるか
そのようなファイルを扱うのが「1:」のパターンです。
テキストファイルでも、1行の長さを固定にして出力すれば、読み込むときに計算で読みたい位置はわかるのでランダムにアクセスできます。これが「2:」のパターンです。

テキストファイル同様、バイナリーファイルでもファイルの構造によって必ずしもランダムアクセスできるわけではありません。そこのところは間違えないようにしてください。
    • good
    • 1

>いまデータはHDDに保存されているので


>バイナリデータを扱う場合には常にランダムアクセスしているのではないでしょうか?

プログラミング言語のレベルで言うと、
「どの位置だったかにかかわらず、前回読んだ次の位置のデータを読め」というのがシーケンシャルアクセスで、
「前回どこを読んだかに関係なく、指定したこの位置のデータを読め」というのがランダムアクセスです。
データが実際にどこにあるのか、HDDなのか、RAMDISKなのか、あるいは磁気テープ上にあるのか、などには無関係です。
    • good
    • 0

昨日のソースがよくなかったので手直ししました。



Dim buffer(3) As Byte

buffer(0) = AscW("A")
buffer(1) = AscW("B")
buffer(2) = AscW("C")

Dim i As Long
'バイナリファイル書き込み
Open outputFileName For Binary As #1
 Seek #1, 2000
 For i = 0 To UBound(buffer) - 1
  Put #1, , buffer(i)
 Next
Close #1

>質問2
>最初から読み直して2001バイト目に達してから
勘違いをさせてしまったようです。
実際には「読み直し」はしません。
「位置情報を変更してから」です。

>Put intFileNumber, 2000, xxx
>Put intFileNumber, 2001, yyy
xxx、yyyがByteデータだとすると、
最初の行でxxxを出力すると、位置情報が自動的に2001になります。
なので、2行目で位置情報を指定しなくても正しく出力されます。
例のように、2行目で2001と指定すると位置情報を再度セットしなおして
出力するので非効率と説明しました。
【位置を2000に移動】-【xxxを出力】-【位置を2001に移動】-【yyyを出力】

>Put intFileNumber, 2000, xxx
>Put intFileNumber, , yyy
【位置を2000に移動】-【xxxを出力】-【yyyを出力】
※xxxを出力すると、自動で2001に移動している。
ということです。

最初に記述したサンプルのbufferが500や1000と大きくなればなるほど、
出力のたびに毎回【位置移動】をさせるのと、しないのでは差がでるのはお分かりだと思います。

【補足】
xxx、yyyがIntegerだとすると、Integerは2Byteなので、
2000でxxxを出力すると、位置情報は2002になります。
この回答への補足あり
    • good
    • 0

>質問1


Seekなどで飛ばすだけなら気にならないと思います。
あちこちに移動させて読み書きする(データベースの処理)のようなことでもしない限り問題ないと思います。

>質問2
そのとおりです。
とても非効率になります。

>この方法よりも
>のようにするとして書き込んだ方が高速でしょうか?
高速に処理できます。

>質問3
例えばですが、以下のようにして配列を処理すればどうでしょう?
Dim buffer(3) As Byte

buffer(0) = AscW("A")
buffer(1) = AscW("B")
buffer(2) = AscW("C")

Dim i As Long
'バイナリファイル書き込み
Open outputFileName For Binary As #outputFn
Put #outputFn, 2000, buffer(0)
For i = 1 To UBound(buffer) - 1
Put #outputFn, , buffer(i)
Next
Close #outputFn
この回答への補足あり
    • good
    • 0

ファイルには、「TEXTファイル」と「Binaryファイル」が存在します。


ファイルにアクセス(読み込み・書き込み)するには、シーケンシャルとランダムがあります。
つまり、
1:「TEXTファイル」を「シーケンシャルアクセス」
2:「TEXTファイル」を「ランダムアクセス」
3:「Binaryファイル」を「シーケンシャルアクセス」
4:「Binaryファイル」を「ランダムアクセス」
この4つのパターンが存在します。
しかし、VBAでファイルをOPENする場合のモードには、
Append
Binary
Input
Output
Random
この5つで、同時に複数選択することができません。
なので、
1:「TEXTファイル」を「シーケンシャルアクセス」
Append、Input、Output
2:「TEXTファイル」を「ランダムアクセス」
Random
3:「Binaryファイル」を「シーケンシャルアクセス」
Binary
この、3種類になります。
基本は「シーケンシャルアクセス」で、先頭から順に読み書きしていく形式です。
ランダムアクセスは、ファイルの任意の位置から読み書きする場合に高速にアクセスできる形式ですが、何万件もデータがある場合でなければあまり差はありません。
※シーケンシャルアクセスでも途中から読み書きは可能です。普段扱うファイルならシーケンシャルでも速度が遅くなることがないので、基本はこちらになっています。

>つまりrandomモードはテキストファイルを読み書きするモード
結果的にそうなります。

>例えば4バイトのデータをファイルの途中に書き込もうとしようとすると
>その後にゼロでーたが大量に生成して元のファイルよりも
書き込み方法が間違っているだけだと思います。
この回答への補足あり
    • good
    • 0

Randomは、ファイルの途中から読み書きできる。


その反対がシーケンシャルです。
ただ、省略した場合ランダムです。

Binaryは、開くファイルがバイナリーファイルのときに指定します。
その反対がテキストです。
省略するとテキストです。

つまり、バイナリーファイルを扱うのであればBinaryを指定する必要があります。
テキストファイルの場合、16進数の「1A」が見つかるとファイルの終わり(EOF)と判断します。
バイナリーの場合は、「1A」をEOFとして判断しません。
ですので、バイナリーファイルをテキストモードでOPENすると正常に動作しない場合があります。
この回答への補足あり
    • good
    • 0

Randomモードは、ファイルが固定長のレコードの集まりであるとして、入出力します。

何番目のレコードを読み書きするのかという番号を指定するので、途中の読み書きが出来ます。
Randomモードでなくても、Seek文を使えば、ファイルの途中から読み書きできるので、その方が良いと思います。
    • good
    • 0

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

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