質問

何が最も簡単な方法遮断するスレッドでファイルをロックは閲覧および名称変更?例えば、あるWaitOnFile()のどこかできます。純させていただきます。

しているサービスを使用しFileSystemWatcher見のためのファイルを送信することができるFTPサイトが、 ファイルが作成されました イベントの火災前のロセスが完了した文書のファイルです。

最適なソリューションがタイムアウト期間のスレッドが掛からない永遠方、バプティスタの家の前です。

編集:るようにして、あのソリューションは、以下の成績を変更する システム そのすべてのファイルが書いた Path.GetTempFileName(), しを行った File.Move() 最終的な場所です。どの FileSystemWatcher イベントが発ファイルが完了しています。

役に立ちましたか?

解決

これに回答しました、 関連する質問:

    /// <summary>
    /// Blocks until the file is not locked any more.
    /// </summary>
    /// <param name="fullPath"></param>
    bool WaitForFile(string fullPath)
    {
        int numTries = 0;
        while (true)
        {
            ++numTries;
            try
            {
                // Attempt to open the file exclusively.
                using (FileStream fs = new FileStream(fullPath,
                    FileMode.Open, FileAccess.ReadWrite, 
                    FileShare.None, 100))
                {
                    fs.ReadByte();

                    // If we got this far the file is ready
                    break;
                }
            }
            catch (Exception ex)
            {
                Log.LogWarning(
                   "WaitForFile {0} failed to get an exclusive lock: {1}", 
                    fullPath, ex.ToString());

                if (numTries > 10)
                {
                    Log.LogWarning(
                        "WaitForFile {0} giving up after 10 tries", 
                        fullPath);
                    return false;
                }

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

        Log.LogTrace("WaitForFile {0} returning true after {1} tries",
            fullPath, numTries);
        return true;
    }

他のヒント

開始からエリックの答えは、私の一部で改善のためのコードによりコンパクト-再利用が可能です。希望便利であるとはいえるでしょう。

FileStream WaitForFile (string fullPath, FileMode mode, FileAccess access, FileShare share)
{
    for (int numTries = 0; numTries < 10; numTries++) {
        FileStream fs = null;
        try {
            fs = new FileStream (fullPath, mode, access, share);
            return fs;
        }
        catch (IOException) {
            if (fs != null) {
                fs.Dispose ();
            }
            Thread.Sleep (50);
        }
    }

    return null;
}

このは汎用のコードをこのためには、大聖堂と象の噴水からのファイル操作そのものです。この例で使う:

WrapSharingViolations(() => File.Delete(myFile));

または

WrapSharingViolations(() => File.Copy(mySourceFile, myDestFile));

を定義することもでき、再送回数の待ち時間の間に障害.

注意:残念ながら、基本となるWin32エラー(ERROR_SHARING_VIOLATION)に晒されていない。当期純ない小さなハッキング機能IsSharingViolation に基づく反射のメカニズムチェック。

    /// <summary>
    /// Wraps sharing violations that could occur on a file IO operation.
    /// </summary>
    /// <param name="action">The action to execute. May not be null.</param>
    public static void WrapSharingViolations(WrapSharingViolationsCallback action)
    {
        WrapSharingViolations(action, null, 10, 100);
    }

    /// <summary>
    /// Wraps sharing violations that could occur on a file IO operation.
    /// </summary>
    /// <param name="action">The action to execute. May not be null.</param>
    /// <param name="exceptionsCallback">The exceptions callback. May be null.</param>
    /// <param name="retryCount">The retry count.</param>
    /// <param name="waitTime">The wait time in milliseconds.</param>
    public static void WrapSharingViolations(WrapSharingViolationsCallback action, WrapSharingViolationsExceptionsCallback exceptionsCallback, int retryCount, int waitTime)
    {
        if (action == null)
            throw new ArgumentNullException("action");

        for (int i = 0; i < retryCount; i++)
        {
            try
            {
                action();
                return;
            }
            catch (IOException ioe)
            {
                if ((IsSharingViolation(ioe)) && (i < (retryCount - 1)))
                {
                    bool wait = true;
                    if (exceptionsCallback != null)
                    {
                        wait = exceptionsCallback(ioe, i, retryCount, waitTime);
                    }
                    if (wait)
                    {
                        System.Threading.Thread.Sleep(waitTime);
                    }
                }
                else
                {
                    throw;
                }
            }
        }
    }

    /// <summary>
    /// Defines a sharing violation wrapper delegate.
    /// </summary>
    public delegate void WrapSharingViolationsCallback();

    /// <summary>
    /// Defines a sharing violation wrapper delegate for handling exception.
    /// </summary>
    public delegate bool WrapSharingViolationsExceptionsCallback(IOException ioe, int retry, int retryCount, int waitTime);

    /// <summary>
    /// Determines whether the specified exception is a sharing violation exception.
    /// </summary>
    /// <param name="exception">The exception. May not be null.</param>
    /// <returns>
    ///     <c>true</c> if the specified exception is a sharing violation exception; otherwise, <c>false</c>.
    /// </returns>
    public static bool IsSharingViolation(IOException exception)
    {
        if (exception == null)
            throw new ArgumentNullException("exception");

        int hr = GetHResult(exception, 0);
        return (hr == -2147024864); // 0x80070020 ERROR_SHARING_VIOLATION

    }

    /// <summary>
    /// Gets the HRESULT of the specified exception.
    /// </summary>
    /// <param name="exception">The exception to test. May not be null.</param>
    /// <param name="defaultValue">The default value in case of an error.</param>
    /// <returns>The HRESULT value.</returns>
    public static int GetHResult(IOException exception, int defaultValue)
    {
        if (exception == null)
            throw new ArgumentNullException("exception");

        try
        {
            const string name = "HResult";
            PropertyInfo pi = exception.GetType().GetProperty(name, BindingFlags.NonPublic | BindingFlags.Instance); // CLR2
            if (pi == null)
            {
                pi = exception.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance); // CLR4
            }
            if (pi != null)
                return (int)pi.GetValue(exception, null);
        }
        catch
        {
        }
        return defaultValue;
    }

私は投げたとのヘルパークラスはこのようなことです。その場合にはそれを制御するアクセスのファイルです。だ見争から々ソフトバンクグループは、このには役に立た.

using System;
using System.IO;
using System.Threading;

/// <summary>
/// This is a wrapper aroung a FileStream.  While it is not a Stream itself, it can be cast to
/// one (keep in mind that this might throw an exception).
/// </summary>
public class SafeFileStream: IDisposable
{
    #region Private Members
    private Mutex m_mutex;
    private Stream m_stream;
    private string m_path;
    private FileMode m_fileMode;
    private FileAccess m_fileAccess;
    private FileShare m_fileShare;
    #endregion//Private Members

    #region Constructors
    public SafeFileStream(string path, FileMode mode, FileAccess access, FileShare share)
    {
        m_mutex = new Mutex(false, String.Format("Global\\{0}", path.Replace('\\', '/')));
        m_path = path;
        m_fileMode = mode;
        m_fileAccess = access;
        m_fileShare = share;
    }
    #endregion//Constructors

    #region Properties
    public Stream UnderlyingStream
    {
        get
        {
            if (!IsOpen)
                throw new InvalidOperationException("The underlying stream does not exist - try opening this stream.");
            return m_stream;
        }
    }

    public bool IsOpen
    {
        get { return m_stream != null; }
    }
    #endregion//Properties

    #region Functions
    /// <summary>
    /// Opens the stream when it is not locked.  If the file is locked, then
    /// </summary>
    public void Open()
    {
        if (m_stream != null)
            throw new InvalidOperationException(SafeFileResources.FileOpenExceptionMessage);
        m_mutex.WaitOne();
        m_stream = File.Open(m_path, m_fileMode, m_fileAccess, m_fileShare);
    }

    public bool TryOpen(TimeSpan span)
    {
        if (m_stream != null)
            throw new InvalidOperationException(SafeFileResources.FileOpenExceptionMessage);
        if (m_mutex.WaitOne(span))
        {
            m_stream = File.Open(m_path, m_fileMode, m_fileAccess, m_fileShare);
            return true;
        }
        else
            return false;
    }

    public void Close()
    {
        if (m_stream != null)
        {
            m_stream.Close();
            m_stream = null;
            m_mutex.ReleaseMutex();
        }
    }

    public void Dispose()
    {
        Close();
        GC.SuppressFinalize(this);
    }

    public static explicit operator Stream(SafeFileStream sfs)
    {
        return sfs.UnderlyingStream;
    }
    #endregion//Functions
}

この作品を名ミューテックス.ご希望の方にそのファイルにアクセス取得を試みることができるように制御されたミューテックス、株式ファイルの名前に'\'sが'/'s)どちらも使用可能でオーディオデータファイルには、屋台までのミューテックスはアクセス又は使用できTryOpen(揃)を取得しようとし、ミューテックス指定された時間のときはfalseを返しますを取得できない時間内にスなサービスを提供しています。これが使用する内部使用のブロックでは、確実にロックが解除され、適切なストリームの場合は開館)に、適切な処分がこのオブジェクト処理.

かったので試~20ものさまざまな書き込みや読み込みファイルのファイルと見なしました。明らかではありませんが、もう大多数の簡単な例です。

この特定のアプリケーションを直接観察のファイルにつく微量のバグが、ファイルサイズが増加します。ここでは二つの異なる戦略とします。

  • Ftpファイルだけを見ます。たとえば送信ファイルimportant.txt とても大事だと思います。仕上がりです。時計に仕上がりファイルが処理のtxt.
  • FTPファイルが名前を変更できます。例えば送ります。お待ちして送信者の名前を変更するimportant.txt が終了しました。

幸運を祈っています。

の技術を使ってあった自分です。基本的には例外をキャッチし、この例外は、再利用、タイマーできる火災のために指定された。がある場合は、より良いください。

から MSDN:

のOnCreatedイベントとして取り上げられるのが早く ファイルが作成されます。場合はファイル れをコピー又は移転され込 たディレクトリのOnCreatedイベント 引き上げの直後 よOnChangedます。

おFileSystemWatcher変更することができないような読み取り/名前の変更時に"OnCreated"イベントではなく:

  1. Spanwsるスレッドは投票のファイルの状態でロックされていないものを使用しFileInfoオブジェクト)
  2. 電話のサービスの処理にファイルなどを決定するファイルはロックされ、準備が整

ほとんどの場合の簡単なアプローチのような@ハーポ提案します。の開発を行うことができますより高度なコードをこのアプローチ:

  • すべての開設を取り扱っており選択されたファイルを使用SystemHandleInformation\SystemProcessInformation
  • サブクラスWaitHandleクラスへのアクセスで内部の対応
  • パスが取り扱うに包まれたサブクラス化WaitHandleにWaitHandle.WaitAny方法

広告への移動過程をトリガーのファイルSameNameASTrasferedFile.trg 作成された後のファイル送信が完了します。

その後の設定FileSystemWatcherる火災イベントのみ※。trgファイルです。

どうなるかはわからないがんで用を決定するファイルのロック状態でのようなことをなすべきます。

while (true)
{
    try {
        stream = File.Open( fileName, fileMode );
        break;
    }
    catch( FileIOException ) {

        // check whether it's a lock problem

        Thread.Sleep( 100 );
    }
}

解決策との組み合わせをfilesystemwatcher一部のポーリングエンジン

取得通知毎に変更はファイルする必要がある場合であって通知確認の場合は ロックとして記されて答え: https://stackoverflow.com/a/50800/6754146 のコードを開filestreamコピーからの答えは、わずかに修正:

public static void CheckFileLock(string directory, string filename, Func<Task> callBack)
{
    var watcher = new FileSystemWatcher(directory, filename);
    FileSystemEventHandler check = 
        async (sender, eArgs) =>
    {
        string fullPath = Path.Combine(directory, filename);
        try
        {
            // Attempt to open the file exclusively.
            using (FileStream fs = new FileStream(fullPath,
                    FileMode.Open, FileAccess.ReadWrite,
                    FileShare.None, 100))
            {
                fs.ReadByte();
                watcher.EnableRaisingEvents = false;
                // If we got this far the file is ready
            }
            watcher.Dispose();
            await callBack();
        }
        catch (IOException) { }
    };
    watcher.NotifyFilter = NotifyFilters.LastWrite;
    watcher.IncludeSubdirectories = false;
    watcher.EnableRaisingEvents = true;
    //Attach the checking to the changed method, 
    //on every change it gets checked once
    watcher.Changed += check;
    //Initially do a check for the case it is already released
    check(null, null);
}

この方法で確認できるファイルがすでに存在する場合、そのロックの場合、その閉鎖を指定したコールバックに、この方法を回避するため、過度に積極的にポーリングだけになる場合が実際に休

いと同じようにGulzarで信を持てるように、ループを実行します。

実は私は全く身に覚えがないのですが邪魔にファイルシステムの観.ポーリング、ネットワークドライブのための新しいファイルを一度分は安いです。

での利用 変更 イベントのNotifyFilter NotifyFilters.LastWrite:

var watcher = new FileSystemWatcher {
      Path = @"c:\temp\test",
      Filter = "*.xml",
      NotifyFilter = NotifyFilters.LastWrite
};
watcher.Changed += watcher_Changed; 
watcher.EnableRaisingEvents = true;

また、同様の問題を追加する場合は、追加する見通し。"使用"保存されます。

string fileName = MessagingBLL.BuildPropertyAttachmentFileName(currProp);

                //create a temporary file to send as the attachment
                string pathString = Path.Combine(Path.GetTempPath(), fileName);

                //dirty trick to make sure locks are released on the file.
                using (System.IO.File.Create(pathString)) { }

                mailItem.Subject = MessagingBLL.PropertyAttachmentSubject;
                mailItem.Attachments.Add(pathString, Outlook.OlAttachmentType.olByValue, Type.Missing, Type.Missing);

このオプション:

private void WaitOnFile(string fileName)
{
    FileInfo fileInfo = new FileInfo(fileName);
    for (long size = -1; size != fileInfo.Length; fileInfo.Refresh())
    {
        size = fileInfo.Length;
        System.Threading.Thread.Sleep(1000);
    }
}

もちろんの場合はfilesizeはpreallocatedの作成ん偽ります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top