Mr_Fulano
asked on
Reading bytes from a text file using "StreamReader.BaseStream".
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?
Thanks,
Fulano
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...");
}
}
}
Thanks,
Fulano
it’s doing so very, very slowly because this code:
foreach ( byte myByte in buffer)
{
strBuffer += myByte.ToString("X2") + " ";
tbxText.Text = strBuffer;
i++;
}
you can change to:foreach ( byte myByte in buffer)
{
strBuffer += myByte.ToString("X2") + " ";
i++;
}
tbxText.Text = strBuffer;
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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
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
ASKER
Hi Minhve, I tried your suggestion, but it still took long...several minutes.
Thanks,
Fulano
Thanks,
Fulano
ASKER
Hi Mwochnick, I also tried your suggestion, but it failed to give me the results I was expecting. Thanks for your help.
Fulano
Fulano
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.
For large files, you'd want to use the second approach that only reads a byte at a time.
ASKER
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
How would I do that with your options?
Thanks,
Fulano
ASKER
Hi Idle_Mind, when you say:
what do you mean? What constitutes a large file (i.e. 1MB, 5MB, 20MB, 1GB, etc)?
Thanks,
Fulano
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
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.
ASKER
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
How would I do that with your options?
Thanks,
Fulano
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):
For the second option, you should be able to use BaseStream.Seek():
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();
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();
ASKER
Very cool code Idle_Mind...very cool indeed!
Thanks again,
Fulano
Thanks again,
Fulano
ASKER
Excellent code! Excellent explanation. Excellent help. Thank you very much.
try something like this
Open in new window
In your case assign myString to the textbox.Text