.NET में फ़ाइल के अनलॉक होने तक प्रतीक्षा करें


103

जब तक किसी फ़ाइल को अनलॉक नहीं किया गया है, तब तक एक थ्रेड को ब्लॉक करने का सबसे सरल तरीका क्या है और पढ़ने और नाम बदलने के लिए सुलभ है? उदाहरण के लिए, .NET फ्रेमवर्क में कहीं एक WaitOnFile () है?

मेरे पास एक ऐसी सेवा है जो एक FTP साइट पर संचारित होने वाली फ़ाइलों की तलाश के लिए एक फाइलसिस्टमवॉकर का उपयोग करती है, लेकिन फ़ाइल द्वारा बनाई गई ईवेंट ने दूसरी प्रक्रिया को फ़ाइल लिखने से पहले समाप्त कर दिया है।

आदर्श समाधान में एक टाइमआउट अवधि होगी ताकि धागा देने से पहले हमेशा के लिए लटक न जाए।

संपादित करें: नीचे दिए गए कुछ समाधानों को आज़माने के बाद, मैंने सिस्टम को बदलना समाप्त कर दिया ताकि सभी फ़ाइलों को लिखा जाए Path.GetTempFileName(), फिर File.Move()अंतिम स्थान पर प्रदर्शन किया । जैसे ही FileSystemWatcherईवेंट को निकाल दिया गया, फ़ाइल पहले से ही पूर्ण थी।


4
.NET 4.0 को जारी करने के बाद से, इस समस्या को हल करने का एक बेहतर तरीका है?
जेसन

जवाबों:


40

यह एक संबंधित प्रश्न पर दिया गया उत्तर था :

    /// <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;
    }

8
मुझे यह बदसूरत लगता है लेकिन एकमात्र संभव समाधान है
knupx

6
क्या यह वास्तव में सामान्य मामले में काम करने वाला है? यदि आप फ़ाइल को एक उपयोग () क्लॉज़ में खोलते हैं, तो फ़ाइल का उपयोग बंद हो जाता है और अनलॉक होने पर स्कोप समाप्त हो जाता है। यदि इस तरह की रणनीति का उपयोग करते हुए एक दूसरी प्रक्रिया है (बार-बार रिट्रीट), तो WaitForFile () से बाहर निकलने के बाद, इस बारे में दौड़ की स्थिति है कि क्या फ़ाइल खुली होगी या नहीं। नहीं?
चीज़ो

75
बुरा विचार! जबकि अवधारणा सही है, बूल के बजाय फाइलस्ट्रीम को वापस करने के लिए एक बेहतर समाधान होगा। यदि फ़ाइल को फिर से लॉक किया जाता है तो उपयोगकर्ता को फ़ाइल पर अपना लॉक प्राप्त करने का मौका मिलता है - यदि फ़ंक्शन "झूठा" वापस आ जाता है, तो भी उसे एक अपवाद मिलेगा
Nissim

2
फेरो की विधि कहां है?
Vbp

1
निसिम की टिप्पणी ठीक वही है जो मैं भी सोच रहा था लेकिन अगर आप उस तलाश का उपयोग करने जा रहे हैं तो बाइट पढ़ने के बाद इसे 0 पर रीसेट करना न भूलें। fs.Seek (0, SeekOrigin.Begin);
व्होल

73

एरिक के जवाब से शुरू करके, मैंने कोड को और अधिक कॉम्पैक्ट और पुन: प्रयोज्य बनाने के लिए कुछ सुधार शामिल किए। आशा है कि यह उपयोगी है।

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;
}

16
मैं भविष्य से यह कहने के लिए आया हूं कि यह कोड अभी भी एक आकर्षण की तरह काम करता है। धन्यवाद।
ओनोसेन्डाई

6
@ पाब्लोकोस्टा बिल्कुल! यह इसे बंद नहीं कर सकता , क्योंकि अगर यह किया जाता है, तो एक और धागा इसमें भाग ले सकता है और इसे खोल सकता है, उद्देश्य को हरा सकता है। यह कार्यान्वयन सही है क्योंकि यह इसे खुला रखता है! कॉल करने वाले को इस बारे में चिंता करने दें, यह usingएक नल पर सुरक्षित है , बस usingब्लॉक के अंदर नल की जांच करें ।
doug65536

2
"FileStream fs = null;" कोशिश के बाहर घोषित किया जाना चाहिए लेकिन अंदर के लिए। फिर असाइन करें और कोशिश के अंदर fs का उपयोग करें। कैच ब्लॉक को "if (fs! = Null) fs.Dispose ();" करना चाहिए। (या fs। .Dispose () C # 6 में) यह सुनिश्चित करने के लिए कि फाइलस्ट्रीम को वापस नहीं किया जा रहा है, ठीक से साफ किया गया है।
बिल मेनेस

1
क्या बाइट पढ़ना वास्तव में आवश्यक है? मेरे अनुभव में यदि आपने फ़ाइल को पढ़ने के लिए खोला है, तो आपके पास यह है, इसके लिए परीक्षण करने की आवश्यकता नहीं है। यद्यपि यहाँ डिज़ाइन के साथ आप अनन्य पहुँच के लिए बाध्य नहीं हैं, इसलिए यह संभव है कि आप पहले बाइट को पढ़ने में सक्षम हों, लेकिन कोई अन्य (बाइट स्तर लॉकिंग) नहीं। मूल प्रश्न से आपको केवल-पढ़ने के लिए शेयर स्तर के साथ खुलने की संभावना है, इसलिए कोई अन्य प्रक्रिया फ़ाइल को लॉक या संशोधित नहीं कर सकती है। किसी भी दर पर, मुझे लगता है कि fs.ReadByte () या तो पूरी तरह से बेकार है, या उपयोग के आधार पर पर्याप्त नहीं है।
निकल गया

8
उपयोगकर्ता किस परिस्थिति fsमें catchब्लॉक नहीं हो सकता है ? यदि FileStreamकंस्ट्रक्टर फेंकता है, तो चर को एक मान नहीं सौंपा जाएगा, और इसके अंदर कुछ और नहीं है tryजो एक फेंक सकता है IOException। मेरे लिए ऐसा लगता है कि यह सिर्फ करना ठीक होना चाहिए return new FileStream(...)
मत्ती विर्ककुनेन

18

यहाँ ऐसा करने के लिए एक सामान्य कोड है, फ़ाइल ऑपरेशन से स्वतंत्र। यह इसका उपयोग करने के तरीके पर एक उदाहरण है:

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

या

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

आप रिट्री काउंट को भी परिभाषित कर सकते हैं, और रिट्रीट के बीच प्रतीक्षा समय।

नोट: दुर्भाग्य से, अंतर्निहित Win32 त्रुटि (ERROR_SHARING_VIOLATION) .NET के साथ उजागर नहीं है, इसलिए मैंने इसे 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;
    }

5
वे वास्तव में एक प्रदान कर सकते थे SharingViolationException। वास्तव में, वे अभी भी, पीछे से-अनुकूलता कर सकते हैं, जब तक कि यह नीचे से आता है IOException। और वे वास्तव में, वास्तव में होना चाहिए।
रोमन स्टार्कोव


9
.NET फ्रेमवर्क 4.5, .NET स्टैंडर्ड, और .NET कोर में, HResult एक्सेप्शन क्लास पर एक सार्वजनिक संपत्ति है। अब इसके लिए प्रतिबिंब की आवश्यकता नहीं है। MSDN से:Starting with the .NET Framework 4.5, the HResult property's setter is protected, whereas its getter is public. In previous versions of the .NET Framework, both getter and setter are protected.
NightOwl888

13

मैंने इस तरह की चीजों के लिए एक सहायक वर्ग को एक साथ फेंक दिया। यह काम करेगा यदि आपके पास फ़ाइल को एक्सेस करने वाली हर चीज पर नियंत्रण होगा। यदि आप अन्य चीजों के एक समूह से विवाद की उम्मीद कर रहे हैं, तो यह बहुत बेकार है।

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' में बदल गया)। आप या तो ओपन () का उपयोग कर सकते हैं, जो म्यूटेक्स के सुलभ होने तक स्टाल करेगा या आप ट्रायऑन (टाइमस्पैन) का उपयोग कर सकते हैं, जो म्यूटेक्स को दिए गए अवधि के लिए प्राप्त करने की कोशिश करता है और अगर यह समय अवधि के भीतर हासिल नहीं कर पाता है तो वापस लौट आता है। इसका उपयोग संभवतः एक ब्लॉक के अंदर किया जाना चाहिए, यह सुनिश्चित करने के लिए कि ताले ठीक से जारी किए गए हैं, और इस वस्तु के निपटान के बाद धारा (यदि खुली) का ठीक से निपटान किया जाएगा।

मैंने फ़ाइल का विभिन्न रीड / लिखने के लिए ~ 20 चीजों के साथ एक त्वरित परीक्षण किया और कोई भ्रष्टाचार नहीं देखा। जाहिर है यह बहुत उन्नत नहीं है, लेकिन इसे सरल मामलों के बहुमत के लिए काम करना चाहिए।


5

इस विशेष एप्लिकेशन के लिए सीधे फ़ाइल का निरीक्षण करना अनिवार्य रूप से बग को ट्रेस करने के लिए कठिन हो जाएगा, खासकर जब फ़ाइल का आकार बढ़ता है। यहां दो अलग-अलग रणनीतियां हैं जो काम करेंगी।

  • फीट दो फाइलें लेकिन केवल एक ही देखें। उदाहरण के लिए फ़ाइलें भेजें। महत्वपूर्ण और महत्वपूर्ण। केवल फिनिश फाइल के लिए देखें लेकिन txt को प्रोसेस करें।
  • एफ़टीपी एक फ़ाइल लेकिन जब यह किया नाम बदलें। उदाहरण के लिए महत्वपूर्ण भेजें। प्रतीक्षा करें और प्रेषक का नाम बदलने के लिए इसे समाप्त कर दें।

सौभाग्य!


वह स्वचालित के विपरीत है। यह मैन्युअल रूप से फ़ाइल प्राप्त करने की तरह है, अधिक चरणों के साथ।
हैकलैश

4

कुछ समय पहले मैंने जिन तकनीकों का उपयोग किया था, उनमें से एक अपने स्वयं के फ़ंक्शन को लिखना था। मूल रूप से अपवाद को पकड़ें और टाइमर का उपयोग करके पुनः प्रयास करें जिसे आप एक निर्दिष्ट अवधि के लिए फायर कर सकते हैं। अगर कोई बेहतर तरीका है, तो कृपया साझा करें


3

से MSDN :

फ़ाइल बनाते ही OnCreated ईवेंट उठाया जाता है। यदि किसी फ़ाइल को कॉपी किया गया है या एक देखी गई निर्देशिका में स्थानांतरित किया जा रहा है, तो OnCreated ईवेंट तुरंत उठाया जाएगा, उसके बाद एक या अधिक OnChanged ईवेंट।

आपका FileSystemWatcher को संशोधित किया जा सकता है ताकि यह "OnCreated" इवेंट के दौरान अपना रीड / रीनेम न करे, लेकिन:

  1. एक थ्रेड को फ़ाइल स्थिति को प्रदूषित करता है जब तक कि इसे लॉक नहीं किया जाता है (FileInfo ऑब्जेक्ट का उपयोग करके)
  2. फ़ाइल को संसाधित करने के लिए सेवा में वापस जाता है जैसे ही यह निर्धारित करता है कि फ़ाइल अब बंद नहीं है और जाने के लिए तैयार है

1
फाइलसिस्टम वॉच के धागे को जकड़ने से अंतर्निहित बफर ओवरफ्लो हो सकता है, इस प्रकार बहुत सारी परिवर्तित फाइलें गायब हो जाती हैं। उपभोक्ता / निर्माता कतार बनाने के लिए एक बेहतर तरीका होगा।
निसिम

2

ज्यादातर मामलों में @harpo जैसे सरल दृष्टिकोण काम करेंगे। आप इस दृष्टिकोण का उपयोग करके अधिक परिष्कृत कोड विकसित कर सकते हैं:

  • SystemHandleInformation \ SystemProcessInformation का उपयोग करके चयनित फ़ाइल के लिए सभी खोले गए हैंडल ढूंढें
  • Subclass WaitHandle वर्ग को आंतरिक हैंडल तक पहुंच प्राप्त करने के लिए
  • पास पाए गए हैंडल को उपक्लास्ड वेटहैंडल में वेटहैंडल के लिए लपेटा गया

2

फ़ाइल स्थानांतरण पूर्ण होने के बाद बनाई गई प्रक्रिया ट्रिगर फ़ाइल SameNameASTrasferedFile.trg को स्थानांतरित करने के लिए विज्ञापन।

तब सेटअप फ़ाइलसिस्टमचैकर जो केवल * .trg फ़ाइल पर आग लगा देगा।


1

मुझे नहीं पता कि आप फ़ाइल की लॉक स्थिति का निर्धारण करने के लिए क्या उपयोग कर रहे हैं, लेकिन कुछ ऐसा होना चाहिए।

जबकि (सच)
{
    प्रयत्न {
        स्ट्रीम = File.Open (fileName, fileMode);
        टूटना;
    }
    पकड़ (FileIOException) {

        // जांचें कि क्या यह लॉक की समस्या है

        धागा। सो (100);
    }
}

1
थोड़ी देर, लेकिन जब फ़ाइल किसी तरह बंद हो जाती है तो आप कभी भी अपने लूप से बाहर नहीं निकलेंगे। आपको एक काउंटर जोड़ना चाहिए (1 उत्तर देखें)।
पीटर

0

एक संभावित समाधान होगा, कुछ मतदान के साथ फाइलसिस्टम वॉच को संयोजित करना,

किसी फ़ाइल पर प्रत्येक परिवर्तन के लिए सूचित करें, और जब यह वर्तमान में स्वीकार किए गए उत्तर में बताया गया है, तो अधिसूचित चेक प्राप्त करने के लिए : https://stackoverflow.com/a/50800/6754146 , फ़ाइल नाम के कोड को उत्तर से कॉपी किया जाता है। और थोड़ा संशोधित:

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);
}

इस तरह से आप किसी फ़ाइल की जाँच कर सकते हैं यदि उसका लॉक और निर्दिष्ट कॉलबैक पर बंद होने पर उसे सूचित कर दिया जाए, तो इस तरह से आप अत्यधिक आक्रामक मतदान से बच जाते हैं और केवल तभी काम करते हैं जब वह वास्तव में बंद हो सकता है।


-1

मैं इसे गुलज़ार की तरह ही करता हूं, बस एक लूप के साथ कोशिश करता रहता हूं।

वास्तव में मैं फाइल सिस्टम वॉचर से भी परेशान नहीं हूं। एक मिनट सस्ता होने के बाद नई फ़ाइलों के लिए नेटवर्क ड्राइव करना।


2
यह सस्ता हो सकता है लेकिन एक बार बहुत सारे अनुप्रयोगों के लिए एक मिनट बहुत लंबा है। कभी-कभी वास्तविक समय की निगरानी आवश्यक है। इसके बजाय आपको कुछ ऐसी चीज़ों को लागू करना होगा जो सी # में फाइलसिस्टम संदेशों के लिए सुन रही होंगी (इन चीजों के लिए सबसे सुविधाजनक भाषा नहीं) आप एफएसडब्ल्यू का उपयोग करें।
थंडरग्रास

-1

बस NotifyFilter NotifyFilters.LastWrite के साथ परिवर्तित घटना का उपयोग करें :

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

1
FileSystemWatcher केवल सूचित नहीं करता है जब एक फ़ाइल को लिखा जा रहा है। यह आपको "एकल" तार्किक लिखने के लिए कई बार सूचित करेगा, और यदि आप पहली अधिसूचना प्राप्त करने के बाद फ़ाइल को खोलने का प्रयास करते हैं तो आपको एक अपवाद मिलेगा।
रॉस

-1

मैं आउटलुक अटैचमेंट को जोड़ते समय एक समान मुद्दे में भाग गया। "का उपयोग कर" दिन बचाया।

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);

-3

एक विकल्प के रूप में इसके बारे में कैसे:

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);
    }
}

बेशक अगर फाइल बनाने के लिए प्रचार किया जाता है तो आपको एक झूठी सकारात्मक मिलेगी।


1
यदि फ़ाइल में लिखने की प्रक्रिया एक सेकंड से अधिक समय तक रुकती है, या एक सेकंड से अधिक समय तक स्मृति में बफ़र करता है, तो आपको एक और गलत सकारात्मक मिलेगा। मुझे नहीं लगता कि यह किसी भी परिस्थिति में एक अच्छा समाधान है।
क्रिस वेनहम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.