Răsfoiți Sursa

Truncate existing file in CreateText (#1686)

SftpClient.CreateText does not truncate the file if it exists, contrary to
System.IO.File.CreateText which does. It is documented, but seems pretty
unintuitive and more like a mistake than a concious decision.

I considered leaving this 14 year old behaviour as it is, but turns out other
people have hit it as well (it also affects WriteAll{Bytes/Text/Lines}).
Rob Hague 2 luni în urmă
părinte
comite
6cba1be72e

+ 18 - 48
src/Renci.SshNet/ISftpClient.cs

@@ -454,12 +454,8 @@ namespace Renci.SshNet
         /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
         /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
+        /// If the file specified by <paramref name="path"/> does not exist, it is created.
+        /// If the file does exist, its contents are replaced.
         /// </remarks>
         StreamWriter CreateText(string path);
 
@@ -476,12 +472,8 @@ namespace Renci.SshNet
         /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
         /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
+        /// If the file specified by <paramref name="path"/> does not exist, it is created.
+        /// If the file does exist, its contents are replaced.
         /// </remarks>
         StreamWriter CreateText(string path, Encoding encoding);
 
@@ -1151,12 +1143,8 @@ namespace Renci.SshNet
         /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
         /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
+        /// If the file specified by <paramref name="path"/> does not exist, it is created.
+        /// If the file does exist, its contents are replaced.
         /// </remarks>
         void WriteAllBytes(string path, byte[] bytes);
 
@@ -1174,10 +1162,8 @@ namespace Renci.SshNet
         /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
         /// </para>
         /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
+        /// If the file specified by <paramref name="path"/> does not exist, it is created.
+        /// If the file does exist, its contents are replaced.
         /// </para>
         /// </remarks>
         void WriteAllLines(string path, IEnumerable<string> contents);
@@ -1193,12 +1179,8 @@ namespace Renci.SshNet
         /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
         /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
+        /// If the file specified by <paramref name="path"/> does not exist, it is created.
+        /// If the file does exist, its contents are replaced.
         /// </remarks>
         void WriteAllLines(string path, IEnumerable<string> contents, Encoding encoding);
 
@@ -1216,10 +1198,8 @@ namespace Renci.SshNet
         /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
         /// </para>
         /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
+        /// If the file specified by <paramref name="path"/> does not exist, it is created.
+        /// If the file does exist, its contents are replaced.
         /// </para>
         /// </remarks>
         void WriteAllLines(string path, string[] contents);
@@ -1235,12 +1215,8 @@ namespace Renci.SshNet
         /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
         /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
+        /// If the file specified by <paramref name="path"/> does not exist, it is created.
+        /// If the file does exist, its contents are replaced.
         /// </remarks>
         void WriteAllLines(string path, string[] contents, Encoding encoding);
 
@@ -1258,10 +1234,8 @@ namespace Renci.SshNet
         /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
         /// </para>
         /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
+        /// If the file specified by <paramref name="path"/> does not exist, it is created.
+        /// If the file does exist, its contents are replaced.
         /// </para>
         /// </remarks>
         void WriteAllText(string path, string contents);
@@ -1277,12 +1251,8 @@ namespace Renci.SshNet
         /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
         /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
         /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
+        /// If the file specified by <paramref name="path"/> does not exist, it is created.
+        /// If the file does exist, its contents are replaced.
         /// </remarks>
         void WriteAllText(string path, string contents, Encoding encoding);
     }

+ 14 - 183
src/Renci.SshNet/SftpClient.cs

@@ -1468,56 +1468,18 @@ namespace Renci.SshNet
             return SftpFileStream.Open(_sftpSession, path, FileMode.Create, FileAccess.ReadWrite, bufferSize);
         }
 
-        /// <summary>
-        /// Creates or opens a file for writing UTF-8 encoded text.
-        /// </summary>
-        /// <param name="path">The file to be opened for writing.</param>
-        /// <returns>
-        /// A <see cref="StreamWriter"/> that writes text to a file using UTF-8 encoding without
-        /// a Byte-Order Mark (BOM).
-        /// </returns>
-        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
-        /// <exception cref="SshConnectionException">Client is not connected.</exception>
-        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
-        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
-        /// </remarks>
+        /// <inheritdoc/>
         public StreamWriter CreateText(string path)
         {
             return CreateText(path, Utf8NoBOM);
         }
 
-        /// <summary>
-        /// Creates or opens a file for writing text using the specified encoding.
-        /// </summary>
-        /// <param name="path">The file to be opened for writing.</param>
-        /// <param name="encoding">The character encoding to use.</param>
-        /// <returns>
-        /// A <see cref="StreamWriter"/> that writes to a file using the specified encoding.
-        /// </returns>
-        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
-        /// <exception cref="SshConnectionException">Client is not connected.</exception>
-        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
-        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
-        /// </remarks>
+        /// <inheritdoc/>
         public StreamWriter CreateText(string path, Encoding encoding)
         {
             CheckDisposed();
 
-            return new StreamWriter(OpenWrite(path), encoding);
+            return new StreamWriter(Open(path, FileMode.Create, FileAccess.Write), encoding);
         }
 
         /// <summary>
@@ -1903,99 +1865,27 @@ namespace Renci.SshNet
             SetAttributes(path, attributes);
         }
 
-        /// <summary>
-        /// Writes the specified byte array to the specified file, and closes the file.
-        /// </summary>
-        /// <param name="path">The file to write to.</param>
-        /// <param name="bytes">The bytes to write to the file.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
-        /// <exception cref="SshConnectionException">Client is not connected.</exception>
-        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
-        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
-        /// </remarks>
+        /// <inheritdoc/>
         public void WriteAllBytes(string path, byte[] bytes)
         {
-            using (var stream = OpenWrite(path))
-            {
-                stream.Write(bytes, 0, bytes.Length);
-            }
+            ThrowHelper.ThrowIfNull(bytes);
+
+            UploadFile(new MemoryStream(bytes), path);
         }
 
-        /// <summary>
-        /// Writes a collection of strings to the file using the UTF-8 encoding, and closes the file.
-        /// </summary>
-        /// <param name="path">The file to write to.</param>
-        /// <param name="contents">The lines to write to the file.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
-        /// <exception cref="SshConnectionException">Client is not connected.</exception>
-        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
-        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        /// <remarks>
-        /// <para>
-        /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
-        /// </para>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
-        /// </remarks>
+        /// <inheritdoc/>
         public void WriteAllLines(string path, IEnumerable<string> contents)
         {
             WriteAllLines(path, contents, Utf8NoBOM);
         }
 
-        /// <summary>
-        /// Write the specified string array to the file using the UTF-8 encoding, and closes the file.
-        /// </summary>
-        /// <param name="path">The file to write to.</param>
-        /// <param name="contents">The string array to write to the file.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
-        /// <exception cref="SshConnectionException">Client is not connected.</exception>
-        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
-        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        /// <remarks>
-        /// <para>
-        /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
-        /// </para>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
-        /// </remarks>
+        /// <inheritdoc/>
         public void WriteAllLines(string path, string[] contents)
         {
             WriteAllLines(path, contents, Utf8NoBOM);
         }
 
-        /// <summary>
-        /// Writes a collection of strings to the file using the specified encoding, and closes the file.
-        /// </summary>
-        /// <param name="path">The file to write to.</param>
-        /// <param name="contents">The lines to write to the file.</param>
-        /// <param name="encoding">The character encoding to use.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
-        /// <exception cref="SshConnectionException">Client is not connected.</exception>
-        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
-        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
-        /// </remarks>
+        /// <inheritdoc/>
         public void WriteAllLines(string path, IEnumerable<string> contents, Encoding encoding)
         {
             using (var stream = CreateText(path, encoding))
@@ -2007,55 +1897,13 @@ namespace Renci.SshNet
             }
         }
 
-        /// <summary>
-        /// Writes the specified string array to the file by using the specified encoding, and closes the file.
-        /// </summary>
-        /// <param name="path">The file to write to.</param>
-        /// <param name="contents">The string array to write to the file.</param>
-        /// <param name="encoding">An <see cref="Encoding"/> object that represents the character encoding applied to the string array.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
-        /// <exception cref="SshConnectionException">Client is not connected.</exception>
-        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
-        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
-        /// </remarks>
+        /// <inheritdoc/>
         public void WriteAllLines(string path, string[] contents, Encoding encoding)
         {
-            using (var stream = CreateText(path, encoding))
-            {
-                foreach (var line in contents)
-                {
-                    stream.WriteLine(line);
-                }
-            }
+            WriteAllLines(path, (IEnumerable<string>)contents, encoding);
         }
 
-        /// <summary>
-        /// Writes the specified string to the file using the UTF-8 encoding, and closes the file.
-        /// </summary>
-        /// <param name="path">The file to write to.</param>
-        /// <param name="contents">The string to write to the file.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
-        /// <exception cref="SshConnectionException">Client is not connected.</exception>
-        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
-        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        /// <remarks>
-        /// <para>
-        /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
-        /// </para>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
-        /// </remarks>
+        /// <inheritdoc/>
         public void WriteAllText(string path, string contents)
         {
             using (var stream = CreateText(path))
@@ -2064,24 +1912,7 @@ namespace Renci.SshNet
             }
         }
 
-        /// <summary>
-        /// Writes the specified string to the file using the specified encoding, and closes the file.
-        /// </summary>
-        /// <param name="path">The file to write to.</param>
-        /// <param name="contents">The string to write to the file.</param>
-        /// <param name="encoding">The encoding to apply to the string.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
-        /// <exception cref="SshConnectionException">Client is not connected.</exception>
-        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on the remote host.</exception>
-        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
-        /// <remarks>
-        /// <para>
-        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
-        /// </para>
-        /// <para>
-        /// If the target file does not exist, it is created.
-        /// </para>
-        /// </remarks>
+        /// <inheritdoc/>
         public void WriteAllText(string path, string contents, Encoding encoding)
         {
             using (var stream = CreateText(path, encoding))

+ 0 - 32
test/Renci.SshNet.IntegrationTests/Common/ArrayBuilder`1.cs

@@ -1,32 +0,0 @@
-namespace Renci.SshNet.IntegrationTests.Common
-{
-    public class ArrayBuilder<T>
-    {
-        private readonly List<T> _buffer;
-
-        public ArrayBuilder()
-        {
-            _buffer = new List<T>();
-        }
-
-        public ArrayBuilder<T> Add(T[] array)
-        {
-            return Add(array, 0, array.Length);
-        }
-
-        public ArrayBuilder<T> Add(T[] array, int index, int length)
-        {
-            for (var i = 0; i < length; i++)
-            {
-                _buffer.Add(array[index + i]);
-            }
-
-            return this;
-        }
-
-        public T[] Build()
-        {
-            return _buffer.ToArray();
-        }
-    }
-}

+ 46 - 95
test/Renci.SshNet.IntegrationTests/SftpTests.cs

@@ -1058,8 +1058,7 @@ namespace Renci.SshNet.IntegrationTests
             const string initialContent = "\u0100ert & Ann";
             var initialContentBytes = GetBytesWithPreamble(initialContent, encoding);
             const string newContent = "\u0116ver";
-            const string expectedContent = "\u0116ver" + " & Ann";
-            var expectedContentBytes = GetBytesWithPreamble(expectedContent, encoding);
+            var newContentBytes = GetBytesWithPreamble(newContent, encoding);
 
             using (var client = new SftpClient(_connectionInfoFactory.Create()))
             {
@@ -1076,26 +1075,21 @@ namespace Renci.SshNet.IntegrationTests
                 {
                     client.WriteAllText(remoteFile, initialContent);
 
-                    using (client.CreateText(remoteFile))
-                    {
-                    }
-
-                    // verify that original content is left untouched
-                    var actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(initialContentBytes, actualBytes);
+                    Assert.AreEqual(initialContentBytes.Length, client.Get(remoteFile).Length);
 
-                    // write content that is less bytes than original content
                     using (var sw = client.CreateText(remoteFile))
                     {
                         sw.Write(newContent);
                     }
 
-                    // verify that original content is only partially overwritten
+                    // verify that the file was truncated
+                    Assert.AreEqual(newContentBytes.Length, client.Get(remoteFile).Length);
+
                     var text = client.ReadAllText(remoteFile);
-                    Assert.AreEqual(expectedContent, text);
+                    Assert.AreEqual(newContent, text);
 
-                    actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedContentBytes, actualBytes);
+                    var actualBytes = client.ReadAllBytes(remoteFile);
+                    CollectionAssert.AreEqual(newContentBytes, actualBytes);
                 }
                 finally
                 {
@@ -1206,8 +1200,7 @@ namespace Renci.SshNet.IntegrationTests
             var initialContent = "\u0100ert & Ann";
             var initialContentBytes = GetBytesWithPreamble(initialContent, encoding);
             var newContent = "\u0116ver";
-            var expectedContent = "\u0116ver" + " & Ann";
-            var expectedContentBytes = GetBytesWithPreamble(expectedContent, encoding);
+            var newContentBytes = GetBytesWithPreamble(newContent, encoding);
 
             using (var client = new SftpClient(_connectionInfoFactory.Create()))
             {
@@ -1224,26 +1217,21 @@ namespace Renci.SshNet.IntegrationTests
                 {
                     client.WriteAllText(remoteFile, initialContent, encoding);
 
-                    using (client.CreateText(remoteFile))
-                    {
-                    }
-
-                    // verify that original content is left untouched
-                    var actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(initialContentBytes, actualBytes);
+                    Assert.AreEqual(initialContentBytes.Length, client.Get(remoteFile).Length);
 
-                    // write content that is less bytes than original content
                     using (var sw = client.CreateText(remoteFile, encoding))
                     {
                         sw.Write(newContent);
                     }
 
-                    // verify that original content is only partially overwritten
-                    var text = client.ReadAllText(remoteFile, encoding);
-                    Assert.AreEqual(expectedContent, text);
+                    // verify that the file was truncated
+                    Assert.AreEqual(newContentBytes.Length, client.Get(remoteFile).Length);
 
-                    actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedContentBytes, actualBytes);
+                    var text = client.ReadAllText(remoteFile);
+                    Assert.AreEqual(newContent, text);
+
+                    var actualBytes = client.ReadAllBytes(remoteFile);
+                    CollectionAssert.AreEqual(newContentBytes, actualBytes);
                 }
                 finally
                 {
@@ -1942,9 +1930,6 @@ namespace Renci.SshNet.IntegrationTests
         {
             var initialContent = GenerateRandom(size: 13);
             var newContent1 = GenerateRandom(size: 5);
-            var expectedContent1 = new ArrayBuilder<byte>().Add(newContent1)
-                                                           .Add(initialContent, newContent1.Length, initialContent.Length - newContent1.Length)
-                                                           .Build();
             var newContent2 = GenerateRandom(size: 50000);
 
             using (var client = new SftpClient(_connectionInfoFactory.Create()))
@@ -1965,14 +1950,14 @@ namespace Renci.SshNet.IntegrationTests
                         fs.Write(initialContent, offset: 0, initialContent.Length);
                     }
 
-                    #region Write less bytes than the current content, overwriting part of that content
+                    #region Write less bytes than the current content, overwriting that content
 
                     client.WriteAllBytes(remoteFile, newContent1);
 
                     var actualContent1 = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedContent1, actualContent1);
+                    CollectionAssert.AreEqual(newContent1, actualContent1);
 
-                    #endregion Write less bytes than the initial content, overwriting part of that content
+                    #endregion
 
                     #region Write more bytes than the current content, overwriting and appending to that content
 
@@ -1981,7 +1966,7 @@ namespace Renci.SshNet.IntegrationTests
                     var actualContent2 = client.ReadAllBytes(remoteFile);
                     CollectionAssert.AreEqual(newContent2, actualContent2);
 
-                    #endregion Write less bytes than the initial content, overwriting part of that content
+                    #endregion
                 }
                 finally
                 {
@@ -2068,19 +2053,12 @@ namespace Renci.SshNet.IntegrationTests
         {
             var encoding = new UTF8Encoding(false, true);
             var initialContent = "\u0100ert & Ann Forever & Ever Lisa & Sofie";
-            var initialContentBytes = GetBytesWithPreamble(initialContent, encoding);
             IEnumerable<string> linesToWrite1 = new[] { "Forever", "&", "\u0116ver" };
             var linesToWrite1Bytes =
                 GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite1) + Environment.NewLine, encoding);
-            var expectedBytes1 = new ArrayBuilder<byte>().Add(linesToWrite1Bytes)
-                                                         .Add(initialContentBytes,
-                                                              linesToWrite1Bytes.Length,
-                                                              initialContentBytes.Length - linesToWrite1Bytes.Length)
-                                                         .Build();
             IEnumerable<string> linesToWrite2 = new[] { "Forever", "&", "\u0116ver", "Gert & Ann", "Lisa + Sofie" };
             var linesToWrite2Bytes =
                 GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite2) + Environment.NewLine, encoding);
-            var expectedBytes2 = linesToWrite2Bytes;
 
             using (var client = new SftpClient(_connectionInfoFactory.Create()))
             {
@@ -2098,21 +2076,21 @@ namespace Renci.SshNet.IntegrationTests
                     // create initial content
                     client.WriteAllText(remoteFile, initialContent);
 
-                    #region Write less bytes than the current content, overwriting part of that content
+                    #region Write less bytes than the current content, overwriting that content
 
                     client.WriteAllLines(remoteFile, linesToWrite1);
 
                     var actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes1, actualBytes);
+                    CollectionAssert.AreEqual(linesToWrite1Bytes, actualBytes);
 
-                    #endregion Write less bytes than the current content, overwriting part of that content
+                    #endregion
 
                     #region Write more bytes than the current content, overwriting and appending to that content
 
                     client.WriteAllLines(remoteFile, linesToWrite2);
 
                     actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes2, actualBytes);
+                    CollectionAssert.AreEqual(linesToWrite2Bytes, actualBytes);
 
                     #endregion Write more bytes than the current content, overwriting and appending to that content
                 }
@@ -2203,18 +2181,11 @@ namespace Renci.SshNet.IntegrationTests
         {
             var encoding = GetRandomEncoding();
             const string initialContent = "\u0100ert & Ann Forever & Ever Lisa & Sofie";
-            var initialContentBytes = GetBytesWithPreamble(initialContent, encoding);
             IEnumerable<string> linesToWrite1 = new[] { "Forever", "&", "\u0116ver" };
             var linesToWrite1Bytes =
                 GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite1) + Environment.NewLine, encoding);
-            var expectedBytes1 = new ArrayBuilder<byte>().Add(linesToWrite1Bytes)
-                                                         .Add(initialContentBytes,
-                                                              linesToWrite1Bytes.Length,
-                                                              initialContentBytes.Length - linesToWrite1Bytes.Length)
-                                                         .Build();
             IEnumerable<string> linesToWrite2 = new[] { "Forever", "&", "\u0116ver", "Gert & Ann", "Lisa + Sofie" };
             var linesToWrite2Bytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite2) + Environment.NewLine, encoding);
-            var expectedBytes2 = linesToWrite2Bytes;
 
             using (var client = new SftpClient(_connectionInfoFactory.Create()))
             {
@@ -2232,21 +2203,21 @@ namespace Renci.SshNet.IntegrationTests
                     // create initial content
                     client.WriteAllText(remoteFile, initialContent, encoding);
 
-                    #region Write less bytes than the current content, overwriting part of that content
+                    #region Write less bytes than the current content, overwriting that content
 
                     client.WriteAllLines(remoteFile, linesToWrite1, encoding);
 
                     var actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes1, actualBytes);
+                    CollectionAssert.AreEqual(linesToWrite1Bytes, actualBytes);
 
-                    #endregion Write less bytes than the current content, overwriting part of that content
+                    #endregion
 
                     #region Write more bytes than the current content, overwriting and appending to that content
 
                     client.WriteAllLines(remoteFile, linesToWrite2, encoding);
 
                     actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes2, actualBytes);
+                    CollectionAssert.AreEqual(linesToWrite2Bytes, actualBytes);
 
                     #endregion Write more bytes than the current content, overwriting and appending to that content
                 }
@@ -2336,15 +2307,10 @@ namespace Renci.SshNet.IntegrationTests
         {
             var encoding = new UTF8Encoding(false, true);
             const string initialContent = "\u0100ert & Ann Forever & Ever Lisa & Sofie";
-            var initialContentBytes = GetBytesWithPreamble(initialContent, encoding);
             var linesToWrite1 = new[] { "Forever", "&", "\u0116ver" };
             var linesToWrite1Bytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite1) + Environment.NewLine, encoding);
-            var expectedBytes1 = new ArrayBuilder<byte>().Add(linesToWrite1Bytes)
-                                                         .Add(initialContentBytes, linesToWrite1Bytes.Length, initialContentBytes.Length - linesToWrite1Bytes.Length)
-                                                         .Build();
             var linesToWrite2 = new[] { "Forever", "&", "\u0116ver", "Gert & Ann", "Lisa + Sofie" };
             var linesToWrite2Bytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite2) + Environment.NewLine, encoding);
-            var expectedBytes2 = linesToWrite2Bytes;
 
             using (var client = new SftpClient(_connectionInfoFactory.Create()))
             {
@@ -2362,21 +2328,21 @@ namespace Renci.SshNet.IntegrationTests
                     // create initial content
                     client.WriteAllText(remoteFile, initialContent);
 
-                    #region Write less bytes than the current content, overwriting part of that content
+                    #region Write less bytes than the current content, overwriting that content
 
                     client.WriteAllLines(remoteFile, linesToWrite1);
 
                     var actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes1, actualBytes);
+                    CollectionAssert.AreEqual(linesToWrite1Bytes, actualBytes);
 
-                    #endregion Write less bytes than the current content, overwriting part of that content
+                    #endregion
 
                     #region Write more bytes than the current content, overwriting and appending to that content
 
                     client.WriteAllLines(remoteFile, linesToWrite2);
 
                     actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes2, actualBytes);
+                    CollectionAssert.AreEqual(linesToWrite2Bytes, actualBytes);
 
                     #endregion Write more bytes than the current content, overwriting and appending to that content
                 }
@@ -2468,15 +2434,10 @@ namespace Renci.SshNet.IntegrationTests
             const string initialContent = "\u0100ert & Ann Forever & Ever Lisa & Sofie";
 
             var encoding = GetRandomEncoding();
-            var initialContentBytes = GetBytesWithPreamble(initialContent, encoding);
             var linesToWrite1 = new[] { "Forever", "&", "\u0116ver" };
             var linesToWrite1Bytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite1) + Environment.NewLine, encoding);
-            var expectedBytes1 = new ArrayBuilder<byte>().Add(linesToWrite1Bytes)
-                                                         .Add(initialContentBytes, linesToWrite1Bytes.Length, initialContentBytes.Length - linesToWrite1Bytes.Length)
-                                                         .Build();
             var linesToWrite2 = new[] { "Forever", "&", "\u0116ver", "Gert & Ann", "Lisa + Sofie" };
             var linesToWrite2Bytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite2) + Environment.NewLine, encoding);
-            var expectedBytes2 = linesToWrite2Bytes;
 
             using (var client = new SftpClient(_connectionInfoFactory.Create()))
             {
@@ -2494,23 +2455,23 @@ namespace Renci.SshNet.IntegrationTests
                     // create initial content
                     client.WriteAllText(remoteFile, initialContent, encoding);
 
-                    #region Write less bytes than the current content, overwriting part of that content
+                    #region Write less bytes than the current content, overwriting that content
 
                     client.WriteAllLines(remoteFile, linesToWrite1, encoding);
 
                     var actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes1, actualBytes);
+                    CollectionAssert.AreEqual(linesToWrite1Bytes, actualBytes);
 
-                    #endregion Write less bytes than the current content, overwriting part of that content
+                    #endregion
 
                     #region Write more bytes than the current content, overwriting and appending to that content
 
                     client.WriteAllLines(remoteFile, linesToWrite2, encoding);
 
                     actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes2, actualBytes);
+                    CollectionAssert.AreEqual(linesToWrite2Bytes, actualBytes);
 
-                    #endregion Write more bytes than the current content, overwriting and appending to that content
+                    #endregion
                 }
                 finally
                 {
@@ -2601,14 +2562,9 @@ namespace Renci.SshNet.IntegrationTests
             const string newContent1 = "For\u0116ver & Ever";
 
             var encoding = new UTF8Encoding(false, true);
-            var initialContentBytes = GetBytesWithPreamble(initialContent, encoding);
             var newContent1Bytes = GetBytesWithPreamble(newContent1, encoding);
-            var expectedBytes1 = new ArrayBuilder<byte>().Add(newContent1Bytes)
-                                                         .Add(initialContentBytes, newContent1Bytes.Length, initialContentBytes.Length - newContent1Bytes.Length)
-                                                         .Build();
             var newContent2 = "Sofie & Lisa For\u0116ver & Ever with \u0100ert & Ann";
             var newContent2Bytes = GetBytesWithPreamble(newContent2, encoding);
-            var expectedBytes2 = newContent2Bytes;
 
             using (var client = new SftpClient(_connectionInfoFactory.Create()))
             {
@@ -2625,21 +2581,21 @@ namespace Renci.SshNet.IntegrationTests
                 {
                     client.WriteAllText(remoteFile, initialContent);
 
-                    #region Write less bytes than the current content, overwriting part of that content
+                    #region Write less bytes than the current content, overwriting that content
 
                     client.WriteAllText(remoteFile, newContent1);
 
                     var actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes1, actualBytes);
+                    CollectionAssert.AreEqual(newContent1Bytes, actualBytes);
 
-                    #endregion Write less bytes than the current content, overwriting part of that content
+                    #endregion
 
                     #region Write more bytes than the current content, overwriting and appending to that content
 
                     client.WriteAllText(remoteFile, newContent2);
 
                     actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes2, actualBytes);
+                    CollectionAssert.AreEqual(newContent2Bytes, actualBytes);
 
                     #endregion Write more bytes than the current content, overwriting and appending to that content
                 }
@@ -2734,13 +2690,8 @@ namespace Renci.SshNet.IntegrationTests
             const string newContent2 = "Sofie & Lisa For\u0116ver & Ever with \u0100ert & Ann";
 
             var encoding = GetRandomEncoding();
-            var initialContentBytes = GetBytesWithPreamble(initialContent, encoding);
             var newContent1Bytes = GetBytesWithPreamble(newContent1, encoding);
-            var expectedBytes1 = new ArrayBuilder<byte>().Add(newContent1Bytes)
-                                                         .Add(initialContentBytes, newContent1Bytes.Length, initialContentBytes.Length - newContent1Bytes.Length)
-                                                         .Build();
             var newContent2Bytes = GetBytesWithPreamble(newContent2, encoding);
-            var expectedBytes2 = newContent2Bytes;
 
             using (var client = new SftpClient(_connectionInfoFactory.Create()))
             {
@@ -2757,21 +2708,21 @@ namespace Renci.SshNet.IntegrationTests
                 {
                     client.WriteAllText(remoteFile, initialContent, encoding);
 
-                    #region Write less bytes than the current content, overwriting part of that content
+                    #region Write less bytes than the current content, overwriting that content
 
                     client.WriteAllText(remoteFile, newContent1, encoding);
 
                     var actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes1, actualBytes);
+                    CollectionAssert.AreEqual(newContent1Bytes, actualBytes);
 
-                    #endregion Write less bytes than the current content, overwriting part of that content
+                    #endregion
 
                     #region Write more bytes than the current content, overwriting and appending to that content
 
                     client.WriteAllText(remoteFile, newContent2, encoding);
 
                     actualBytes = client.ReadAllBytes(remoteFile);
-                    CollectionAssert.AreEqual(expectedBytes2, actualBytes);
+                    CollectionAssert.AreEqual(newContent2Bytes, actualBytes);
 
                     #endregion Write more bytes than the current content, overwriting and appending to that content
                 }