using 子句会关闭该流吗?

发布于 2024-07-16 09:15:52 字数 1998 浏览 8 评论 0原文

显然我已经养成了不好的编码习惯。 这是我一直在编写的代码示例:

using(StreamReader sr = new StreamReader(File.Open("somefile.txt", FileMode.Open)))
{
    //read file
}
File.Move("somefile.txt", "somefile.bak"); //can't move, get exception that I the file is open

我认为这是因为 using 子句显式调用了 Close()Dispose()StreamReader 上,FileStream 也将被关闭。

我可以解决我遇到的问题的唯一方法是将上面的块更改为:

using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
{
  using(StreamReader sr = new StreamReader(fs))
  {
    //read file
  }
}

File.Move("somefile.txt", "somefile.bak"); // can move file with no errors

是否应该通过在第一个块中进行处理来关闭 StreamReader 也关闭底层 FileStream? 或者说,我错了?

编辑

我决定发布实际的有问题的代码块,看看我们是否能弄清楚这一点。 我现在只是好奇。

我以为我在 using 子句中遇到了问题,所以我将所有内容展开,但每次仍然无法复制。 我在此方法调用中创建了该文件,因此我认为该文件上没有其他任何东西打开了句柄。 我还验证了从 Path.Combine 调用返回的字符串是否正确。

private static void GenerateFiles(List<Credit> credits)
{
    Account i;
    string creditFile = Path.Combine(Settings.CreditLocalPath, DateTime.Now.ToString("MMddyy-hhmmss") + ".credits");

    StreamWriter creditsFile = new StreamWriter(File.Open(creditFile, FileMode.Create));

    creditsFile.WriteLine("code\inc");

    foreach (Credit c in credits)
    {
        if (DataAccessLayer.AccountExists(i))
        {
            string tpsAuth = DataAccessLayer.GetAuthCode(i.Pin);
            creditsFile.WriteLine(String.Format("{0}{1}\t{2:0.00}", i.AuthCode, i.Pin, c.CreditAmount));
        }
        else
        {
            c.Error = true;
            c.ErrorMessage = "NO ACCOUNT";
        }

        DataAccessLayer.AddCredit(c);

    }

    creditsFile.Close();
    creditsFile.Dispose();

    string dest =  Path.Combine(Settings.CreditArchivePath, Path.GetFileName(creditFile));
    File.Move(creditFile,dest);
    //File.Delete(errorFile);
}

I've apparently worked myself into a bad coding habit. Here is an example of the code I've been writing:

using(StreamReader sr = new StreamReader(File.Open("somefile.txt", FileMode.Open)))
{
    //read file
}
File.Move("somefile.txt", "somefile.bak"); //can't move, get exception that I the file is open

I thought that because the using clause explicitly called Close() and Dispose() on the StreamReader that the FileStream would be closed as well.

The only way I could fix the problem I was having was by changing the above block to this:

using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
{
  using(StreamReader sr = new StreamReader(fs))
  {
    //read file
  }
}

File.Move("somefile.txt", "somefile.bak"); // can move file with no errors

Should closing the StreamReader by disposing in the first block also close the underlying FileStream? Or, was I mistaken?

Edit

I decided to post the actual offending block of code, to see if we can get to the bottom of this. I am just curious now.

I thought I had a problem in the using clause, so I expanded everything out, and it still can't copy, every time. I create the file in this method call, so I don't think anything else has a handle open on the file. I've also verified that the strings returned from the Path.Combine calls are correct.

private static void GenerateFiles(List<Credit> credits)
{
    Account i;
    string creditFile = Path.Combine(Settings.CreditLocalPath, DateTime.Now.ToString("MMddyy-hhmmss") + ".credits");

    StreamWriter creditsFile = new StreamWriter(File.Open(creditFile, FileMode.Create));

    creditsFile.WriteLine("code\inc");

    foreach (Credit c in credits)
    {
        if (DataAccessLayer.AccountExists(i))
        {
            string tpsAuth = DataAccessLayer.GetAuthCode(i.Pin);
            creditsFile.WriteLine(String.Format("{0}{1}\t{2:0.00}", i.AuthCode, i.Pin, c.CreditAmount));
        }
        else
        {
            c.Error = true;
            c.ErrorMessage = "NO ACCOUNT";
        }

        DataAccessLayer.AddCredit(c);

    }

    creditsFile.Close();
    creditsFile.Dispose();

    string dest =  Path.Combine(Settings.CreditArchivePath, Path.GetFileName(creditFile));
    File.Move(creditFile,dest);
    //File.Delete(errorFile);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

隱形的亼 2024-07-23 09:15:52

是的,StreamReader.Dispose 关闭底层流(对于创建流的所有公共方式)。 不过,还有一个更好的替代方案:

using (TextReader reader = File.OpenText("file.txt"))
{
}

这还有一个额外的好处,即它会打开底层流,并向 Windows 提示您将按顺序访问它。

这是一个测试应用程序,它显示了对我有用的第一个版本。 我并不是想说这是任何特别的证据 - 但我很想知道它对你有多有效。

using System;
using System.IO;

class Program
{
    public static void Main(string[] args)
    {
        for (int i=0; i < 1000; i++)
        {
            using(StreamReader sr = new StreamReader
                  (File.Open("somefile.txt", FileMode.Open)))
            {
                Console.WriteLine(sr.ReadLine());
            }
            File.Move("somefile.txt", "somefile.bak");
            File.Move("somefile.bak", "somefile.txt");
        }
    }
}

如果有效,则表明这与您在阅读时所做的事情有关...

现在这是您编辑的问题代码的缩短版本 - 即使在网络共享上,它也对我来说效果很好。 请注意,我已将 FileMode.Create 更改为 FileMode.CreateNew - 否则可能仍然有一个带有旧版本句柄的应用程序文件,可能。 这对你有用吗?

using System;
using System.IO;

public class Test
{    
    static void Main()
    {
        StreamWriter creditsFile = new StreamWriter(File.Open("test.txt", 
                                          FileMode.CreateNew));

        creditsFile.WriteLine("code\\inc");

        creditsFile.Close();
        creditsFile.Dispose();

        File.Move("test.txt", "test2.txt");
    }
}

Yes, StreamReader.Dispose closes the underlying stream (for all public ways of creating one). However, there's a nicer alternative:

using (TextReader reader = File.OpenText("file.txt"))
{
}

This has the added benefit that it opens the underlying stream with a hint to Windows that you'll be accessing it sequentially.

Here's a test app which shows the first version working for me. I'm not trying to say that's proof of anything in particular - but I'd love to know how well it works for you.

using System;
using System.IO;

class Program
{
    public static void Main(string[] args)
    {
        for (int i=0; i < 1000; i++)
        {
            using(StreamReader sr = new StreamReader
                  (File.Open("somefile.txt", FileMode.Open)))
            {
                Console.WriteLine(sr.ReadLine());
            }
            File.Move("somefile.txt", "somefile.bak");
            File.Move("somefile.bak", "somefile.txt");
        }
    }
}

If that works, it suggests that it's something to do with what you do while reading...

And now here's a shortened version of your edited question code - which again works fine for me, even on a network share. Note that I've changed FileMode.Create to FileMode.CreateNew - as otherwise there could still have been an app with a handle on the old file, potentially. Does this work for you?

using System;
using System.IO;

public class Test
{    
    static void Main()
    {
        StreamWriter creditsFile = new StreamWriter(File.Open("test.txt", 
                                          FileMode.CreateNew));

        creditsFile.WriteLine("code\\inc");

        creditsFile.Close();
        creditsFile.Dispose();

        File.Move("test.txt", "test2.txt");
    }
}
眼角的笑意。 2024-07-23 09:15:52

注意 - 您的 using 块不需要嵌套在它们自己的块中 - 它们可以是连续的,如下所示:

using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
using(StreamReader sr = new StreamReader(fs))
{
    //read file
}

在这种情况下的处置顺序仍然与嵌套块相同(即, StreamReader 仍将在 FileStream 之前处置在这种情况下)。

Note - your using blocks do not need to be nested in their own blocks - they can be sequential, as in:

using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
using(StreamReader sr = new StreamReader(fs))
{
    //read file
}

The order of disposal in this case is still the same as the nested blocks (ie, the StreamReader will still dispose before the FileStream in this case).

贪恋 2024-07-23 09:15:52

我会尝试使用 FileInfo.Open()FileInfo.MoveTo() 而不是 File.Open()File。移动()。 您还可以尝试使用FileInfo.OpenText()。 但这些只是建议。

I would try to use FileInfo.Open() and FileInfo.MoveTo() instead of File.Open() and File.Move(). You could also try to use FileInfo.OpenText(). But these are just suggestions.

╰沐子 2024-07-23 09:15:52

是否有可能其他东西锁定了 somefile.txt?

从本地(到文件)命令行进行简单的检查

net files

可能会为您提供一些线索,看看是否有其他东西有锁。

或者,您可以使用 FileMon 来获取更多详细信息,并且检查您的应用程序是否正常发布。

Is there any possibility that something else has a lock to somefile.txt?

A simple check from a local (to the file) cmd line

net files

may well give you some clues if anything else has a lock.

Alternatively you can get something like FileMon to take even more details, and check that your app is releasing properly.

御守 2024-07-23 09:15:52

由于这似乎不是一个编码问题,因此我将戴上我的系统管理员帽子并提供一些建议。

  1. 客户端或服务器上的病毒扫描程序在创建文件时对其进行扫描。
  2. Windows机会主义锁定有搞砸网络共享的习惯。 我记得这主要是具有平面文件数据库的多个读/写客户端的问题,但是缓存肯定可以解释你的问题。
  3. Windows 文件打开缓存。 我不确定这在 Win2K 中是否仍然是一个问题,但 FileMon 会告诉你。

编辑:如果您可以从服务器计算机实时捕获它,那么 Sysinternal 的句柄将告诉您它打开了什么。

Since this doesn't seem to be a coding issue, I'm going to put my syadmin hat on and offer a few suggestions.

  1. Virus scanner on either the client or server that's scanning the file as it's created.
  2. Windows opportunistic locking has a habit of screwing things up on network shares. I recall it being mostly an issue with multiple read/write clients with flat file databases, but caching could certainly explain your problem.
  3. Windows file open cache. I'm not sure if this is still a problem in Win2K or not, but FileMon would tell you.

Edit: If you can catch it in the act from the server machine, then Sysinternal's Handle will tell you what has it open.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文