C# 为什么在流中打开的文件不能重命名?

C# 为什么在流中打开的文件不能重命名?,c#,.net,C#,.net,使用下面的代码,我读取一个文件并保持流的打开状态 static void Main(string[] args) { FileStream fileStream = new FileStream(@"C:\temp\test1.txt", FileMode.Open); Console.ReadLine(); } 如果我现在尝试重命名此文件,将显示消息“file in use”。 看起来应该可以重命名文件(在操作系统级别),即使它正在使

使用下面的代码,我读取一个文件并保持流的打开状态

    static void Main(string[] args)
    {
        FileStream fileStream = new FileStream(@"C:\temp\test1.txt", FileMode.Open);
        Console.ReadLine();
    }
如果我现在尝试重命名此文件,将显示消息“file in use”。

看起来应该可以重命名文件(在操作系统级别),即使它正在使用:


当.net将文件加载到流中时,为什么不能重命名该文件?

当您创建
文件流时,您不会将其数据加载到内存中。
当您查找流时,文件内容仍然是从磁盘读取的——当您需要读取大文件时,这是一件好事

如果您只想将整个内容加载到内存中,则可以使用
File.ReadAllBytes
。 您可以在此处阅读更多信息:


注意:如果要使用流而不是字节数组,可以使用
MemoryStream
并将读取的文件内容传递给它。

关于程序集,.NET应该使用类似
FileShare.ReadWrite的方法打开程序集,因此,即使它加载到域中,任何其他进程都可以写入或重命名整个文件

AFAIK,.NET没有用于允许或不允许重命名文件共享的托管
FileShare
enum值(类似于
FileShare.Rename
),但是Win32应该具有这样的功能:程序集加载将创建具有类似
FileShare.ReadWrite | FileShare.Rename
FileShare.Delete
包括重命名,但也包括删除整个文件…)

为了演示这一点,我尝试了以下代码:

    FileStream a = File.Open(@"C:\blah.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    a.Dispose();
当文件流被打开,直到它被释放,我不能删除整个文件,但我可以重命名它

请注意,程序集在需要时加载到
AppDomain
,这意味着您可以编写、删除或重命名程序集,因为它尚未加载

尝试删除已加载到
AppDomain
中的程序集:您不能(我刚才也尝试过,测试代码在控制台应用程序中运行,运行时无法删除可执行文件)。现在尝试重命名它:它可以工作

总结 所有这些都是关于如何打开文件以及打开文件流时使用了哪些文件掩码配置:这就是为什么不能重命名文件,但可以重命名已加载的程序集的原因

像修改下一个一样修改您的代码,您将能够重命名整个文件(甚至删除它!):


由于流具有文件句柄,程序集被加载到内存中,位置变得不相关(发现后)。但据我从中了解,文件名无论如何都不重要。如果存在文件句柄,为什么重要?它只会更改目录项。@GrantTomas以及当程序集加载到
AppDomain
中时会发生什么情况。是否可以删除程序集文件?对于文本文件,请使用file.ReadAllText(以单个字符串的形式获取文件中的所有文本)或file.ReadAllLines(以字符串数组的形式获取文件中的所有文本,文件中每行一个元素)。我知道如何读取文件,但我不明白为什么我可以重命名已执行的程序集,而不能重命名具有句柄的文件。这两个操作都应该只更改有效文件的目录项。@Manuel检查我的答案,我相信,经过一些调查后,我找到了为什么可以或不可以。您可以看到确切的answer在此(也阅读评论):downvoter有任何理由进行downvote吗?我相信这是OP的合理答案。这不是关于diposing或不处理流,而是为什么一些打开的流允许重命名文件和其他no。
    FileStream fileStream = File.Open(@"C:\temp\test1.txt", FileMode.Open, FileShare.ReadWrite | FileShare.Delete);
    Console.ReadLine();