ファイルが使用中かどうかを取得したいです。 への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2017/9/7 18:44:59
HResult プロパティは、IOException のみならず、
素の Exception クラスにも用意されています。
ただし、.NET 3.5 までは Protected Get/Protected Set でした。
.NET 4 以降で、Public Get/Protected Set なスコープに変更されています。
HRESULT の意味についてはこちら。
https://msdn.microsoft.com/ja-jp/library/system.exception.hresult.aspx
http://ascii.jp/elem/000/001/432/1432965/
エラーコードに対応するメッセージを知りたければ、Win32Exception.Message を利用できます。
さて、ご質問の『定数一覧』ですが、基本的には、Windows SDK のヘッダーファイルから
取得することになります。公式のものでなくても良ければ、下記が便利でしょう。
http://ir9.jp/prog/ayu/win32err.htm#com
ただし、上記にも掲載されていないコードはありますので、あくまでも参考程度に。
例:XPS_E_某系のエラー(0x8052**** 番台)
また、エラーの発生元が変わることで、同じエラーコードが別の意味を持つこともあります。
例:0x80040200 = TS_E_INVALIDPOS = EVENT_E_FIRST = MPEG2_E_UNINITIALIZED
素の Exception クラスにも用意されています。
ただし、.NET 3.5 までは Protected Get/Protected Set でした。
.NET 4 以降で、Public Get/Protected Set なスコープに変更されています。
HRESULT の意味についてはこちら。
https://msdn.microsoft.com/ja-jp/library/system.exception.hresult.aspx
http://ascii.jp/elem/000/001/432/1432965/
エラーコードに対応するメッセージを知りたければ、Win32Exception.Message を利用できます。
Dim ex As New System.ComponentModel.Win32Exception(STIERR_SHARING_VIOLATION)
MsgBox(ex.Message)
Throw ex
さて、ご質問の『定数一覧』ですが、基本的には、Windows SDK のヘッダーファイルから
取得することになります。公式のものでなくても良ければ、下記が便利でしょう。
http://ir9.jp/prog/ayu/win32err.htm#com
ただし、上記にも掲載されていないコードはありますので、あくまでも参考程度に。
例:XPS_E_某系のエラー(0x8052**** 番台)
また、エラーの発生元が変わることで、同じエラーコードが別の意味を持つこともあります。
例:0x80040200 = TS_E_INVALIDPOS = EVENT_E_FIRST = MPEG2_E_UNINITIALIZED
投稿者 みどりこぶた  (高校生)
投稿日時
2017/9/7 17:40:31
daive 様、回答ありがとうございます。
様々な候補ありがとうございます。ほとんどが vb.net だけではできないと思っていました。
もう一度、ひとつづつきちんと調べなおしてみようと思います。
>ディスク上のファイル
というのは私が考えていたものと似たようなものでしょうか。
魔界の仮面弁士 様、回答ありがとうございます。
>強いて言えば
直球な回答ありがとうございます。何というか、求めていた解答そのものズバリでした。
余談ですが、IOException.HResult の定数一覧のようなものは、どう調べると検索にヒットしますでしょうか…。
>Mutex、WCF、.NET Remoting、MemoryMappedFile、、
こちらも様々な候補ありがとうございます。上述しましたが、vb.net、いろいろできるのですね。
まず、検索・知識不足な面、失礼しました。
とりあえず、ex.HResult で判断、ということで解決とさせていただきますm(_ _)m
浅くですが調べた感じ、.NET Remoting か WCF あたりなら私にもできそうなので、時間がとれたときにそれに置き換えようと思います。
もう少し時間がとれた時、他に候補いただいた Windowsサービス、MemoryMappedFile、DB、同期サーバープログラム の方も調べてみようと思います。
ありがとうございました。
様々な候補ありがとうございます。ほとんどが vb.net だけではできないと思っていました。
もう一度、ひとつづつきちんと調べなおしてみようと思います。
>ディスク上のファイル
というのは私が考えていたものと似たようなものでしょうか。
魔界の仮面弁士 様、回答ありがとうございます。
>強いて言えば
直球な回答ありがとうございます。何というか、求めていた解答そのものズバリでした。
余談ですが、IOException.HResult の定数一覧のようなものは、どう調べると検索にヒットしますでしょうか…。
>Mutex、WCF、.NET Remoting、MemoryMappedFile、、
こちらも様々な候補ありがとうございます。上述しましたが、vb.net、いろいろできるのですね。
まず、検索・知識不足な面、失礼しました。
とりあえず、ex.HResult で判断、ということで解決とさせていただきますm(_ _)m
浅くですが調べた感じ、.NET Remoting か WCF あたりなら私にもできそうなので、時間がとれたときにそれに置き換えようと思います。
もう少し時間がとれた時、他に候補いただいた Windowsサービス、MemoryMappedFile、DB、同期サーバープログラム の方も調べてみようと思います。
ありがとうございました。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2017/9/6 19:47:00
強いて言えば、こんな感じでしょうか。
機能要件にもよりますが、プロセス間の排他制御だけが目的ならば、
ファイルではなく、System.Threading.Mutex を使った方が簡単かも知れません。
また、プロセス間でのデータ通信が目的ならば、
WCF を使うとか(System.ServiceModel 名前空間)、あるいは
昔ながらの .NET Remoting (System.Runtime.Remoting 名前空間)を
利用するという手もあります。
同一ファイルを複数のプロセスから編集する場合には、
System.IO.MemoryMappedFiles.MemoryMappedFile
を使うという手もあります。(排他制御とは別の話として)
Try
'ファイルオープン処理
Catch ex As IOException When ex.HResult = STIERR_SHARING_VIOLATION '&H80070020
'プロセスはファイルにアクセスできません。別のプロセスが使用中です。
Catch ex As IOException When ex.HResult = STIERR_DEVICE_LOCKED '&H80070021
'プロセスはファイルにアクセスできません。別のプロセスがファイルの一部をロックしています。
Catch ex As Exception
'その他の例外:必要に応じて再 Throw する
Finally
'後始末
End Try
機能要件にもよりますが、プロセス間の排他制御だけが目的ならば、
ファイルではなく、System.Threading.Mutex を使った方が簡単かも知れません。
また、プロセス間でのデータ通信が目的ならば、
WCF を使うとか(System.ServiceModel 名前空間)、あるいは
昔ながらの .NET Remoting (System.Runtime.Remoting 名前空間)を
利用するという手もあります。
同一ファイルを複数のプロセスから編集する場合には、
System.IO.MemoryMappedFiles.MemoryMappedFile
を使うという手もあります。(排他制御とは別の話として)
投稿者 (削除されました)  ()
投稿日時
2017/9/6 19:45:50
(削除されました)
投稿者 daive  (社会人)
投稿日時
2017/9/6 19:10:07
>もとはと言えば、別々のプロセス間でちょっとした同期をとりたくなり、
>それにファイルを使用しています。
>他に簡単な方法があればいいのですが、C++ などは書いたことなくて自身がなくて…、
古くからある方法は、
メモリーマップドファイル:だんだん使わなくなっている。
⇒もっと古いのは、アセンブラ時代に、共有実メモリ、実I/O でマッピング
ディスク上のファイル:DOS時代からある方法
Windowsサービス
同期サーバプログラムが、同期、スケジュール、を担う
プロセス間通信、WCF などなど
ほかに、DBを使ってしまう。
⇒SQlite など軽量DB
>それにファイルを使用しています。
>他に簡単な方法があればいいのですが、C++ などは書いたことなくて自身がなくて…、
古くからある方法は、
メモリーマップドファイル:だんだん使わなくなっている。
⇒もっと古いのは、アセンブラ時代に、共有実メモリ、実I/O でマッピング
ディスク上のファイル:DOS時代からある方法
Windowsサービス
同期サーバプログラムが、同期、スケジュール、を担う
プロセス間通信、WCF などなど
ほかに、DBを使ってしまう。
⇒SQlite など軽量DB
投稿者 みどりこぶた  (高校生)
投稿日時
2017/9/6 16:54:19
すみません、非常に不十分な質問文でした、少し補足します。
ファイルが使用中かどうか、というより、
ファイルの排他的なオープンを試行した結果、成功・ロック取得の失敗・それ以外の原因による失敗、で切り分けたいです。
最初は、 事前に IO.File.Exists で存在するかどうかなどチェックを入れていたのですが、
よく考えると、事前チェックでは意味が無いことに気づき、
更に良く考えると、そもそもオープンに失敗したとき、ファイルが存在さえすれば、ロック取得に失敗したとみなせるのか、と気づき…
上記のようなコードになりました。
指摘感謝します、もう一度調べなおしてみました。
みましたが、
・例外を catch したらファイル使用中とみなす
・APIを使う
しか見つけられませんでした…。
APIの方は「IsFileAlreadyOpen」などを使うのでしょうか…?
ロック取得の失敗(共有違反エラー?)は区別できたのですが、「Err.LastDllError」で取得する値は他のスレッドやプロセスと共有なのでしょうか…。
もとはと言えば、別々のプロセス間でちょっとした同期をとりたくなり、それにファイルを使用しています。
他に簡単な方法があればいいのですが、C++ などは書いたことなくて自身がなくて…、vb.net の範囲でもできる方法ありますでしょうか…?
もう少しヒント与えていただけましたら幸いですm(_ _)m
ファイルが使用中かどうか、というより、
ファイルの排他的なオープンを試行した結果、成功・ロック取得の失敗・それ以外の原因による失敗、で切り分けたいです。
最初は、 事前に IO.File.Exists で存在するかどうかなどチェックを入れていたのですが、
よく考えると、事前チェックでは意味が無いことに気づき、
更に良く考えると、そもそもオープンに失敗したとき、ファイルが存在さえすれば、ロック取得に失敗したとみなせるのか、と気づき…
上記のようなコードになりました。
指摘感謝します、もう一度調べなおしてみました。
みましたが、
・例外を catch したらファイル使用中とみなす
・APIを使う
しか見つけられませんでした…。
APIの方は「IsFileAlreadyOpen」などを使うのでしょうか…?
ロック取得の失敗(共有違反エラー?)は区別できたのですが、「Err.LastDllError」で取得する値は他のスレッドやプロセスと共有なのでしょうか…。
もとはと言えば、別々のプロセス間でちょっとした同期をとりたくなり、それにファイルを使用しています。
他に簡単な方法があればいいのですが、C++ などは書いたことなくて自身がなくて…、vb.net の範囲でもできる方法ありますでしょうか…?
もう少しヒント与えていただけましたら幸いですm(_ _)m
投稿者 daive  (社会人)
投稿日時
2017/9/6 12:52:33
代理検索:vb.net ファイル 使用中 チェック
https://www.google.co.jp/search?q=vb.net+%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB+%E4%BD%BF%E7%94%A8%E4%B8%AD+%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF&oq=VB.NET+%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%80%80%E3%81%97&gs_l=psy-ab.3.3.0i4k1l5j0i4i30k1l3.8235763.8242341.0.8245833.16.16.0.0.0.0.201.1662.11j4j1.16.0....0...1.1j4.64.psy-ab..0.16.1653...0j0i131k1j0i3k1.tGFXgDhep8Y
’
サイト、フォーラムの書込みなどを渉猟して、知見得てください。
https://www.google.co.jp/search?q=vb.net+%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB+%E4%BD%BF%E7%94%A8%E4%B8%AD+%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF&oq=VB.NET+%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%80%80%E3%81%97&gs_l=psy-ab.3.3.0i4k1l5j0i4i30k1l3.8235763.8242341.0.8245833.16.16.0.0.0.0.201.1662.11j4j1.16.0....0...1.1j4.64.psy-ab..0.16.1653...0j0i131k1j0i3k1.tGFXgDhep8Y
’
サイト、フォーラムの書込みなどを渉猟して、知見得てください。
投稿者 みどりこぶた  (高校生)
投稿日時
2017/9/5 22:49:10
すみません、コードの上から8行目、間違えてました。
If ex.Message IsNot Nothing AndAlso sss.Length <= ex.Message.Length AndAlso ex.Message.Substring(0, sss.Length) = sss Then
投稿者 みどりこぶた  (高校生)
投稿日時
2017/9/5 20:01:42
ファイルが使用中かどうかを取得したいです。
「Catch ex As Exception」の「ex.Message」に「別のプロセスで使用されているため、...」と文字列があるので、
とりあえずそれで判断しているのですが、本来どのように取得すれば良いのでしょうか?
低レベルな質問ですみません。
vb.net、vs2017で書いてます。勉強とかではなく趣味で、高校生です。常識無いかもしれませんが、指摘いただけると助かります。
Dim ppp As String = "D:\Test.txt"
Dim sss As String = "別のプロセスで使用されているため、"
Try
Using fs = New IO.FileStream(ppp, IO.FileMode.Open, IO.FileAccess.ReadWrite, IO.FileShare.None)
MsgBox("オープン成功。")
End Using
Catch ex As Exception
If sss.Length <= ex.Message AndAlso ex.Message.Substring(0, sss.Length) = sss Then
MsgBox("ロックの取得に失敗。")
Else
MsgBox("何かしらの理由で失敗。" & vbNewLine & ex.Message)
End If
End Try
「Catch ex As Exception」の「ex.Message」に「別のプロセスで使用されているため、...」と文字列があるので、
とりあえずそれで判断しているのですが、本来どのように取得すれば良いのでしょうか?
低レベルな質問ですみません。
vb.net、vs2017で書いてます。勉強とかではなく趣味で、高校生です。常識無いかもしれませんが、指摘いただけると助かります。
>HRESULT の意味についてはこちら。
エラーコードの値にもある程度のルールがあったりするのですね。
非常に勉強になります。
>基本的には、Windows SDK のヘッダーファイルから取得することになります。
今回もまた直球な解答ありがとうございます。
「何それ」レベルで理解してないので、WCF等の方をある程度理解してから、また今度調べてみようと思います。
参考リンクも感謝です。
細かいところまで親切丁寧な説明、ありがとうございました。
もし次投稿する機会ありましたら、そのときはまたご助力いただけましたら幸いですm(_ _)m