2010-06-08 103 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