.NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)

栏目: IT技术 · 发布时间: 4年前

内容简介:.NET 中文件打开的 API文件打开的多个重载方法中,除了封装好的

.NET 中文件打开的 API File.Open 提供了多种不同的文件打开方式,这些方式大多数与 Windows 文件 API 中的模式是对应的,但也有一些 .NET 层面的判断以及名称的变化。在 .NET 层你可以选择适合你业务场景需要的文件打开方式。

文件打开方式

文件打开的多个重载方法中,除了封装好的 OpenRead / OpenWrite 之外,其他都是需要指定 FileMode 参数的。

public static FileStream Open(string path, FileMode mode);

FileMode

FileMode 枚举有 6 种不同的值:

public enum FileMode
{
    CreateNew = 1,
    Create = 2,
    Open = 3,
    OpenOrCreate = 4,
    Truncate = 5,
    Append = 6,
}

注意,在 File.Open 方法中传入以下这些参数的含义描述中可能有一些包含过程和判断的语句,但实际上这些真正的判断和过程发生在 Windows 内核(虽然 .NET 也有一些判断,但是一些参数预判断和参数转换),所以实际拿到文件流(对应 Win32 中拿到句柄)是一个原子操作,不会因为中间加了判断导致与其他线程发生竞争。

CreateNew

如果文件不存在,则创建一个新的文件并返回新文件的文件流。如果文件已经存在,则抛出 IOException

Create

如果文件不存在,则创建一个新的文件并返回新文件的文件流。如果文件已经存在,则打开文件并返回此文件的文件流。

基于此文件流的修改会完全复写文件。也就是说,如果原文件内容是 walterlv ,通过此文件流写入 111 ,那么最终文件内容是 111

Open

如果文件存在,则打开文件并返回此文件的文件流。如果文件不存在,则抛出 FileNotFoundException

基于此文件流的修改不会截断文件。也就是说,如果原文件内容是 walterlv ,通过此文件流写入 111 ,那么最终文件内容是 111terlv

OpenOrCreate

如果文件存在,则打开文件并返回此文件的文件流。如果文件不存在,则创建一个文件并返回新文件的文件流。

基于此文件流的修改不会截断文件。也就是说,如果原文件内容是 walterlv ,通过此文件流写入 111 ,那么最终文件内容是 111terlv

Truncate

如果文件存在,则打开后文件的长度直接变为 0,随后返回此文件的文件流。如果文件不存在,则会抛出 FileNotFoundException

由于在打开文件时就已经将文件设置为 0 字节,所以对应到上面截断的描述是一定会截断的。写入任何新内容到文件候,文件中都不会存在旧文件中的内容。

Append

如果文件不存在,则创建一个新的文件并返回新文件的文件流。如果文件已经存在,则创建一个可以往文件的结尾处开始写的文件流。

如果试图从文件流中往前倒推找到此前的文件内容,会抛出 IOException

总结表

FileMode 如果文件存在 如果文件不存在
CreateNew IOException 新建
Create 截断 新建
Open 打开 FileNotFoundException
OpenOrCreate 打开 新建
Truncate 截断 FileNotFoundException
Append 追加 新建

所有这些打开模式都不会修改到文件的属性(Attribute),包括创建时间、针对用户的权限设置。所以如果你希望连这些属性都不需要,而是完完全全创建新的文件,那么请先将原来的文件删除。

配合文件打开权限

在以上这些 FileMode 中, CreateNewCreateTruncateAppend 都是需要写文件的权限的, OpenOrCreate 是否需要写权限则取决于文件是否存在。

附源码

以下是 FileStream 中的 Open 方法最终调用处。可以发现,此方法将传入的 FileMode 转换成了 Win32 中的值,并且最终调用了 Windows API CreateFile

你可以阅读我的另一篇博客了解 Win32 API 中的 CreateFile

private unsafe SafeFileHandle CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options)
{
    Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);

    int fAccess =
        ((_access & FileAccess.Read) == FileAccess.Read ? Interop.Kernel32.GenericOperations.GENERIC_READ : 0) |
        ((_access & FileAccess.Write) == FileAccess.Write ? Interop.Kernel32.GenericOperations.GENERIC_WRITE : 0);

    // Our Inheritable bit was stolen from Windows, but should be set in
    // the security attributes class.  Don't leave this bit set.
    share &= ~FileShare.Inheritable;

    // Must use a valid Win32 constant here...
    if (mode == FileMode.Append)
        mode = FileMode.OpenOrCreate;

    int flagsAndAttributes = (int)options;

    // For mitigating local elevation of privilege attack through named pipes
    // make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
    // named pipe server can't impersonate a high privileged client security context
    // (note that this is the effective default on CreateFile2)
    flagsAndAttributes |= (Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT | Interop.Kernel32.SecurityOptions.SECURITY_ANONYMOUS);

    using (DisableMediaInsertionPrompt.Create())
    {
        Debug.Assert(_path != null);
        return ValidateFileHandle(
            Interop.Kernel32.CreateFile(_path, fAccess, share, ref secAttrs, mode, flagsAndAttributes, IntPtr.Zero));
    }
}
// Contains constants for specifying how the OS should open a file.
// These will control whether you overwrite a file, open an existing
// file, or some combination thereof.
//
// To append to a file, use Append (which maps to OpenOrCreate then we seek
// to the end of the file).  To truncate a file or create it if it doesn't
// exist, use Create.
//
public enum FileMode
{
    // Creates a new file. An exception is raised if the file already exists.
    CreateNew = 1,

    // Creates a new file. If the file already exists, it is overwritten.
    Create = 2,

    // Opens an existing file. An exception is raised if the file does not exist.
    Open = 3,

    // Opens the file if it exists. Otherwise, creates a new file.
    OpenOrCreate = 4,

    // Opens an existing file. Once opened, the file is truncated so that its
    // size is zero bytes. The calling process must open the file with at least
    // WRITE access. An exception is raised if the file does not exist.
    Truncate = 5,

    // Opens the file if it exists and seeks to the end.  Otherwise,
    // creates a new file.
    Append = 6,
}

参考资料


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

标签

标签

Gene Smith / 张军、陈军亮 / 机械工业出版社 / 2012-6 / 59.00元

本书对标记系统这一概念的内涵和外延进行了系统化的、深入浅出的阐述。从什么是标记系统、标记系统有什么价值,到标记系统的架构和与其他分类系统的对比,再到标签的呈现方式和标记系统的实现细节,作者都用通俗易懂的语言进行了阐述,并附有详细的示例和具体的案例研究。本书的每一章都涵盖了标记系统的一个方面,主要内容包括:标记系统的模型、价值、架构,标签的分类、可视化、管理方法,最后介绍标记系统设计方法。本书带领读......一起来看看 《标签》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具