2010-06-08 102 views
3

我有一個Web服務,檢查字典,看看是否存在一個文件,然後如果它存在它讀取文件,否則它保存到文件。這是來自一個網絡應用程序。我不知道最好的辦法是什麼,因爲如果同時訪問同一個文件,我偶爾會得到FileNotFoundException異常。 下面的代碼的相關部分:文件流寫入文件和讀取文件

String signature; 
signature = "FILE," + value1 + "," + value2 + "," + value3 + "," + value4;  // this is going to be the filename 

string result;    
MultipleRecordset mrSummary = new MultipleRecordset(); // MultipleRecordset is an object that retrieves data from a sql server database 

if (mrSummary.existsFile(signature)) 
{     
    result = mrSummary.retrieveFile(signature);     
} 
else 
{     
    result = mrSummary.getMultipleRecordsets(System.Configuration.ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString.ToString(), value1, value2, value3, value4); 
    mrSummary.saveFile(signature, result); 
} 

下面的代碼,看看是否該文件已經存在:

private static Dictionary<String, bool> dict = new Dictionary<String, bool>(); 

public bool existsFile(string signature) 
{      
    if (dict.ContainsKey(signature)) 
    { 
     return true; 
    } 
    else 
    { 
     return false; 
    }         
} 

這是我用來檢索如果它已經存在:

try 
{        

    byte[] buffer; 
    FileStream fileStream = new FileStream(@System.Configuration.ConfigurationManager.AppSettings["CACHEPATH"] + filename, FileMode.Open, FileAccess.Read, FileShare.Read); 
     try 
     { 
     int length = 0x8000; // get file length 
     buffer = new byte[length];   // create buffer 
     int count;       // actual number of bytes read 
     JSONstring = ""; 
     while ((count = fileStream.Read(buffer, 0, length)) > 0) 
     { 
      JSONstring += System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, count); 
     } 
     } 
     finally 
     { 
     fileStream.Close(); 
     } 
} 
catch (Exception e) 
{ 

    JSONstring = "{\"error\":\"" + e.ToString() + "\"}";     
} 

如果該文件以前不存在,則會將JSON保存到文件中:

try 
{     
    if (dict.ContainsKey(filename) == false) 
    { 
     dict.Add(filename, true); 
    } 
    else 
    { 
     this.retrieveFile(filename, ipaddress); 
    } 

} 
catch 
{ 


} 


try 
{ 
    TextWriter tw = new StreamWriter(@System.Configuration.ConfigurationManager.AppSettings["CACHEPATH"] + filename); 
    tw.WriteLine(JSONstring); 
    tw.Close(); 
} 
catch { 

} 

這裏有詳細的例外,我有時運行上面的代碼獲得:

System.IO.FileNotFoundException: Could not find file 'E:\inetpub\wwwroot\cache\FILE,36,36.25,14.5,14.75'. 
File name: 'E:\inetpub\wwwroot\cache\FILE,36,36.25,14.5,14.75' 
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 
    at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) 
    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) 
    at com.myname.business.MultipleRecordset.retrieveFile(String filename, String ipaddress) 
+2

相當高的WTF/LOC比之前,我必須說... – SWeko 2010-06-08 17:42:05

回答

3

,因爲你實際上在寫入文件前將文件名添加到字典中你得到一個FileNotFoundException。因此,對同一個文件的併發操作會導致這個問題。

寫入後將其添加到字典中將只會產生一個新問題:它將開始嘗試同時寫入文件(並且失敗)。如果性能很關鍵,我會將字典更改爲Dictionary<string, object>,並將該值用作文件級別的同步對象。您還需要添加一個單獨的同步對象來檢查和添加到字典本身。

然而,這可能是矯枉過正,它需要手動使用Monitor.EnterMonitor.Exit。這裏有一個稍微簡單的實現:

static HashSet<string> files = new HashSet<string>(); 
static object syncRoot = new object(); 

void Whatever(string filename, string ipaddress) 
{ 
    bool fileFound; 

    lock (syncRoot) 
    { 
     fileFound = files.Contains(filename); 
     if (!fileFound) 
     { 
      files.Add(filename); 
      // Code to write file here 
     } 
    } 

    if (fileFound) 
    { 
     retrieveFile(filename, ipaddress); 
    } 
} 

當一個寫操作完成,性能會有點次優的,因爲直到寫入完成了它阻止所有讀取操作。如果大部分操作都是讀取操作,則這不是問題。

在這個例子中,我已經將你的字典更改爲HashSet,因爲你似乎只使用密鑰而不是值。

+0

謝謝 - 你的實施效果很好。 – user220511 2010-06-09 17:26:57

1

這是一個線程問題。

的FileNotFoundException異常是在這條線發生

FileStream fileStream = new FileStream(System.Configuration.ConfigurationManager.AppSettings["CACHEPATH"] + filename, FileMode.Open, FileAccess.Read, FileShare.Read); 

,因爲該文件不存在。

你打電話

dict.Add(filename, true); 

創建文件

TextWriter tw = new StreamWriter(@System.Configuration.ConfigurationManager.AppSettings["CACHEPATH"] + filename); 
tw.WriteLine(JSONstring); 
tw.Close(); 

這會導致你的測試文件的存在是不準確的

public bool existsFile(string signature)  
{        
    if (dict.ContainsKey(signature))  
    {  
     return true;  
    }  
    else  
    {  
     return false;  
    }          
} 
+0

然而,這不是全部問題。改變這兩個操作的順序將導致新的潛在問題(請參閱我的答案)。 – Thorarin 2010-06-08 18:14:07