プロが教えるわが家の防犯対策術!

こんにちはExcel 2007 on Win 7の環境でVBAを書いています。

ある別のアプリケーションがつかんでいるテキストファイルを新しい内容に置き換えたいのですが、うまくいかずに困っています。当初は「Open filename For Input As #n」の方法で開いて、編集して、保存することができていたのですが、アプリケーションの都合上、ファイルをUTF-8で保存する必要が出てきました。そのため、ADODB.Streamで書き直すことになったのですが、最後の「SaveToFile filename, 2」とすると、「アプリケーション定義またはオブジェクト定義のエラー」が出て書き込むことができません。

「Open file」して「Close」したり「Unlock」したりしたのですが、ADODB.StreamのSaveToFileで上書き保存できる状態になりません。

大元のアプリケーションをいったん終了させれば良いのでしょうが、それでは本末転倒なのです。

お知恵を貸してください

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

  • ちなみに、#3の回答で書いたコードの ADODBTestは、問題のアプリケーションを閉じると正常に動作します。
    また、OpenTestでファイルを正常に更新できるのですが、そのあとも問題のアプリケーションでは古い内容のデータを扱っています。おそらくですが、問題のアプリケーションは対象ファイルの内容をいったん内部に取り込んで処理をしているので、リアル タイムには更新されないようにできているのだと思います。

    さらに、コマンド プロンプトでOpenfilesを実行したところ、やはり問題のアプリケーションがこの対象ファイルを使用していると表示されました。ロックの仕組みについて詳しくないので正確な表現なのかわかりませんが、やはりこの状態は、問題のアプリケーションが対象ファイルを使用していると呼んで良いのだと思います。であれば、Open コマンドで開いて編集して保存できるのは何なんでしょう。

    No.3の回答に寄せられた補足コメントです。 補足日時:2015/09/09 09:33

A 回答 (4件)

こんにちは。



#3の回答者です。概ね、状況は理解しました。まだ、*ちょっと理解していない部分はあるけれども、私は、アプリ側の「排他制御」モードと読んでいます。アプリ側が許しているものとそうでないものがありますし、「排他」にするか、オプションで選べるものもあります。排他モードでも、種類を選べるものもあります。

だから、Open ~ For Input As ** でも、ADODB.Stream でも本来、ロックされた状態ですと、同じ結果というか、編集・保存は出来ないはずです。それで、ふつう、そういう場合は、一旦、ダミーファイルでコピーで作ってやって、それを加工して、アプリが終わった時点で戻すというようなステップにします。

*理解してない部分
#1の回答
>でも Open filename For Input As #n だと編集して保存できちゃうんですよ。
補足#3
>であれば、Open コマンドで開いて編集して保存できるのは何なんでしょう。
もしかしたら、ロック解除のタイミングがあるかもしれません。ロックが解除になる時が存在しているなら、それはループで書き込みできる時を調べればよいと思います。ただし、Excel 等のVBAでは長い時間は無理だと思います。メモリが累積していくはずですから。

最初の話の部分は、例えば、このようなことです。

'//モジュール始め

Const myPath = "D:\Test1\"
Const fName = "abc.txt"
Dim dummyFn As String

Sub MacroSample1()
Dim fn As String
Dim objFS As Object
Dim objFile As Object

''"他のアプリケーションが使用中のファイル"
dummyFn = "$" & fName 'ここでダミーに切り替える
Shell "cmd.exe /c copy " & myPath & fName & "," & myPath & dummyFn
fn = myPath & dummyFn
Open fn For Output As #1
Print #1, "open for output" & Now() & vbCrLf
Close #1

End Sub
Sub ADODBTest()

 'fName = "D:\Test1\abc.txt"
 '"他のアプリケーションが使用中のファイル"
 
 Dim strm As Object
 Set strm = CreateObject("ADODB.Stream")
 strm.Type = 2
 strm.Charset = "UTF-8"
 strm.Open
 strm.WriteText "ADODB" & Now() & vbCrLf
 strm.Position = 0 '念のため、このコードがなくてもエラーになった
 strm.SaveToFile myPath & dummyFn, 2 'ダミーファイルに書き込む
 strm.Close
 Set strm = Nothing
End Sub
'///
話が中途になっていますが、とりあえず、ここまで調べてみてください。
*の部分は、今は、ちょっと不安が残ります。
ループで断続的にファイルのロック状態を調べるのです……。

ダメなら、別のアプリが終わった時点でも、VBA側から戻してあげればよいと思います。
    • good
    • 0
この回答へのお礼

根本的な謎は解決していないのですが、やりたいことは実現できました。書いてくださったコードがヒントになりました。

まず、新たに生成するファイルは、まだ存在していない新規のダミーファイルにしました。

次のようなコードにしたところ、事実上上書き保存ができました。

strm.SaveToFile dummyFile, 2
cmd = "cmd.exe /c copy /Y """ & dummyFile & """ """ & fName & """"
Shell cmd
cmd = "cmd.exe /c del /Q """ & dummyFile
Shell cmd

やはり SaveToFile の上書きは、表現が適切かわかりませんが、「厳しい条件」があるように感じました。

お礼日時:2015/09/09 14:03

こんちには。



このご質問は、一度、VBAコードを出してから話をしたほうがよいと思います。

>ある別のアプリケーションがつかんでいるテキストファイル
でも、Open filename for input で出来ていたというなら、別のアプリなど関係ないのではありませんか?別のアプリというのは、Excel以外という意味だと思いますが。

>Open filename For Input As #n だと編集して保存できちゃうんですよ。
ただ、これで保存ということではあっても、これだけでは、Application側のコマンドが実行中です。その後、Close #n で、始めて終わるわけなのです。

つまり、一連のコマンドのストーリーを終わらせるっていうのは、当たり前だと思うのです。

>編集して、保存することができていたのです
それが出来ているというなら、ロックは掛かっていません。

しかし、私の知っている範囲では、コマンド実行中で、オブジェクトの支配下にあるものを、横から割り込むことは出来なかった気がします。(やったことはないけれど)

私が想像するのは、コードの修正は、おそらくは、本当に簡単なことなんだろうと思うのです。

UTF-8 にするために、ADODB.Stream で云々はいいけれども、言葉だけでは伝わらないのです。
それに、Opne filename ~とは、別の流れなのです。こちらを一旦、終わらせていないのではないでしょうか。

ここの質問でも、話半分だったから、いえ、私の思い違いで、解決にまでは、二転三転してしまったのです。
http://oshiete.goo.ne.jp/qa/9054919.html

もし、見当はずれの内容でしたら、どうかスルーしてください。返事は不要です。
この回答への補足あり
    • good
    • 0
この回答へのお礼

ありがとうございます。

Open コマンドと ADODB を比較するコードを作ってみました。
やはり、Open コマンド (for outputでした)だと保存でき、ADODB の SaveToFileでは保存できませんでした。

Sub OpenTest()
Dim fName As String
fName = "他のアプリケーションが使用中のファイル"

Open fName For Output As #1
Print #1, "open for output"
Close #1

'結果、対象ファイルの中身は「hoge」だけになります。
End Sub

Sub ADODBTest()

Dim fName As String
fName = "他のアプリケーションが使用中のファイル"

Dim strm As Object
Set strm = CreateObject("ADODB.Stream")

strm.Type = 2
strm.Charset = "UTF-8"
strm.Open
strm.WriteText "ADODB"
strm.Position = 0 '念のため、このコードがなくてもエラーになった
strm.SaveToFile fName, 2 'この時にファイルに書き込めないエラーが発生して止まる
strm.Close
Set strm = Nothing

End Sub

エラーは今試したところ、実行時エラー 3004 ファイルへ書き込めませんでした。となりました。以前は「70」のエラーも出ていたように思いますが。

お礼日時:2015/09/09 09:29

それはOSの根幹部分でやっていることなのでVBA如きで歯が立たないのはあたりまえ。


ウイルス活動としてセキュリティソフトにブロックされるようなコードを書かないと無理だろう。

どうしても保存したいのであれば、
別名で保存して他で使用しているアプリケーションが終了したら書き換える
などの手段を講じてはどうか。
他で使用されて編集されていたらその内容を問答無用で破棄することになるが・・・。
    • good
    • 0
この回答へのお礼

ありがとうございます。

やっぱりアプリケーションをいっかい終了させてから、ファイルを上書き保存し、再度開き直すまでをすべてVBAに書き込もうと思います。
Open コマンドでは普通にできていたので、ADODB.Streamになったらとたんに使いづらく(ファイルが無駄に増える)ことになったのでどうにかならないかと思案していたところです。

お礼日時:2015/09/08 15:26

>使用中(ロック)のファイルを上書き



いやいや、それこそむしろ本末転倒でしょう?
それをさせないためにロックしているのだから・・・
    • good
    • 0
この回答へのお礼

ありがとうございます。
そうなんですねー

でも Open filename For Input As #n だと編集して保存できちゃうんですよ。今まで通り、タイムスタンプと付けたファイル名で新規ファイルを作成してアプリケーションに読み込ませ直すか(これでと新規ファイルが増殖しちゃって汚いんですけど)、あるいはアプリケーションをいったん閉じてから上書き保存して再度起動するのが無難ですかねぇ。

お礼日時:2015/09/08 15:24

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

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


このQ&Aを見た人がよく見るQ&A