Изменить размер файла, не открывая файл - PullRequest
1 голос
/ 14 января 2020

С std::filesystem::resize_file в C ++ можно изменять размер файла, не открывая файл.

Есть ли в C# аналогичная функция, которая позволяет изменять размер файла без его открытия?

Я думаю, что открыть файл как FileStream и сохранить его снова с новым размером будет медленнее.

1 Ответ

5 голосов
/ 14 января 2020

Использование FileStream.SetLength() будет примерно таким же быстрым, как вы можете это сделать.

В итоге вызывается API Windows для установки длины файла, такой же, как 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 API SetFilePointer().)

Это НЕ считывает файл в память.

Кроме того, функция 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);
        }
    }
}

My E: \ диск это жесткий диск, а не SSD.

Вывод был: 00:00:00.0003574

Таким образом, расширение файла до 1 ГБ заняло не более сотни секунд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...