Beispiel #1
0
        public static void WriteAllBytes(string path, byte[] bytes)
        {
            ArgumentException.ThrowIfNullOrEmpty(path);
            ArgumentNullException.ThrowIfNull(bytes);

            using SafeFileHandle sfh = OpenHandle(path, FileMode.Create, FileAccess.Write, FileShare.Read);
            RandomAccess.WriteAtOffset(sfh, bytes, 0);
        }
        private static void WriteToFile(string path, FileMode mode, string?contents, Encoding encoding)
        {
            ReadOnlySpan <byte> preamble = encoding.GetPreamble();
            int preambleSize             = preamble.Length;

            using SafeFileHandle fileHandle = OpenHandle(path, mode, FileAccess.Write, FileShare.Read, FileOptions.None, 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.
                {
                    RandomAccess.WriteAtOffset(fileHandle, preamble, fileOffset);
                }
                return;
            }

            int bytesNeeded = preambleSize + encoding.GetMaxByteCount(Math.Min(contents.Length, ChunkSize));

            byte[]? rentedBytes = null;
            Span <byte> bytes = bytesNeeded <= 1024 ? stackalloc byte[1024] : (rentedBytes = ArrayPool <byte> .Shared.Rent(bytesNeeded));

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

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

                    RandomAccess.WriteAtOffset(fileHandle, toStore, fileOffset);

                    fileOffset  += toStore.Length;
                    preambleSize = 0;
                }
            }
            finally
            {
                if (rentedBytes is not null)
                {
                    ArrayPool <byte> .Shared.Return(rentedBytes);
                }
            }
        }
        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 #4
0
        private static async Task <byte[]> InternalReadAllBytesUnknownLengthAsync(SafeFileHandle sfh, CancellationToken cancellationToken)
        {
            byte[] rentedArray = ArrayPool <byte> .Shared.Rent(512);

            try
            {
                int bytesRead = 0;
                while (true)
                {
                    if (bytesRead == rentedArray.Length)
                    {
                        uint newLength = (uint)rentedArray.Length * 2;
                        if (newLength > Array.MaxLength)
                        {
                            newLength = (uint)Math.Max(Array.MaxLength, rentedArray.Length + 1);
                        }

                        byte[] tmp = ArrayPool <byte> .Shared.Rent((int)newLength);

                        Buffer.BlockCopy(rentedArray, 0, tmp, 0, bytesRead);

                        byte[] toReturn = rentedArray;
                        rentedArray = tmp;

                        ArrayPool <byte> .Shared.Return(toReturn);
                    }

                    Debug.Assert(bytesRead < rentedArray.Length);
                    int n = await RandomAccess.ReadAtOffsetAsync(sfh, rentedArray.AsMemory(bytesRead), bytesRead, cancellationToken).ConfigureAwait(false);

                    if (n == 0)
                    {
                        return(rentedArray.AsSpan(0, bytesRead).ToArray());
                    }
                    bytesRead += n;
                }
            }
            finally
            {
                sfh.Dispose();
                ArrayPool <byte> .Shared.Return(rentedArray);
            }
        }
Beispiel #5
0
        public static byte[] ReadAllBytes(string path)
        {
            // SequentialScan is a perf hint that requires extra sys-call on non-Windows OSes.
            FileOptions options = OperatingSystem.IsWindows() ? FileOptions.SequentialScan : FileOptions.None;

            using (SafeFileHandle sfh = OpenHandle(path, FileMode.Open, FileAccess.Read, FileShare.Read, options))
            {
                long fileLength = 0;
                if (sfh.CanSeek && (fileLength = sfh.GetFileLength()) > Array.MaxLength)
                {
                    throw new IOException(SR.IO_FileTooLong2GB);
                }

#if DEBUG
                fileLength = 0; // improve the test coverage for ReadAllBytesUnknownLength
#endif

                if (fileLength == 0)
                {
                    // Some file systems (e.g. procfs on Linux) return 0 for length even when there's content; also there are non-seekable files.
                    // Thus we need to assume 0 doesn't mean empty.
                    return(ReadAllBytesUnknownLength(sfh));
                }

                int    index = 0;
                int    count = (int)fileLength;
                byte[] bytes = new byte[count];
                while (count > 0)
                {
                    int n = RandomAccess.ReadAtOffset(sfh, bytes.AsSpan(index, count), index);
                    if (n == 0)
                    {
                        ThrowHelper.ThrowEndOfFileException();
                    }

                    index += n;
                    count -= n;
                }
                return(bytes);
            }
        }
Beispiel #6
0
        private static async Task <byte[]> InternalReadAllBytesAsync(SafeFileHandle sfh, int count, CancellationToken cancellationToken)
        {
            using (sfh)
            {
                int    index = 0;
                byte[] bytes = new byte[count];
                do
                {
                    int n = await RandomAccess.ReadAtOffsetAsync(sfh, bytes.AsMemory(index), index, cancellationToken).ConfigureAwait(false);

                    if (n == 0)
                    {
                        ThrowHelper.ThrowEndOfFileException();
                    }

                    index += n;
                } while (index < count);

                return(bytes);
            }
        }
Beispiel #7
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);
 }