Max
Max

Reputation: 1309

FileStream adding "extra" characters to TXT file

It does not matter if I read a TXT file or a XML file I always see "extra" info added into my file which is saved to disk. We first do the following:

FileStream fs = new FileStream(fileMoverFile.SourcePath, FileMode.Open, FileAccess.Read);

Then we assign fs to a variable of type Stream which we pass to the function below:

private void SaveToDisk(Stream fileStream, string saveToPath)
{
  if (!Directory.Exists(Path.GetDirectoryName(saveToPath)))
  {
    Directory.CreateDirectory(Path.GetDirectoryName(saveToPath));
  }
  FileStream outputStream = new FileInfo(saveToPath).OpenWrite();
  const int bufferSize = 1024;
  byte[] buffer = new byte[bufferSize];
  int bytesRead = fileStream.Read(buffer, 0, bufferSize);
  while (bytesRead > 0)
  {
    outputStream.Write(buffer, 0, bufferSize);
    bytesRead = fileStream.Read(buffer, 0, bufferSize);
  }
  outputStream.Close();
}

When I open the file which was saved to disk, I see extra information which is basically some content of the same file being repeated with some other info which do not belong to the file. Very strange.

What could be causing this?

Upvotes: 3

Views: 3943

Answers (2)

Reed Copsey
Reed Copsey

Reputation: 564851

You need to write bytesRead bytes, not bufferSize bytes:

int bytesRead = fileStream.Read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
    outputStream.Write(buffer, 0, bytesRead); // Change this here

Right now, when you reach the end of the input stream, you're potentially writing more data than you read in, which will cause "extra garbage" at the end of the file.

That being said, if your goal is just to copy the stream, you could just use Stream.CopyTo (provided you're in .NET 4+). This avoids the read/write loop entirely, and simplifies your code dramatically:

private void SaveToDisk(Stream fileStream, string saveToPath)
{
  if (!Directory.Exists(Path.GetDirectoryName(saveToPath)))
  {
    Directory.CreateDirectory(Path.GetDirectoryName(saveToPath));
  }
  using(FileStream outputStream = new FileInfo(saveToPath).OpenWrite())
  {
      fileStream.CopyTo(outputStream);
  }
}

Upvotes: 5

Dai
Dai

Reputation: 155648

You're not using your buffer properly. In the event that the call to fileStream.Read() returns less than bufferSize then your program still continues to read the rest of the buffer that would contain previously-read data.

Here's how you should do it:

using(FileStream output = new FileStream( saveToPath, FileMode.Create, FileAccess.Write )) {

    Byte[] buffer = new Byte[ 32 * 1024 ]; // a 32KB-sized buffer is the most efficient
    Int32 bytesRead;

    while( (bytesRead = fileStream.Read( buffer, 0, buffer.Length ) ) > 0 ) {

        output.Write( buffer, 0, bytesRead );
    }
    output.Flush();
}

Note how I used using and bytesRead to limit the data rewritten to the output.

Upvotes: 1

Related Questions