Get remnants from StreamReader - c#

I have a stream reader that I am using to read lines from a stream. This works well however I would like to be able to get the last line which will never end with a line break so the readLine() will not capture it.
I will store this is a global variable and append to the stream before the next run.
Is this possible at all?
void readHandler(IAsyncResult result)
{
tcpClient = (TcpClient)result.AsyncState;
StreamReader reader ;
string line;
using (reader = new StreamReader(stream))
{
while((line = reader.ReadLine()) != null){
System.Diagnostics.Debug.Write(line);
System.Diagnostics.Debug.Write("\n\n");
}
}
getData();
}

ReadLine does capture the final line of the stream even if it doesn't have a line-break after it. For example:
using System;
using System.IO;
class Test
{
static void Main()
{
string text = "line1\r\nline2";
using (TextReader reader = new StringReader(text))
{
string line;
while((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
}
}
Prints:
line1
line2
ReadLine() will only return null when it's reached the end of the stream and returned all of the data.

Unless you really need to do this line by line, you could do away with this entire loop and just use the StreamReader.ReadToEnd method. That will give you everything that's currently in the buffer.

Related

How do you cause a filestream to re-read a line in the event of an exception?

I have a filestream being read by a streamreader. I want to return the position of the stream to the previous line in the event of an IOException to try and read the same line again. I tried to just record the position of the stream before the line, and then seek to that point, but I must be misunderstanding or misusing it.
using (var fs = new FileStream("MyPath\\linetest.txt", FileMode.Open))
using (var sr = new StreamReader(fs))
{
Console.WriteLine(fs.CanSeek);
while (!sr.EndOfStream)
{
string line;
try
{
var streamPosition = fs.Position;
line = sr.ReadLine();
if (line.StartsWith("#"))
{
fs.Seek(streamPosition, SeekOrigin.Begin);
throw new IOException();
}
Console.WriteLine(line);
}
catch (IOException e)
{
Console.WriteLine(e.Message);
}
}
In case its not obvious, I'm throwing an exception when a line is read that starts with "#". only one line in my 7 line test file starts with #, so I would expect that line to be written in an infinite loop, however, when I execute this, it prints each line of the file, substituting the exception message for the line that starts with #. Any insight or help you guy and gals could offer would be appreciated!
The reason why your code goes through to the end of input file is that the position you take by fs.Position is the one up to which StreamReader reads from FileStream into StreamReader's buffer at that phase (Position A). This is different from the position up to which StreamReader has returned lines by sr.ReadLine() (Position B). Off course, Position A is always ahead of Position B.
StreamReader does not have a way to provide Position B. It is not impossible to acquire such physical position by accumulatively calculating from what ReadLine() returns every time, but think of a variety of encoding and EOL and BOM code. That'll be not easy to be accurate.
Instead, why don't you get logical position after the decode by StreamReader? I mean, keep the line number in this case.
var row = 0;
using (var fs = new FileStream("input/sample.txt", FileMode.Open)
using (var sr = new StreamReader(fs))
{
Console.WriteLine(fs.CanSeek);
while (!sr.EndOfStream)
{
try
{
var line = sr.ReadLine();
if (line.StartsWith("#"))
throw new IOException();
row++;
Console.WriteLine(line);
}
catch (IOException e)
{
Console.WriteLine(e.Message);
// Reset to the line where the exception happened
fs.Seek(0, SeekOrigin.Begin);
sr.DiscardBufferedData();
for (var i = 0; i < row; i++)
sr.ReadLine();
}
}
}
sr.DiscardBufferedData() in the catch block is for clearing up the buffer in StreamReader that I mentioned at the beginning. Keep it in mind that sr.DiscardBufferedData() slows performance, which is mentioned in here.
I don't get why you want to keep the file stream open and keep getting the same error result. Be aware that the program never get updates on the file while the stream is open. Therefore, I leave one more code, which can keep reading the same line until the line is corrected, provided that already-processed lines are never edited in terms of line break.
var row = 0;
while (true)
{
using (var fs = new FileStream("input/sample.txt", FileMode.Open))
using (var sr = new StreamReader(fs))
{
for (var i = 0; i < row; i++)
sr.ReadLine();
try
{
while (!sr.EndOfStream)
{
var line = sr.ReadLine();
if (line.StartsWith("#"))
throw new IOException();
row++;
Console.WriteLine(line);
}
}
catch (IOException e)
{
Console.WriteLine(e.Message);
}
if (sr.EndOfStream)
break;
}
}
However, in either way, repeatedly reading through from the beginning to the error line is not so good even if you concern performance. In that case, you should reconsider the design how you input data.

how read not empty lines of file in StreamReader

i want check if lines of file is more than 20 (for example) then prevent user to upload text file so want read file only once this is my code
using (Stream stream = fileUploadBatch.FileContent)
{
stream.Seek(0, SeekOrigin.Begin);
using (StreamReader streamReader = new StreamReader(stream))
{
string line = null;
List<string> fileLines = new List<string>();
while (!streamReader.EndOfStream && fileLines.Count < 50)
{
line = streamReader.ReadLine();
if(strig.IsNullOrEmpty(line))
return;
fileLines.Add(line);
}
// do something with list
}
}
this is bad practice because result of streamReader.ReadLine() assigns to line variable and create memory issues (string is immutable)
so i want add not empty line in to list without storing in line variable

StreamWriter Not working in C#

This piece of code worked perfectly in VS 2010. Now that I have VS 2013 it no longer writes to the file. It doesn't error or anything. (I get an alert in Notepad++ stating that the file has been updated, but there is nothing written.)
It all looks fine to me. Any Ideas?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
String line;
try
{
//Pass the file path and file name to the StreamReader constructor
StreamReader sr = new StreamReader("C:\\Temp1\\test1.txt");
StreamWriter sw = new StreamWriter("C:\\Temp2\\test2.txt");
//Read the first line of text
line = sr.ReadLine();
//Continue to read until you reach end of file
while (line != null)
{
//write the line to console window
Console.WriteLine(line);
int myVal = 3;
for (int i = 0; i < myVal; i++)
{
Console.WriteLine(line);
sw.WriteLine(line);
}
//Write to the other file
sw.WriteLine(line);
//Read the next line
line = sr.ReadLine();
}
//close the file
sr.Close();
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
finally
{
Console.WriteLine("Executing finally block.");
}
}
}
}
You need to close StreamWriter. Like this:
using(var sr = new StreamReader("..."))
using(var sw = new StreamWriter("..."))
{
...
}
This will close streams even if exception is thrown.
You need to Flush() the StreamWriter after write.
By default StreamWriter is buffered that means it won't output until it receives a Flush() or Close() call.
Also you can also try to close it like this:
sw.Close(); //or tw.Flush();
You can also have a look at StreamWriter.AutoFlush Property
Gets or sets a value indicating whether the StreamWriter will flush
its buffer to the underlying stream after every call to
StreamWriter.Write.
The other option which is now a days very popular and recommended is to use the using statement which takes care of it.
Provides a convenient syntax that ensures the correct use of
IDisposable objects.
Example:
using(var sr = new StreamReader("C:\\Temp1\\test1.txt"))
using(var sw = new StreamWriter("C:\\Temp2\\test2.txt"))
{
...
}

Reading resource txt line by line

Had a txt file on my desktop with code:
string source = #"C:\Users\Myname\Desktop\file.txt"
string searchfor = *criteria person enters*
foreach (string content in File.ReadLines(source))
{
if (content.StartsWith(searchfor)
{
*do stuff*
}
}
I recently just learned I can add the txt as a resource file (as it will never be changed). However, I cannot get the program to read that file.txt as a resource line by line like above. I have tried
Assembly.GetExecutingAssembly().GetManifestResourceStream("WindowsFormsApplication.file.txt")
with a stream reader but it says invalid types.
Basic concept: user enters data, turned into a string, compared to the starting line of the file.txt as it reads down the list.
Any help?
edit
Jon, I tried as a test to see if it is even reading the file:
var assm = Assembly.GetExecutingAssembly();
using (var stream = assm.GetManifestResourceStream("WindowsFormsApplication.file.txt")) ;
{
using (var reader = new StreamReader(stream))
{
string line;
while ((line = reader.ReadLine()) != null)
{
label1.Text = line;
}
}
}
It says "The name stream does not exist in the current context" and "Possible Mistaken Empty Statement" for the stream = assm.Get line
You can use a TextReader to read a line at a time - and StreamReader is a TextReader which reads from a stream. So:
var assm = Assembly.GetExecutingAssembly();
using (var stream = assm.GetManifestResourceStream("WindowsFormsApplication.file.txt"))
{
using (var reader = new StreamReader(stream))
{
string line;
while ((line = reader.ReadLine()) != null)
{
...
}
}
}
You could write an extension method on TextReader to read all the lines, but the above is simpler if you only need this once.
Found the issue:
The file, while loaded as a resource, despite all the tutorials saying it is NameSpace.File, the truth is the system puts the location as NameSpace.Resources.File, so I had to update that as well.
Then I used the following code:
string searchfor = textBox1.Text
Assembly assm = Assembly.GetExecutingAssembly();
using (Stream datastream = assm.GetManifestResourceStream("WindowsFormsApplication2.Resources.file1.txt"))
using (StreamReader reader = new StreamReader(datastream))
{
string lines;
while ((lines = reader.ReadLine()) != null)
{
if (lines.StartsWith(searchfor))
{
label1.Text = "Found";
break;
}
else
{
label1.Text = "Not found";
}
}
}

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":
c can't be changed (it's the foreach iteration variable), you'll need to copy it in order to process before writing
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();
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!
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());
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.

Categories

Resources