private static async Task WriteToFileAsync(string path, FileMode mode, string?contents, Encoding encoding, CancellationToken cancellationToken)
        {
            ReadOnlyMemory <byte> preamble = encoding.GetPreamble();
            int preambleSize = preamble.Length;

            using SafeFileHandle fileHandle = OpenHandle(path, mode, FileAccess.Write, FileShare.Read, FileOptions.Asynchronous, GetPreallocationSize(mode, contents, encoding, preambleSize));
            long fileOffset = mode == FileMode.Append && fileHandle.CanSeek ? RandomAccess.GetLength(fileHandle) : 0;

            if (string.IsNullOrEmpty(contents))
            {
                if (preambleSize > 0 && // even if the content is empty, we want to store the preamble
                    fileOffset == 0)    // if we're appending to a file that already has data, don't write the preamble.
                {
                    await RandomAccess.WriteAtOffsetAsync(fileHandle, preamble, fileOffset, cancellationToken).ConfigureAwait(false);
                }
                return;
            }

            byte[] bytes = ArrayPool <byte> .Shared.Rent(preambleSize + encoding.GetMaxByteCount(Math.Min(contents.Length, ChunkSize)));

            try
            {
                if (fileOffset == 0)
                {
                    preamble.CopyTo(bytes);
                }
                else
                {
                    preambleSize = 0; // don't append preamble to a non-empty file
                }

                Encoder encoder = encoding.GetEncoder();
                ReadOnlyMemory <char> remaining = contents.AsMemory();
                while (!remaining.IsEmpty)
                {
                    ReadOnlyMemory <char> toEncode = remaining.Slice(0, Math.Min(remaining.Length, ChunkSize));
                    remaining = remaining.Slice(toEncode.Length);
                    int encoded = encoder.GetBytes(toEncode.Span, bytes.AsSpan(preambleSize), flush: remaining.IsEmpty);
                    ReadOnlyMemory <byte> toStore = new ReadOnlyMemory <byte>(bytes, 0, preambleSize + encoded);

                    await RandomAccess.WriteAtOffsetAsync(fileHandle, toStore, fileOffset, cancellationToken).ConfigureAwait(false);

                    fileOffset  += toStore.Length;
                    preambleSize = 0;
                }
            }
            finally
            {
                ArrayPool <byte> .Shared.Return(bytes);
            }
        }
Beispiel #2
0
 static async Task Core(string path, byte[] bytes, CancellationToken cancellationToken)
 {
     using SafeFileHandle sfh = OpenHandle(path, FileMode.Create, FileAccess.Write, FileShare.Read, FileOptions.Asynchronous);
     await RandomAccess.WriteAtOffsetAsync(sfh, bytes, 0, cancellationToken).ConfigureAwait(false);
 }