2016-07-25 3 views
0

ファイルを作成し、別のプロセスがそのファイルのロックを取得することを許さずにLast Write Time(およびその他のタイムスタンプ情報)を設定する方法があるかどうかを知りたいこれら2つの操作。ファイルを作成してからファイルロックを解除せずにタイムスタンプを設定する

私がこれをやりたいのは、ウイルス対策ソフトウェアがファイルの作成直後にロックを取得し、ファイル属性を設定しようとするまでにロックを保持するという問題を修正することです。具体的には、私が作業しているコードはSevenZipSharpです(私が見る限り、これ以上維持されません)。この問題を再現

コードは次のとおりです。

var filePath = "test.txt"; 
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite)) 
{ 
    var bytes = Encoding.ASCII.GetBytes("Hello fail."); 
    fileStream.Write(bytes, 0, bytes.Length); 
    var fileInfo = new FileInfo(filePath); 
    fileInfo.CreationTime = DateTime.Now; 
} 

最後の文を実行するときにこれが次の例外を生成します。 System.IO.IOException 「プロセスはファイルにアクセスできません「C:\ test.txtのを'それは別のプロセスで使用されているためです。

私は再試行メカニズムで時間属性の設定を実装することを検討していますが、より洗練されたソリューションがあるかどうか疑問に思っています。

+0

なぜ* "別のプロセスが" * "の間にファイルへのロックを取得することを許可しないのですか?後で時間を変更できないのはなぜですか? – Sinatr

+0

のように、アンチウイルスソフトウェアが攻撃して改ざんを防止していますか? –

+0

fileStream.Dispose()の後にCreationTimeを変更できます。しかし、間にはありません。 –

答えて

2

@Damien_The_Unbelieverが述べたように、ファイルハンドルを取得する必要があります。これを試して。

class Program { 
    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool SetFileTime(SafeFileHandle hFile, ref long lpCreationTime, ref long lpLastAccessTime, ref long lpLastWriteTime); 

    static void Main(string[] args) { 
     var filePath = "test.txt"; 
     long when = DateTime.Now.AddDays(10).ToFileTime(); 
     using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite)) { 
      if (!SetFileTime(fileStream.SafeFileHandle, ref when, ref when, ref when)) { 
       throw new Win32Exception(); 
      } 
      var bytes = Encoding.ASCII.GetBytes("Hello fail."); 
      fileStream.Write(bytes, 0, bytes.Length); 
     } 
    } 
} 
+0

パーフェクト。あなたと@Damien_The_Unbelieverに感謝します。 – flange

0

問題は、使用しているステートメントで使用されているファイルにアクセスしようとしていることです。だからあなたはエラーを受けている。 usingステートメントを終了する必要があります。次に、ファイルの作成時間を割り当てることができます。

他のソフトウェアによってファイルがロックされている場合は、ファイルを待つためのwhileループを作成することをお勧めします。

は、以下のことを試してみてください。

var filePath = "test.txt"; 
DateTime creationTime; 
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite)) 
{ 
    var bytes = Encoding.ASCII.GetBytes("Hello fail."); 
    fileStream.Write(bytes, 0, bytes.Length); 
    creationTime = DateTime.Now; 
} 
int numTries = 0; 
while (true) 
{ 
    ++numTries; 
    try 
    { 
     // Attempt to open the file exclusively. 
     using (var fileInfo = new FileInfo(filePath)) 
     { 
      // If we got this far the file is ready 
      fileInfo.CreationTime = creationTime; 
      break; 
     } 
    } 
    catch (Exception ex) 
    { 
     if (numTries > 10) 
     { 
      // Get out of it 
      Console.WriteLine("This joker still has your file, I'm out."); 
      break; 
     } 

     // Wait for the lock to be released 
     System.Threading.Thread.Sleep(500); 
    } 
} 
+0

これは例外を停止しますが、作成と属性の設定との間にロックを取得する別のプロセスの問題は解決しません。元の投稿で述べたように、私は再試行を検討していますが、ファイルロックを解放しない別の方法が可能かどうかを知りたいと思います。 – flange

+0

ええ、私はあなたの目標は何かを理解していますが、別のライブラリを使用してファイルを開く前にファイルをリリースする必要があります。 –

+0

例外がファイルがロックされているためにチェックする必要があります:http://stackoverflow.com/a/11060322 –

0

いいえ、あなたはファイルをロックから別のプロセスを防ぐためにできることは何もありません。

ファイルの一時バージョンを作成してから、Process.Startを使用してRobocopyを実行して、属性を設定している間にファイルをコピーできます。ファイルの元のコピーは無関係になります。後でそのファイルをクリーンアップすることができます。

Robocopyがファイルをコピーして属性を設定する方法がアトミックであるかどうかによって異なります。

.NETコードからコマンドラインアプリケーションを呼び出すことの醜さを避けるため、既にラッパーを作成しています。これはRoboSharpと呼ばれ、nuget packageです。

+1

Robocopyがアトミックだった場合、アトミック性が可能です。アトミシティが可能な場合、おそらく私のコードでこのアトミック性を使用する方法があります。 – flange

+0

はい、いくつかの低レベルAPIを使用しています。すでにパッケージ化されているサードパーティのライブラリがあるのだろうかと思います。今私は興味があります。私は見ています...はい、RoboCopyを包むナゲットパッケージがあります。 –

+0

しかし、@ aquinasの答えがうまくいくならば、この解決法は本当に厄介で疑わしいものです。 –

関連する問題