简体   繁体   中英

Unexpected output when reading and writing to a text file

I am a bit new to files in C# and am having a problem. When reading from a file and copying to another, the last chunk of text is not being written. Below is my code:

StringBuilder sb = new StringBuilder(8192);
string fileName = "C:...rest of path...inputFile.txt";
string outputFile = "C:...rest of path...outputFile.txt";

using (StreamReader reader = File.OpenText(fileName))
{
   char[] buffer = new char[8192];
   while ((reader.ReadBlock(buffer, 0, buffer.Length)) != 0)
   {
      foreach (char c in buffer)
      {
         //do some function on char c... 
         sb.Append(c);
      }

      using (StreamWriter writer = File.CreateText(outputFile))
      {
         writer.Write(sb.ToString());
      }
   }
}

My aim was to read and write to a textfile in a buffered manner. Something that in Java I would achieve in the following manner:

public void encrypt(File inputFile, File outputFile) throws IOException
{
   BufferedReader infromfile = null;
   BufferedWriter outtofile = null;

   try
   {
      String key = getKeyfromFile(keyFile);
      if (key != null)
      {
         infromfile = new BufferedReader(new FileReader(inputFile));
         outtofile = new BufferedWriter(new FileWriter(outputFile));
         char[] buffer = new char[8192];
         while ((infromfile.read(buffer, 0, buffer.length)) != -1)
         {
            String temptext = String.valueOf(buffer);
            //some changes to temptext are done
            outtofile.write(temptext);
         }
      }
   }
   catch (FileNotFoundException exc)
   {
   } // and all other possible exceptions
}

Could you help me identify the source of my problem?

If you think that there is possibly a better approach to achieve buffered i/o with text files, I would truly appreciate your suggestion.

There are a couple of "gotchas":

  1. c can't be changed (it's the foreach iteration variable), you'll need to copy it in order to process before writing
  2. you have to keep track of your buffer's size, ReadBlock fills it with characters which would make your output dirty

Changing your code like this looks like it works:

//extracted from your code
foreach (char c in buffer)
{
    if (c == (char)0) break; //GOTCHA #2: maybe you don't want NULL (ascii 0) characters in your output

    char d = c; //GOTCHA #1: you can't change 'c'

    // d = SomeProcessingHere();

    sb.Append(d);
}

Try this:

        string fileName = @"";
        string outputfile = @"";

        StreamReader reader = File.OpenText(fileName);
        string texto = reader.ReadToEnd();

        StreamWriter writer = new StreamWriter(outputfile);
        writer.Write(texto);

        writer.Flush();
        writer.Close();

If you dont care about carraign returns, you could use File.ReadAllText

This method opens a file, reads each line of the file, and then adds each line as an element of a string. It then closes the file. A line is defined as a sequence of characters followed by a carriage return ('\\r'), a line feed ('\\n'), or a carriage return immediately followed by a line feed. The resulting string does not contain the terminating carriage return and/or line feed.

StringBuilder sb = new StringBuilder(8192);
string fileName = "C:...rest of path...inputFile.txt";
string outputFile = "C:...rest of path...outputFile.txt";

// Open the file to read from.
string readText = File.ReadAllText(fileName );
foreach (char c in readText)
{
   // do something to c
   sb.Append(new_c);
}

// This text is added only once to the file, overwrite it if it exists
File.WriteAllText(outputFile, sb.ToString());        

Does this work for you?

       using (StreamReader reader = File.OpenText(fileName))
       {
            char[] buffer = new char[8192];
            bool eof = false;

            while (!eof)
            {
                int numBytes = (reader.ReadBlock(buffer, 0, buffer.Length));
                if (numBytes>0)
                {
                    using (StreamWriter writer = File.CreateText(outputFile))
                    {
                        writer.Write(buffer, 0, numBytes);
                    }
                } else {
                    eof = true;
                }

            }
        }

You still have to take care of character encoding though!

Unless I'm missing something, it appears that your issue is that you're overwriting the existing contents of your output file on each blockread iteration.

You call:

  using (StreamWriter writer = File.CreateText(outputFile))
  {
     writer.Write(sb.ToString());
  }

for every ReadBlock iteration. The output of the file would only be the last chunk of data that was read.

From MSDN documentation on File.CreateText:

If the file specified by path does not exist, it is created. If the file does exist, its contents are overwritten.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM