Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Reading bytes from a text file using "StreamReader.BaseStream".

Posted on 2012-04-12
15
Medium Priority
?
1,285 Views
Last Modified: 2012-04-13
Hi, I’m using MS VS 2010 C#.NET, I’m trying to read a file from disk and send the BaseStream to a textbox on one of my Forms. Below is my code. It's working, but it’s doing so very, very slowly. A 16KB file took about 15 minutes to read and send to the textbox. A 10 KB file took close to 4 minutes to process. I’m sure I’m doing something wrong and I’m sure there’s a much more efficient manner to do so.

If you'd like to create the Form, its simply a Button named "btnRead" and multiline Textbox named "tbxText", with a vertical scroll-bar and its Font set to Courier New." You can use any text file you'd like for testing.

Can anyone help me to increase the efficiency of this code?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace Reader
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // Checks for file. If it exists, it reads it.
        private void btnRead_Click(object sender, EventArgs e)
        {
            string path = @"C:\TestData\testfile.txt";
            string fileLength = "";
            string strBuffer = "";
            
     Console.WriteLine("Started at : " + DateTime.Now);
            if (File.Exists(path))
            {
                Console.WriteLine("The file exists");
                StreamReader sr = new StreamReader(File.OpenRead (path));
                fileLength =  sr.BaseStream.Length.ToString();
                Console.WriteLine(fileLength);

                byte[] buffer = new byte[(long)sr.BaseStream.Length];
                sr.BaseStream.Position = 0;
                sr.BaseStream.Read(buffer, 0, ((int)sr.BaseStream.Length));
                int i = 0;
                foreach ( byte myByte in buffer)
                {
                   
                    strBuffer += myByte.ToString("X2") + " ";
                    tbxText.Text = strBuffer;
                    i++;
                }
                               
                sr.Dispose();
            }
            else
            {
                Console.WriteLine("The file does NOT exists");
            }
            Console.WriteLine("Ended at : " + DateTime.Now);
            Console.WriteLine("Stop...");


        }
        
    }
}

Open in new window


Thanks,
Fulano
0
Comment
Question by:Mr_Fulano
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
15 Comments
 
LVL 12

Expert Comment

by:mwochnick
ID: 37840706
why read it a byte at a time your self
try something like this
// Read the file as one string.
System.IO.StreamReader myFile =
   new System.IO.StreamReader("c:\\test.txt");
string myString = myFile.ReadToEnd();

myFile.Close();

// Display the file contents.
Console.WriteLine(myString);
// Suspend the screen.
Console.ReadLine();

Open in new window


In your case assign myString to the textbox.Text
0
 
LVL 15

Expert Comment

by:Minh Võ Công
ID: 37840783
it’s doing so very, very slowly because this code:
 foreach ( byte myByte in buffer)
                {
                   
                    strBuffer += myByte.ToString("X2") + " ";
                    tbxText.Text = strBuffer;
                    i++;
                }

Open in new window

you can change to:
foreach ( byte myByte in buffer)
                {
                   
                    strBuffer += myByte.ToString("X2") + " ";
                  
                    i++;
                }
  tbxText.Text = strBuffer;

Open in new window

0
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 2000 total points
ID: 37840861
You could take it a step further and not use slow string concatenation.  Instead, use a StringBuilder:
        private void btnRead_Click(object sender, EventArgs e)
        {
            string path = @"C:\TestData\testfile.txt";
            System.IO.FileInfo fi = new FileInfo(path);
            System.Text.StringBuilder Buffer = new StringBuilder();

            Console.WriteLine("Started at : " + DateTime.Now.ToString());
            if (fi.Exists)
            {
                Console.WriteLine("The file exists");
                Console.WriteLine(fi.Length.ToString());
               
                foreach (byte myByte in System.IO.File.ReadAllBytes(fi.FullName))
                {
                    Buffer.Append(myByte.ToString("X2") + " ");
                }
                tbxText.Text = Buffer.ToString();
            }
            else
            {
                Console.WriteLine("The file does NOT exist.");
            }
            Console.WriteLine("Ended at : " + DateTime.Now.ToString());
            Console.WriteLine("Stop...");
        }

Open in new window


If you don't like ReadAllBytes(), then try a BinaryReader() with ReadByte():
        private void btnRead_Click(object sender, EventArgs e)
        {
            string path = @"C:\TestData\testfile.txt";
            System.IO.FileInfo fi = new FileInfo(path);
            System.Text.StringBuilder Buffer = new StringBuilder();

            Console.WriteLine("Started at : " + DateTime.Now.ToString());
            if (fi.Exists)
            {
                Console.WriteLine("The file exists");
                Console.WriteLine(fi.Length.ToString());

                using (BinaryReader br = new BinaryReader(fi.OpenRead()))
                {
                    while (br.PeekChar() != -1)
                    {
                        Buffer.Append(br.ReadByte().ToString("X2") + " ");
                    }
                }
                tbxText.Text = Buffer.ToString();
            }
            else
            {
                Console.WriteLine("The file does NOT exist.");
            }
            Console.WriteLine("Ended at : " + DateTime.Now.ToString());
            Console.WriteLine("Stop...");
        }

Open in new window

0
Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

 

Author Comment

by:Mr_Fulano
ID: 37841075
Wow...all very good suggestion. I tried Idle_Mind's first suggestion and was able to read a 704KB file in 3 seconds...now that's what I was looking for!!!

Idle_Mind, you offered two options....why would one be better that the other or why would I not want to use the ReadAllBytes() method?

Thanks for all your help!
Fulano
0
 

Author Comment

by:Mr_Fulano
ID: 37841085
Hi Minhve, I tried your suggestion, but it still took long...several minutes.

Thanks,
Fulano
0
 

Author Comment

by:Mr_Fulano
ID: 37841094
Hi Mwochnick, I also tried your suggestion, but it failed to give me the results I was expecting. Thanks for your help.

Fulano
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 37841104
You wouldn't want to use ReadAllBytes() with a LARGE file as it reads the entire file at once and returns a byte[] array.  This may take a long time and use a lot of memory.

For large files, you'd want to use the second approach that only reads a byte at a time.
0
 

Author Comment

by:Mr_Fulano
ID: 37841166
OK, thanks....one last question. I would also need a method that allows me to jump around the file. The StreamReader.BaseStream method allowed me a Position property. So, I was able to jump to byte number 208, if I had the need to do so.

How would I do that with your options?

Thanks,
Fulano
0
 

Author Comment

by:Mr_Fulano
ID: 37841183
Hi Idle_Mind, when you say:

You wouldn't want to use ReadAllBytes() with a LARGE file

what do you mean? What constitutes a large file (i.e. 1MB, 5MB, 20MB, 1GB, etc)?

Thanks,
Fulano
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 37842270
That really depends on the system on which the program is running.  A computer with tons of RAM and speed might do fine with a "large" file, while a smaller and slower system may fail or simply take much longer if it has to use the swap file on the hard drive for more memory.  The second approach may take a little longer but it will use only a tiny amount of memory.
0
 

Author Comment

by:Mr_Fulano
ID: 37842665
OK, thanks....one last question. I would also need a method that allows me to jump around the file. The StreamReader.BaseStream method allowed me a Position property. So, I was able to jump to byte number 208, if I had the need to do so.

How would I do that with your options?

Thanks,
Fulano
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 37843061
In the first option, you'd store the byte array before the foreach loop and then simply start at the correct index instead of at 0 (zero):
                byte[] bytes = System.IO.File.ReadAllBytes(fi.FullName);
                for (int i = 207; i < bytes.Length; i++)
                {
                    Buffer.Append(bytes[i].ToString("X2") + " ");
                }
                tbxText.Text = Buffer.ToString();

Open in new window


For the second option, you should be able to use BaseStream.Seek():
                using (BinaryReader br = new BinaryReader(fi.OpenRead()))
                {
                    br.BaseStream.Seek(207, SeekOrigin.Begin);
                    while (br.PeekChar() != -1)
                    {
                        Buffer.Append(br.ReadByte().ToString("X2") + " ");
                    }
                }
                tbxText.Text = Buffer.ToString();

Open in new window

0
 

Author Comment

by:Mr_Fulano
ID: 37845394
Very cool code Idle_Mind...very cool indeed!

Thanks again,
Fulano
0
 

Author Closing Comment

by:Mr_Fulano
ID: 37845396
Excellent code! Excellent explanation. Excellent help. Thank you very much.
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
This tutorial will teach you the special effect of super speed similar to the fictional character Wally West aka "The Flash" After Shake : http://www.videocopilot.net/presets/after_shake/ All lightning effects with instructions : http://www.mediaf…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …

721 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question