[[20111009220410]] 『バイナリモードでファイルをオープンしたい』(フェンダー) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『バイナリモードでファイルをオープンしたい』(フェンダー)

 固定長のデータをバイナリモードでファイルを読み込み、
 仕様によって加工したいのですが
 ファイルをオープンするための操作方法は
 VBAによるコードを記述して
 バイナリモードで読み込むのでしょうか??

 アドバイスよろしくお願いたします。

 XP 2007 7 2010 (フェンダー)

 この質問文に対しては、その通りですとしか答えようがありませんが、
 どのようなことに困っているのでしょうか。

 VBA ファイル バイナリ― で検索すれば事例には事欠きませんので、
 ファイルの開き方がわからないということでもないと思いますが、
 もう少し具体的な内容を記載されたらよいと思います。
 (Mook)

 ご回答ありがとうございます。
 まずデータをバイナリエディタなどではなくで、VBAでファイルを
 読み込みたいのですがうまくいきません。
 読み込むだけなら、エクセルから外部ファイルとして読み込む方法があるのかと
 素人の発想で思ったのですが・・

 ご質問する前にファイルオープンの検索をして、チェックしました。
 調べたサイトには下記のような詳細があったのですが、
 下記の記述に対して
 ファイル名などを変更すれば良いだけなのか
 わかりません。

 バイナリファイル読み込み 
 Openステートメントでモードを「Binary」で開きます。 
 LOF関数にてファイルの長さを取得し、Byte配列を初期化します。 
 Getにて、ファイルを読み込み、Byte配列に格納します。 

 バイナリファイル書き込み 
 Openステートメントでモードを「Binary」で開きます。 
 書き込みたいByteをPutにて書き込みます。 

 Sub test() 

    Dim inputFileName As String 
    Dim inputFn As Long 

    Dim buffer() As Byte 

    Dim outputFileName As String 
    Dim outputFn As Long 

    '読み込むファイル 
    inputFileName = "C:\in.jpg" 

    '空いているファイル番号 
    inputFn = FreeFile 

    'バイナリファイル読み込み 
    Open inputFileName For Binary As #inputFn 
        'ファイルの長さで配列を初期化 
        ReDim buffer(LOF(inputFn)) 

        'ファイルをバイナリで読み込んでByte配列に格納 
        Get #inputFn, , buffer 
    Close #inputFn 

    '書き込むファイル 
    outputFileName = "C:\out2.jpg" 

    '空いているファイル番号 
    outputFn = FreeFile 

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

 End Sub 

 get文が理解できてなく
 上記の記述に対して変更する箇所は
 ファイルネームやファイルの場所を見直す必要があるのでしょうか??

 ちなみにサンプルのデータ詳細になります。

 ファイル名 aa.TEST

 ファイル場所 ディスクトップ

 バイト数   42100バイト

 XP 2007 7 2010 (フェンダー)


 EXCEL がシートで処理できるのは  EXCEL がサポートしているフォーマットのみです。
 > 読み込むだけなら、エクセルから外部ファイルとして読み込む方法があるのかと
 なんて乱暴なことはできません。

 ファイルを処理して書き出すという目的であれば、あまり EXCEL VBA でやる必要性も
 なさそうですが、他の手段もないようであればそこは問いません。

 サンプル例は Cドライブの直下の in.jpg ですから、一致していないですね。
 デスクトップ(ディスクではないですね)はパス指定が面倒なので、分かりやすい
 フォルダに移してやってみてはどうですか。

 EXCEL 自体を同じフォルダに置けば、ファイル名だけですのでパスは関係なくなりますが。

 ファイルシステムやバイナリという概念が分からないのであれば、この処理をやる前に
 少しそのあたりを調べた方が良いかもしれません。
 (Mook)

 ご回答ありがとうございます。

>ファイルを処理して書き出すという目的であれば、あまり EXCEL VBA でやる必要性も

  なさそうですが、他の手段もないようであればそこは問いません。

 そもそも固定長データの加工を行うのに
 どのプログラム言語を勉強するかという点から検証しました。
 パールなどでも出来るらしいのですが
 VBAでも出来るという事でしたので
 まず読み込みが出来なければという事でご質問してみました。
 プログラム業者に委託すれば安全なのですが
 バイナリという概念を理解して今後勉強したいと思ってまして。

 これは質問外ですが
 今後の課題は現在ある固定長データで
 文字コードとして認識される領域と、バイナリ領域が混在してますので
 このままプログラムを組んで
 CSV生成をしてしまうと、バイナリ領域が空白になってしまうのです。

 ですので認識されないバイナリの領域の16進数の部分を
 10進数で見た数値が取得したいので
 固定長時に文字コードとして認識される加工が必要になるのです。

 以上からVBA上で開発出来る環境があれば
 と思いご質問してみました。

 XP 2007 7 2010 (フェンダー)


 バイナリデータと文字データの混在というものはありません。

 テキストファイルもバイナリファイルとして処理しようと思えばバイナリデータですが、
 ファイル内のすべてが表示可能なデータというのが、テキストデータというだけす。
 1バイトでもテキストエディタで認識できないコードが含まれていれば、それはバイナリ
 ファイルとして処理する必要があります。

 CSV ファイルはテキストファイルで、書式が CSV というルールに従っているだけですから
 バイナリファイルを CSV として読み込むこともできません。

 バイナリファイルを処理するためには、文字列ではなく文字コードで処理しなければ
 なりませんし、バイトオーダー、 改行コードなどを意識して処理する必要がありますが、
 そのあたりは大丈夫でしょうか。
 まずは、簡単なテキストファイル(できれば日本語などの2バイト文字の入った)を
 バイナリエディタで見てみて中身がどうなっているか確認してみてはどうでしょうか。
 (Mook)

 アドバイスありがとうございます。

 >バイナリデータと文字データの混在というものはありません。

 これに関して話してしまうとかなり長くなってしまうのですが・・・
 簡単に説明いたします。

 まず固定長データは固定長テキスト形式のファイルではありません。

 固定長時→   属性タイプの混在(バイナリ領域含む)

 CSV生成後→ 文字コードとNULL値の混在
 
 レコードレイアウトにそって
 プログラムを組めば、レコードの区切りことにCSV生成されます。
 バイナリの領域は、今使っているシステムだと
 エラーにはならずに、NULL値としてスキップされ
 空白になってしまうのです。
 で、あとでそこの領域は意図的に空白じゃないと気が付き
 今のシステムだと固定長時にバイナリ領域に加工が必要となったのです。
 この下りは検証済みなので大丈夫です。

 サンプルをバイナリエディタで見てみて中身がどうなっているかは確認済みで
 仕様によって、バイナリの部分を文字コードとして認識できるよう
 しっかりプログラムを組めるかが重要になってくると思います。

 バイナリ領域のフィールドを
 文字コードとして認識される加工を行っても
 レコードの区切りが長くなるだけでシステム的には問題ないです。

 XP 2007 7 2010 (フェンダー)


 中身のイメージができているのであれば、
 読み込んだ buffer のインデックスが バイナリエディタで見たときのアドレスになります。
 ファイル名を実際に合せて、変更したい位置のデータを修正後、書き出せば基本的には
 変更できると思います。

 挿入、削除があると処理が複雑になりますが、固定サイズであればご自身で提示された
 サンプルでできないでしょうか。

 Get Put は テキストファイルで言えば Read Write ですが、バイナリには行という概念
 はありませんので、サイズによる管理になります。
 (Mook)

 元データバイナリ領域 16進数       「0000」

           10進数だと・・   「0」

 加工作業は「0000」のところに→「F0F0」と埋め込む作業が必要になります。
 (まだ埋め込む箇所はあります)

 現状加工は出来なくでもこちらで把握していないと、
 プログラム業者に委託出来なくなります。
 コードを覚える必要は課題になりますが
 ファイルを読み込むのもVBAで作業しなければならないと
 知ったのも勉強になりました。

 ちなみに今回だとバイナリ領域を文字データで表
 すと元の長さ2バイトより長い3バイトが必要になるので提供されているレイ
 アウトより長くなります。

 >挿入、削除があると処理が複雑になりますが、固定サイズであればご自身で提示された
 サンプルでできないでしょうか。

 しっかりした土台を用意しないといけないので
 時間がかかると思います。
どうもありがとうございました。

 XP 2007 7 2010 (フェンダー)


 フェンダーさんは
[[20110726193908]] 『エクセルで開いてからフィールド分割したい』(フェンダー)
 と、同じ方でしょうか?

 であるなら、過去に↑で示した最後の私のサンプルにあるADODBを使った方法でも
 バイナリーの加工が出来ますよ。

 >上のコードで出来たのであれば「ADODB.Stream」で検索して色々調べてみる事をお勧めします。
 と書いておきましたが、調べてみて頂けましたか?
 (momo)

 固定長なら、一般的には、ランダムアクセスモードでOpen(固定長の指定を行う)すれば、
 固定長ごとのデータが取得できますから、こっち方が何かと簡単かもしれませんよ!!

 検討してみてください。

 ichinose


 momoさん。

 どうもありがとうございます。
 以前書いて頂いたコードは使用させていただいてます。
 ADODB.Stream検索で、色々とチェックさせてもらいました。
 とりあえず、ファイルをオープンさせるとこまでいきたいのですが・・・
 また詳しく質問できる状態までなりましたらご質問するかと思います。

 (フェンダー)


 ichinoseさん

 アドバイスどうもありがとうございます。
 ランダムアクセスモードでOpenする方法もあるのですね。
 詳しくわかりませんが色々調べてみます。

 (フェンダー)


 ファイルをオープンするってどこで悩んでいるのでしょうか。
 サンプルコードの
   inputFileName = "C:\in.jpg" 
 を変更すればとりあえず動きますよ。

 提示されたサンプルは何の加工もしていませんので、結果的にはファイルのコピーですが、
        For i = 0 To UBound(buffer) - 1 
            'ファイルにByteを書き込み 
            Put #outputFn, , buffer(i) 
        Next 
 の部分で buffer(i) を見ながら、違う内容に書き出したいのであればそこで処理を
 変えればできます。

 たとえば単純に 0000 を F0F0 に置換するだけなら
    i=0
    Do While i<(UBound(buffer)-3)
        If buffer(i)=0 And buffer(i+1)=0 And buffer(i+2)=0 And buffer(i+3)=0 Then
            Put #outputFn, , CByte(16)
            Put #outputFn, , CByte(0)
            Put #outputFn, , CByte(16)
            Put #outputFn, , CByte(0)
            i = i+4
        Else
            Put #outputFn, , buffer(i) 
            i = i+1
        End If
    Loop
    Do While i<UBound(buffer)
        Put #outputFn, , buffer(i) 
        i = i+1
    Loop
 のような感じでできるかと思います。
 実際はそんなに単純ではないとは思いますが。
 (Mook)

 アドバイスどうもありがとうございます。
 置換作業のアイデアは今後参考にさせて頂きます。

 inputFileName = "C:\in.jpg"の部分をいろいろと
 試しているのですがうまくいきません。
 ちなみに下記の記述だと
 実行時エラー424
 オブジェクトが必要ですとなります。
 ファイルネームや固定長データの場所を変えたりすると
 パス名が違いますと表示されたり
 うまくいきません。

 データはCドライブに入れてまして
 ファイル名はabc.DATになります。
 ファイルネームの記述方法とパス指定が違うのでしょうか??

 Sub test()

    Dim inputFileName As String
    Dim inputFn As Long

    Dim buffer() As Byte

    Dim outputFileName As String
    Dim outputFn As Long

    '読み込むファイル
'★NG  abc.DAT = "C:\abc.DAT"
    inputFileName = "C:\abc.DAT"

    '空いているファイル番号
    inputFn = FreeFile

    'バイナリファイル読み込み
'★NG  Open abc.DAT = "C:\abc.DAT" For Binary As #inputFn
       Open inputFileName  For Binary As #inputFn
'// あるいは直接書くなら
'//    Open "C:\abc.DAT" For Binary As #inputFn
        'ファイルの長さで配列を初期化
        ReDim buffer(LOF(inputFn))

        'ファイルをバイナリで読み込んでByte配列に格納
        Get #inputFn, , buffer
    Close #inputFn

    '書き込むファイル
'    outputFileName = "C:\out2.jpg"
    outputFileName = "C:\abc"  '★ 変えるならこちら

    '空いているファイル番号
    outputFn = FreeFile

    Dim i As Long
    'バイナリファイル書き込み
'★NG  Open abc = "C:\abc" For Binary As #outputFn
       Open outputFileName For Binary As #outputFn

        For i = 0 To UBound(buffer) - 1
            'ファイルにByteを書き込み
            Put #outputFn, , buffer(i)
        Next
    Close #outputFn

  End Sub

 XP 2007 7 2010 (フェンダー)


  Open abc.DAT = "C:\abc.DAT" For Binary As #inputFn
 の部分を元のサンプルとよく見比べてください。

 変数に abc.DAT のように . も使えませんので正しい変数にしてください。

 追記:
 余計なお世話だと思いますが、間違っている点を修正しました。
 (Mook)

 変数に.を使うのはTypeステートメントでユーザー定義した場合とか
 オブジェクトライブラリなどの場合だけですね。
 変数というかプロパティのように思いますが。

 あと、基本的なコードの書き方がだいぶ間違ってるように見えますから
 ヘルプとニラメッコしてみましょうね^^
 (momo)

 問題のファイルって、JPGファイルなんですか?
 でも、JPGファイルって、固定長でしたっけ?
 それともこれは、練習用ですか?
 いずれにせよ、私も問題点が何なのか? がよくわかりません。

 一般的に・・・、

 バイナリファイルってのは、そのファイルのデータ構造がきちんとわかっていないと
 扱いは難しいです。Excelブックやテキストファイルのように簡単にすぐ理解できる
 ような表示はしてくれません。
 (Excelブックだってバイナリファイルですよね?
 Excel本体があるから、簡単に人がわかるデータ表示をしてくれますが)。
 

 共通のデータを用意しました。

 新規ブックの標準モジュールに

 以下のコード

 '=================================================================
 Sub test0()
   With ActiveSheet
      .Range("a1:c1").value = Array("コード 4バイト長整数型", "氏名 16バイト", "モノマネ評価 1000点満点 4バイト長整数")
      .Range("a2:c2").value = Array(100010, "コロッケ", 600)
      .Range("a3:c3").value = Array(100020, "清水あきら", 300)
      .Range("a4:c4").value = Array(100030, "青木隆治", 950)
      .Range("a5:c5").value = Array(100040, "西尾夕紀", 850)
      .Range("a6:c6").value = Array(100050, "星奈々", 900)
      .Range("a7:c7").value = Array(100060, "中島まり", 800)
      .Columns("a:c").AutoFit
   End With
 End Sub

 適当なシートをアクティブにして上記のtest0を実行してみてください。

 シートに表示されるデータをバイナリファイル(固定長)として、書き込む(項目名は入れない)ことを考えます。

 別の標準モジュールに

 '=================================================================
 Option Explicit
 Const flnm = "random.bin"
 Type rec
   cd As Long
   nm As String * 16
   value As Long
 End Type
 '=============================================================
 Sub test1()
    Dim g0 As Long
    Dim myarray As Variant
    Dim flno As Long
    Dim rc As rec
    With ActiveSheet
       myarray = .Range("a2", .Cells(.Rows.Count, "a").End(xlUp)).Resize(, 3).value

    End With
    flno = FreeFile()
    On Error Resume Next
    Kill ThisWorkbook.Path & "\" & flnm
    DoEvents
    Open ThisWorkbook.Path & "\" & flnm For Random As #flno Len = 24
    For g0 = LBound(myarray, 1) To UBound(myarray, 1)
       rc.cd = myarray(g0, 1)
       rc.nm = Space(16)
       LSet rc.nm = myarray(g0, 2)
       rc.value = CLng(myarray(g0, 3))
       Put #flno, , rc
    Next
    Close #flno
 End Sub
 '==================================================================
 Sub test2()
    Dim g0 As Long
    Dim g1 As Long
    Dim myarray As Variant
    Dim flno As Long
    Dim rc As rec
    Dim nm As String
    flno = FreeFile()
    On Error Resume Next
    Open ThisWorkbook.Path & "\" & flnm For Random As #flno Len = 24
    g1 = LOF(flno) / 24
    Do Until g0 >= g1
       rc.nm = Space(Len(rc.nm))
       Get #flno, , rc
       MsgBox rc.cd & " : " & RTrim(rc.nm) & "  :  " & rc.value
       g0 = g0 + 1
    Loop
    Close #flno
 End Sub

*一度このブックを必ず、適当な名前で保存してください。

 保存した後で、データがあるシートをアクティブにした状態で

 test1を実行してください。

 ブックがあるフォルダと同じ場所に 「random.bin」というファイルが作成されます。

 このrandom.binの中身をバイナリエディタで調べてみてください。
 バイナリファイルって、こんなデータのことですよね?
 Excelに表示されたデータがこのように形式で保存されています。

 覗いてみると、B列の名前は、何となくデータとして、認識できますが、
 コードとモノマネ評価の数値は、一見すると、どんな値なのか わかりませんよね?

 でも、ファイルのレイアウトさえ、きちんと把握していれば・・・、

 test2を実行してみてください。

 正しくデータを取得できます。
 (尚、バイナリモードでも同様ロジック(ユーザー定義型を使う方法)で
 データの取得はできます。)

 実際には、
 JISコードやUnicodeで作成された文字データや
 VBAで扱うのとは、違う仕組みの浮動小数点型で保存されている場合もあったりで
 簡単にいかない場合も多々あります。

 実際のデータが私が思ったような固定長という意味ではなくても
 何かの応用は出来ると思います。

 バイナリデータで最初に躓きそうな箇所を記述して見ました。

 追伸
 見せていただいたLofで得られるバイト数分、一気に読み込む方法、
 私も使うことがありますが、読み込む相手は、ファイルです、
 相当膨大なファイルだってありますから、分けて読みこまなければならないことっだて
 ありますよね?(今、フェンダーさんが抱えているファイルがそんなに大きくないなら
 問題はないと思いますけど)。 

 ichinose


mookさん momoさん  ichinoseさん

お世話になります。
ご回答ありがとうございます。

 
Sub test()

    Dim inputFileName As String
    Dim inputFn As Long

    Dim buffer() As Byte

    Dim outputFileName As String
    Dim outputFn As Long

    '読み込むファイル
    inputFileName = "C:\abc"

    '空いているファイル番号
    inputFn = FreeFile

    'バイナリファイル読み込み
       Open inputFileName = "C:\abc" For Binary As #inputFn

        'ファイルの長さで配列を初期化
        ReDim buffer(LOF(inputFn))

        'ファイルをバイナリで読み込んでByte配列に格納
        Get #inputFn, , buffer
    Close #inputFn

    '書き込むファイル

    outputFileName = "C:\abc"

    '空いているファイル番号
    outputFn = FreeFile

    Dim i As Long
    'バイナリファイル書き込み
       Open outputFileName = "C:\abc" For Binary As #outputFn

        For i = 0 To UBound(buffer) - 1
            'ファイルにByteを書き込み
            Put #outputFn, , buffer(i)
        Next
    Close #outputFn

  End Sub

 訂正してみました。
 今度はエラー項目は出ないのですが
 応答がないです。

 >バイナリファイルってのは、そのファイルのデータ構造がきちんとわかっていないと
 扱いは難しいです。Excelブックやテキストファイルのように簡単にすぐ理解できる
 ような表示はしてくれません。
 (Excelブックだってバイナリファイルですよね?
 Excel本体があるから、簡単に人がわかるデータ表示をしてくれますが)。

 今までの記述を見ていただければわかると思いますが冒頭で記述したように
 これから勉強していかなければならないと思います。
 具体的に質問できるようになってから
 質問すると報告したのですが
 mookさんに
 サンプルコードの
   inputFileName = "C:\in.jpg" 
 を変更すればとりあえず動きますよ。
 いうアドバイスを頂いたので
 せっかくだから読み込みだけでもとやってみたのです。

 >問題のファイルって、JPGファイルなんですか?
 でも、JPGファイルって、固定長でしたっけ?
 それともこれは、練習用ですか?
 いずれにせよ、私も問題点が何なのか? がよくわかりません。

 こちらに関してはサンプルマクロなので
 色々と変える必要があるかと思います。

 実際は、サンプルの100件で検証しようと思ってますが
 本番は50万件とかあったりします。
 うまくいかない場合は、バックに
 プログラマーもいますしその都度検証していくか
 他のプログラム言語を使用するか方法は考えようと
 思ってます。
 プログラマーにはなかなか指導してもらう機会がないのと
 これから勉強していくうえで
 固定長データを
 VBAでバイナリモードでファイルをオープン出来るのか?
 1点の質問だけだったのです。
 これまでのアドバイスはありがたく参考にさせて頂きますが
 これ以上は今のとこご質問はございません。

XP 2007 7 2010 (フェンダー)


 >訂正してみました。
 >今度はエラー項目は出ないのですが
 >応答がないです。

 何を持ってそう判断したのでしょうか。
 結果は Cドライブの直下に abc っていうファイルができるだけですが、それができないと
 いうことでしょうか。

 もし、EXCEL に何か表示されると思っているのであれば、根本的にバイナリファイルを
 理解しなおしたほうが良いかと思います。
 (Mook)

 >結果は Cドライブの直下に abc っていうファイルができるだけですがそれが
 できないと
 いうことでしょうか。

 ファイルが出来ません。
 やはり詳しく理解していないと、ご指導して頂ける方に
 伝わらないのもございますし質問もできないようですね。
 とりあえず質問はクローズさせて頂きます。
 長々とどうもありがとうございました。

 XP 2007 7 2010 (フェンダー)

 あぁ、それは何も変わらないように見えますね。
 入力ファイルと出力ファイルが一緒じゃないですか。

 途中で何も変更していないのですから、変化するのはファイルの更新日付くらいですね。
 もしファイルが無ければ、エラーが出る気もしますが、もし On Error Resume Next などを
 おまじないで使っていれば、何も起こらないです。

 まずは特定の位置のデータを変更して、それがバイナリエディタで変わっていることを
 確認するというような、基本的なテストをまずしてみてはどうでしょうか。

 現在の
    Put #outputFn, , buffer(i)
 の部分を
    If i=16 Then
            Put #outputFn, , CByte(255)
    Else
            Put #outputFn, , buffer(i)
    End If
 として、16バイト目が FF になっておることを確認するなど、小さなところから
 始めてはどうでしょうか。

 >やはり詳しく理解していないと、ご指導して頂ける方に
 >伝わらないのもございますし質問もできないようですね。
 あきらめてしまうのは簡単ですが、
 その理解をここですればよいのではないですか?
 (Mook)

 ファイルオープン出来ない理由自体はコードの書き方が根本的に違うからだけだと思います。

 >inputFileName = "C:\abc"
 としているのに
 >Open inputFileName = "C:\abc" For Binary As #inputFn
 ここでまた変数に入れながらオープンしようとしてますよね

 Open inputFileName For Binary As #inputFn

 こうするだけで出来るんじゃないかな?と思いますが(拡張子が本当に無いファイルなら)
 このような記述方法は解らなくてもヘルプを見るだけで解ると思うので
 前回、私は
 >ヘルプとニラメッコしてみましょうね^^
 と書いたのです。

 ちなみにJPEGは先頭付近のExifからしてバイト長指定部分が織り込まれているので
 固定長とは言い難いんじゃないかと思います。

 頑張ってください〜
 (momo)

 サポートありがとうございます。

 ちなみに下記の記述でabc2ファイルの
 16バイト目はFFにはなってませんでした。

 なお今回の操作はアドバイスをもとに
 対応してますが、根本的なやり方自体間違っているかもしれません。
 それとご質問もわかりにくい部分も承知の上で
 ご教授頂ければ助かります。

 Cドライヴに用意したDATデータ

 @abc.DAT    ブロック長15600バイト 6件
 Aabc2.DAT   ブロック長15600バイト 6件

 >inputFileName = "C:\abc"
 としているのに
 >Open inputFileName = "C:\abc" For Binary As #inputFn
 ここでまた変数に入れながらオープンしようとしてますよね

 Open inputFileName For Binary As #inputFn

 こうするだけで出来るんじゃないかな?

 変更しましたが、パス名でつまづきました。

 Sub test()

    Dim inputFileName As String
    Dim inputFn As Long

    Dim buffer() As Byte

    Dim outputFileName As String
    Dim outputFn As Long

    '読み込むファイル
    inputFileName = "C:\abc"

    '空いているファイル番号
    inputFn = FreeFile

    'バイナリファイル読み込み
       Open inputFileName = "C:\abc" For Binary As #inputFn

        'ファイルの長さで配列を初期化
        ReDim buffer(LOF(inputFn))

        'ファイルをバイナリで読み込んでByte配列に格納
        Get #inputFn, , buffer
    Close #inputFn

    '書き込むファイル

    outputFileName = "C:\abc2"

    '空いているファイル番号
    outputFn = FreeFile

    Dim i As Long
    'バイナリファイル書き込み
       Open outputFileName = "C:\abc2" For Binary As #outputFn

        For i = 0 To UBound(buffer) - 1
            'ファイルにByteを書き込み
            If i = 16 Then
            Put #outputFn, , CByte(15600)
    Else
            Put #outputFn, , buffer(i)
    End If

        Next
    Close #outputFn

  End Sub

 XP 2007 7 2010 (フェンダー)


 一度落ち着いてこれまでの指摘を見直してみませんか。
 問題の原因は複数の回答者から再三指摘がありますよ。

 Open では ="...."  は書いちゃダメです。
 (Mook)

 Mookさんからも指摘されてますが
 ちゃんと回答を読んでくださいね。

 何も変更されてませんよ?

 >(拡張子が本当に無いファイルなら)
 これも見落としていませんか?

 (momo)

 もう一つ言っておくと CByte(15600) もダメです。
 バイトデータは 0 〜 255 の範囲の数値です。

 15600 はバイナリ(16進)では 3CF0 になりますが、これを書くには2回に分けて
 CByte(60) と CByte(240) を書く必要があります。
 (Mook) 

 私からも、もう少し

 2Byteを書きこむ際にはエンディアンにも気を付けてください。
 BOM(バイトオーダーマーク)がある型式ならそれに従って
 無い型式なら仕様に沿ってビッグエンディアンかリトルエンディアンにしなければ
 意味がわからないデータになってしまいます。

 (momo)

 アドバイスありがとうございます。
 仕事が忙しくなり、検証できないので
 時間に余裕が出来たら、検証再開したいと思います。

 >Mookさんからも指摘されてますが
 ちゃんと回答を読んでくださいね。

 因みに無視しているわけではなく、
 読んでも理解できなかったようです。
 もちろん関数や変数の知識不足もございますし
 アイデアもありませんので
 そこが知識がある人とない人の差かと思います。

 XP 2007 7 2010 (フェンダー)


 横から失礼します。

 勉強されるとのことですが、バイナリモードの読み書きは決して難しくありません。
 こういうものは手順がガッチリ決まっているので、その決まった手順どおりに書くだけです。
 変な言い方ですが、頭を使う余地はありません。

 フェンダーさんの感じておられる難しさは、「バイナリ読み書き」自体の難しさというよりむしろ
 「説明」を理解する難しさだと思います。
 これをなんとかするには、DOSの基礎と VBAの基礎を勉強されるのがよろしいかと。
 DOSに関する一定の知識を前提として、説明は書かれていますから。

 勉強はひにちがかかるかもしれませんが、あせらず、がんばって下さい。

 −佳−

 理解というほどの物でもないのですが・・・
 私もMookさんも

 >Open inputFileName = "C:\abc" For Binary As #inputFn
       ~~~~~~~~~~~~~~~~~~~~~~~~
 の行は
 Open inputFileName For Binary As #inputFn
      ~~~~~~~~~~~~~
 のように書きましょうね。

 と言っているだけですよ?
 下線部をよ〜く見てください。
 (momo)

 アドバイスありがとうございます。
 返信遅れてすいません。
 今までの記述でご説明したかと思いますが
 Open ではすでに下記のように訂正してまして
 パス名でエラーになったと
 報告はしてるのですが・・・

 >'★NG  Open abc.DAT = "C:\abc.DAT" For Binary As #inputFn
 >  Open inputFileName  For Binary As #inputFn

 >Open inputFileName For Binary As #inputFn

 >こうするだけで出来るんじゃないかな?

 >変更しましたが、パス名でつまづきました。

 Sub test()

    Dim inputFileName As String
    Dim inputFn As Long

    Dim buffer() As Byte

    Dim outputFileName As String
    Dim outputFn As Long

    '読み込むファイル
    inputFileName = "C:\abc"

    '空いているファイル番号
    inputFn = FreeFile

    'バイナリファイル読み込み
       Open inputFileName For Binary As #inputFn

        'ファイルの長さで配列を初期化
        ReDim buffer(LOF(inputFn))

        'ファイルをバイナリで読み込んでByte配列に格納
        Get #inputFn, , buffer
    Close #inputFn

    '書き込むファイル

    outputFileName = "C:\abc2"

    '空いているファイル番号
    outputFn = FreeFile

    Dim i As Long
    'バイナリファイル書き込み
       Open outputFileName For Binary As #outputFn

        For i = 0 To UBound(buffer) - 1
            'ファイルにByteを書き込み
            If i = 16 Then
            Put #outputFn, , CByte(255)
    Else
            Put #outputFn, , buffer(i)
    End If

        Next
    Close #outputFn

  End Sub

 >サンプル例は Cドライブの直下の in.jpg ですから、一致していないですね。
 >デスクトップ(ディスクではないですね)はパス指定が面倒なので、分かりやすい
 >フォルダに移してやってみてはどうですか。

 >EXCEL 自体を同じフォルダに置けば、ファイル名だけですのでパスは関係なくなりますが。

 >(拡張子が本当に無いファイルなら)
 これも見落としていませんか?

 上記のアドバイスも
 言ってることは分かっても
 どのように対処すればいいのかわからない部分でもあります。

 XP 2007 7 2010 (フェンダー)


 変更しました、といってフェンダーさんが提示したコードが変わっていなかったので、
 みんな先のようなコメントになったのですよ。

 C ドライブの直下に abc(拡張子なし)のファイルを置き、マクロを実行すれば
 同じ場所に abc2 ができるはずです。それをバイナリエディタで見れば17バイト目は
 FF になっていませんか?
 こちらで実行した限りは問題なく実行できていますので、コードはそのようになっています。

 もしファイル名云々のエラーが出ているのなら、拡張子のあるファイルを使用して
 マクロ中もその名前にしてください。
 フォルダ上は拡張子が表示されていないだけ、ということもありますから。

 もし拡張子やパスの意味が分からないのであれば、まずそのあたりを申告してください。
 (Mook)


 >変更しました、といってフェンダーさんが提示したコードが変わっていなかったので、
 みんな先のようなコメントになったのですよ。

 すいません。今後わかりやすく致します。

 >もし拡張子やパスの意味が分からないのであれば、まずそのあたりを申告してください。

 >もしファイル名云々のエラーが出ているのなら、拡張子のあるファイルを使用して
 >マクロ中もその名前にしてください。
 >フォルダ上は拡張子が表示されていないだけ、ということもありますから。

    '読み込むファイル
    inputFileName = "C:\abc.dat"

  '書き込むファイル
  outputFileName = "C:\abc2.dat"

    を変更して実行してみました。

 因みに固定長ファイルをプロパティから確認するとdatファイル(.dat)となっていて
 実行後はabc2.datがエクセルによって開かれている状態になっており
 削除できません。

 下記の部分でパス名が無効と表示されます。

 Put #outputFn, , buffer(i)

 拡張子やパスに対してコードをどのようにするのか
 よくわかりません。

 XP 2007 7 2010 (フェンダー)


 うーん、エラーが出ている行は Put で間違いありませんか?
 そこにパスが必要な情報は無いと思うのですが。
 ですが、削除できないという状況は、EXCEL がファイルをロックしているようにも見えます。

 一度 EXCEL を閉じ、新規ファイルのマクロで下記を実行すると Cドライブの下に
 BinaryTestIn.dat と BinaryTestOut.dat というファイルができると思いますが、
 そこでもエラーが出ますか?
 (ファイルは二つともマクロによって作られますので、事前準備はいりません。)

 中身はバイナリエディタで見ても良いですが、メモ帳でもいいです。
 数字が1箇所 0 から 7 変わっていれば、期待通りです。

 これでもエラーが出ますか?
 (Mook)

 Sub CreateAndModify()
    Dim inputFileName As String
    Dim inputFn As Long

    Dim buffer() As Byte

    Dim outputFileName As String
    Dim outputFn As Long

    '読み込むファイル
    inputFileName = "C:\BinaryTestIn.dat"

    '空いているファイル番号
    inputFn = FreeFile

    Dim i As Long
'// 作成
    If Dir(inputFileName, vbNormal) = "" Then
        Open inputFileName For Binary As #inputFn
        For i = 0 To 128
              Put #inputFn, , CByte(48)    '「0」を書く
        Next
        Close #inputFn
    End If

'// 読込み

    'バイナリファイル読み込み
    Open inputFileName For Binary As #inputFn

    'ファイルの長さで配列を初期化
    ReDim buffer(LOF(inputFn))

    'ファイルをバイナリで読み込んでByte配列に格納
    Get #inputFn, , buffer
    Close #inputFn

'// 書込み

    '書き込むファイル
    outputFileName = "C:\BinaryTestOut.dat"

    '空いているファイル番号
    outputFn = FreeFile

    'バイナリファイル書き込み
    Open outputFileName For Binary As #outputFn

    For i = 0 To UBound(buffer) - 1
        'ファイルにByteを書き込み
        If i = 16 Then
            Put #outputFn, , CByte(55)  ' 「7」 に書き換え
        Else
            Put #outputFn, , buffer(i)
        End If
    Next
    Close #outputFn
 End Sub


 >うーん、エラーが出ている行は Put で間違いありませんか?

 Sub CreateAndModify()
    Dim inputFileName As String
    Dim inputFn As Long

    Dim buffer() As Byte

    Dim outputFileName As String
    Dim outputFn As Long

    '読み込むファイル
    inputFileName = "C:\BinaryTestIn.dat"

    '空いているファイル番号
    inputFn = FreeFile

    Dim i As Long
 '// 作成
    If Dir(inputFileName, vbNormal) = "" Then
        Open inputFileName For Binary As #inputFn
        For i = 0 To 128
              Put #inputFn, , CByte(48)    '「0」を書く
        Next
        Close #inputFn
    End If
 '// 読込み 

    'バイナリファイル読み込み
    Open inputFileName For Binary As #inputFn

    'ファイルの長さで配列を初期化
    ReDim buffer(LOF(inputFn))

    'ファイルをバイナリで読み込んでByte配列に格納
    Get #inputFn, , buffer
    Close #inputFn
 '// 書込み 

    '書き込むファイル
    outputFileName = "C:\BinaryTestOut.dat"

    '空いているファイル番号
    outputFn = FreeFile

    'バイナリファイル書き込み
    Open outputFileName For Binary As #outputFn

    For i = 0 To UBound(buffer) - 1
        'ファイルにByteを書き込み
        If i = 16 Then
            Put #outputFn, , CByte(55)  ' 「7」 に書き換え
        Else
            Put #outputFn, , buffer(i)
        End If
    Next
    Close #outputFn
 End Sub

 作成して頂いたコードで、実行する前にCドライヴ直下にファイル名を変更して
 2つファイルを用意して実行しました。

 BinaryTestIn.dat 

 BinaryTestOut.dat

 これで実行しますと

 実行時エラー75

 パス名が無効ですと表示され、やはり下記の部分が指摘されます。

 Put #outputFn, , buffer(i)

 >ですが、削除できないという状況は、EXCEL がファイルをロックしているようにも見えます。

 因みに先ほどと同じような状態になってます。

 >実行後はabc2.datがエクセルによって開かれている状態になっており
 削除できません。

 XP 2007 7 2010 (フェンダー)


 すいません。

 事前準備なしで検証しました。

 やはり

 パス名が無効ですと表示され、やはり下記の部分が指摘されます。

 Put #outputFn, , buffer(i)

 XP 2007 7 2010 (フェンダー)


 もう一度エクセルを新規で立ち上げて、事前準備なしで
 実行してみました。

 すると
 Open inputFileName For Binary As #inputFn

 の部分でパス名が無効と指摘され
 BinaryTestIn.dat と BinaryTestOut.dat というファイルは出来ません

 XP 2007 7 2010 (フェンダー)


 たびたびすいません。

 XPのエクセル2007で、同じ作業をしたところ

 17バイト目の数字が1箇所 0 から 7に 変わっていたのでご報告いたします。

 XP 2007 7 2010 (フェンダー)


 解決しました。

 下記のコードでエクセル2007で同じように試したとこ
 17バイト目が FFで埋め込まれてました。
 これから書き込むコードの書き方も勉強しなければ
 なりませんが、今後ともどうぞよろしくお願いします。
 ほんとどうもありがとうございました。 

 Sub test()

    Dim inputFileName As String
    Dim inputFn As Long

    Dim buffer() As Byte

    Dim outputFileName As String
    Dim outputFn As Long

    '読み込むファイル
    inputFileName = "C:\abc"

    '空いているファイル番号
    inputFn = FreeFile

    'バイナリファイル読み込み
       Open inputFileName For Binary As #inputFn

        'ファイルの長さで配列を初期化
        ReDim buffer(LOF(inputFn))

        'ファイルをバイナリで読み込んでByte配列に格納
        Get #inputFn, , buffer
    Close #inputFn

    '書き込むファイル

    outputFileName = "C:\abc2"

    '空いているファイル番号
    outputFn = FreeFile

    Dim i As Long
    'バイナリファイル書き込み
       Open outputFileName For Binary As #outputFn

        For i = 0 To UBound(buffer) - 1
            'ファイルにByteを書き込み
            If i = 16 Then
            Put #outputFn, , CByte(255)
    Else
            Put #outputFn, , buffer(i)
    End If

        Next
    Close #outputFn

  End Sub

 XP 2007 7 2010 (フェンダー)


 Win7の環境でだけ動かないという事なら
 Cドライブ直下へのアクセス権限が無いんだと思いますので
 場所を他のドライブなりアクセス権がある場所にしたら解決しそうですね。
 (momo)

 ファイルのアクセス権の問題だったのでしょうか。
 だとしたらなかなか EXCEL のコードを見ていただけでは、解決は難しいですね。
 なかなか難航しましたが、ご自身で他の PC で試す思い付き出来たのは良かったです。
 (Mook)

 >(ファイルは二つともマクロによって作られますので、事前準備はいりません。)

 書いていただいたコードで、エラーが出た際
 環境の問題だと気づきました。
 ちなみにビスタでも、アクセス権限の問題で
 機能しなくて
 外付けハードディスクに指定したら書き込めました。
 今までは私のミスも含めて、パス指定等の記述がちがうだけと
 思ってたからです。
 今後は「ADODB.Stream」などもチェックして勉強してみます。
 また書き込みについてご教授下さい。
 ありがとうございました。

 XP 2007 7 2010 (フェンダー)

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.