【问题标题】:Filestream writing to file and reading the bfile文件流写入文件并读取 bfile
【发布时间】:2010-06-08 17:31:30
【问题描述】:

我有一个 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)

【问题讨论】:

  • 相当高的 WTF/LOC 比率,我必须说...

标签: c# .net filestream


【解决方案1】:

您会得到一个FileNotFoundException,因为您在实际写入文件之前将文件名添加到字典中。因此,对同一文件的并发操作会导致此问题。

在写入后将其添加到字典只会产生一个新问题:它会同时开始尝试写入文件(并且失败得很惨)。如果性能很关键,我会将我的字典更改为 Dictionary&lt;string, object&gt; 并将该值用作文件级别的同步对象。您还需要添加一个单独的同步对象来检查并添加到字典本身。

不过,这可能有点矫枉过正,需要手动使用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,因为您似乎只使用键,而不是值。

【讨论】:

    【解决方案2】:

    这是线程问题。

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

    【讨论】:

    • 但这并不是问题的全部。改变这两个操作的顺序会导致一个新的潜在问题(见我的回答)。
    猜你喜欢
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    • 2011-10-16
    • 2019-01-24
    • 2021-09-11
    • 1970-01-01
    • 2018-08-07
    相关资源
    最近更新 更多