/// <summary>
        /// Initializes a new instance of <see cref="AutoSaveTextFile{TUpdate}"/>.
        /// </summary>
        /// <param name="remoteState">
        /// Object responsible for converting updates to text.
        /// </param>
        /// <param name="autoSaveFiles">
        /// The <see cref="FileStreamPair"/> containing <see cref="FileStream"/>s to write to.
        /// Any existing contents in the files will be overwritten.
        /// <see cref="AutoSaveTextFile{TUpdate}"/> assumes ownership of the <see cref="FileStream"/>s
        /// so it takes care of disposing it after use.
        /// To be used as an auto-save <see cref="FileStream"/>,
        /// it must support seeking, reading and writing, and not be able to time out.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="remoteState"/> and/or <paramref name="autoSaveFiles"/> are null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// One or both <see cref="FileStream"/>s in <paramref name="autoSaveFiles"/>
        /// do not have the right capabilities to be used as an auto-save file stream.
        /// See also: <seealso cref="CanAutoSaveTo"/>.
        /// </exception>
        public AutoSaveTextFile(RemoteState remoteState, FileStreamPair autoSaveFiles)
        {
            if (remoteState == null)
            {
                throw new ArgumentNullException(nameof(remoteState));
            }
            AutoSaveFiles = autoSaveFiles ?? throw new ArgumentNullException(nameof(autoSaveFiles));

            // Assert capabilities of the file streams.
            VerifyFileStream(autoSaveFiles.FileStream1, nameof(autoSaveFiles));
            VerifyFileStream(autoSaveFiles.FileStream2, nameof(autoSaveFiles));

            // Immediately attempt to load the saved contents from either FileStream.
            // Choose first auto-save file to load from.
            FileStream latestAutoSaveFile = autoSaveFiles.FileStream1.Length == 0 ? autoSaveFiles.FileStream2 : autoSaveFiles.FileStream1;

            string loadedText = null;

            try
            {
                loadedText = Load(latestAutoSaveFile);
            }
            catch (Exception firstLoadException)
            {
                // Trace and try the other auto-save file as a backup.
                firstLoadException.Trace();
            }

            // If null is returned from the first Load(), the integrity check failed.
            if (loadedText == null)
            {
                latestAutoSaveFile = autoSaveFiles.Different(latestAutoSaveFile);

                try
                {
                    loadedText = Load(latestAutoSaveFile);
                }
                catch (Exception secondLoadException)
                {
                    secondLoadException.Trace();
                }
            }

            // Initialize remote state with the loaded text.
            // If both reads failed, loadedText == null.
            remoteState.Initialize(loadedText);

            // Initialize encoder and buffers.
            // Always use UTF8 for auto-saved text files.
            Encoding encoding = Encoding.UTF8;

            encoder       = encoding.GetEncoder();
            buffer        = new char[CharBufferSize];
            encodedBuffer = new byte[encoding.GetMaxByteCount(CharBufferSize)];

            // Set up long running task to keep auto-saving updates.
            updateQueue            = new ConcurrentQueue <TUpdate>();
            cts                    = new CancellationTokenSource();
            autoSaveBackgroundTask = Task.Run(() => AutoSaveLoop(latestAutoSaveFile, remoteState, cts.Token));
        }
 /// <summary>
 /// Initializes a new <see cref="WorkingCopyTextFile"/> from an open <see cref="LiveTextFile"/>
 /// and a <see cref="FileStreamPair"/> from which to load an <see cref="AutoSaveTextFile{TUpdate}"/> with auto-saved local changes.
 /// Use this constructor for <see cref="LiveTextFile"/> instances which must remain live after this
 /// <see cref="WorkingCopyTextFile"/> is disposed.
 /// It is not possible to use <see cref="Replace(string)"/> on <see cref="WorkingCopyTextFile"/> instances
 /// created with this method.
 /// </summary>
 /// <param name="openTextFile">
 /// The open text file.
 /// </param>
 /// <param name="autoSaveFiles">
 /// The <see cref="FileStreamPair"/> from which to load the auto-save file that contains local changes,
 /// or null to not load from an auto-save file.
 /// </param>
 /// <returns>
 /// The new <see cref="WorkingCopyTextFile"/>.
 /// </returns>
 /// <exception cref="ArgumentNullException">
 /// <paramref name="openTextFile"/> is null.
 /// </exception>
 public static WorkingCopyTextFile FromLiveTextFile(LiveTextFile openTextFile, FileStreamPair autoSaveFiles)
 => new WorkingCopyTextFile(
 /// <summary>
 /// Initializes a new <see cref="WorkingCopyTextFile"/> from a file path and a <see cref="FileStreamPair"/>
 /// from which to load an <see cref="AutoSaveTextFile{TUpdate}"/> with auto-saved local changes.
 /// </summary>
 /// <param name="path">
 /// The path of the file to load and watch, or null to create a new file.
 /// </param>
 /// <param name="autoSaveFiles">
 /// The <see cref="FileStreamPair"/> from which to load the auto-save file that contains local changes,
 /// or null to not load from an auto-save file.
 /// </param>
 /// <exception cref="ArgumentException">
 /// <paramref name="path"/> is empty, contains only whitespace, or contains invalid characters
 /// (see also <seealso cref="Path.GetInvalidPathChars"/>), or is in an invalid format,
 /// or is a relative path and its absolute path could not be resolved.
 /// </exception>
 /// <exception cref="IOException">
 /// <paramref name="path"/> is longer than its maximum length (this is OS specific).
 /// </exception>
 /// <exception cref="System.Security.SecurityException">
 /// The caller does not have sufficient permissions to read the file.
 /// </exception>
 /// <exception cref="NotSupportedException">
 /// <paramref name="path"/> is in an invalid format.
 /// </exception>
 /// <returns>
 /// The new <see cref="WorkingCopyTextFile"/>.
 /// </returns>
 public static WorkingCopyTextFile Open(string path, FileStreamPair autoSaveFiles)
 => new WorkingCopyTextFile(
     path == null ? null : new LiveTextFile(path),
     autoSaveFiles,
     isTextFileOwner: true);