首页 > 解决方案 > 在不打开文件的情况下更改文件的大小

问题描述

std::filesystem::resize_fileC++ 中,可以在不打开文件的情况下更改文件的大小。

C#中是否有任何类似的功能,允许在不打开文件的情况下更改文件的大小?

我认为将文件作为 FileStream 打开并以新大小再次保存会更慢。

标签: c#filesize

解决方案


使用FileStream.SetLength()将尽可能快。

它最终调用 Windows API 来设置文件的长度,与 std::filesystem::resize_file().

所以你只需要做这样的事情,它就会足够快:

using (var file = File.Open(myFilePath, FileMode.Open))
{
    file.SetLength(myRequiredFileSize);
}

FileStream.SetLength() 的实现是:

    private void SetLengthCore(long value)
    {
        Contract.Assert(value >= 0, "value >= 0");
        long origPos = _pos;

        if (_exposedHandle)
            VerifyOSHandlePosition();
        if (_pos != value)
            SeekCore(value, SeekOrigin.Begin);
        if (!Win32Native.SetEndOfFile(_handle)) {
            int hr = Marshal.GetLastWin32Error();
            if (hr==__Error.ERROR_INVALID_PARAMETER)
                throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_FileLengthTooBig"));
            __Error.WinIOError(hr, String.Empty);
        }
        // Return file pointer to where it was before setting length
        if (origPos != value) {
            if (origPos < value)
                SeekCore(origPos, SeekOrigin.Begin);
            else
                SeekCore(0, SeekOrigin.End);
        }
    }

(注意SeekCore()只调用 Windows APISetFilePointer()函数。)

这样做不会将文件读入内存。

此外,Windows API 函数SetEndOfFile()不会写入扩展区域,因此速度很快。文档指出If the file is extended, the contents of the file between the old end of the file and the new end of the file are not defined.- 这是由于数据未写入扩展区域。

作为测试,我尝试了以下代码:

using System;
using System.Diagnostics;
using System.IO;

namespace Demo
{
    public class Program
    {
        public static void Main()
        {
            string filename = @"e:\tmp\test.bin";
            File.WriteAllBytes(filename, new byte[0]); // Create empty file.

            var sw = Stopwatch.StartNew();

            using (var file = File.Open(filename, FileMode.Open))
            {
                file.SetLength(1024*1024*1024);
            }

            Console.WriteLine(sw.Elapsed);
        }
    }
}

我的 E:\ 驱动器是硬盘驱动器,而不是 SSD。

输出是:00:00:00.0003574

因此,将文件扩展至 1GB 只需不到百分之一秒。


推荐阅读