Reputation: 494
I am trying to read from a .json file in two different methods, like so:
void mainMethod()
{
Stream theFile = Assembly.GetExecutingAssembly().GetManifestResourcesStream("pathToFile");
Method1(theFile);
Method2(theFile);
}
void Method1(Stream file)
{
using (StreamReader fileUsage_1 = new StreamReader(file))
{
//do stuff with file
}
}
void Method2(Stream file)
{
using (StreamReader fileUsage_2 = new StreamReader(file))
{
//do stuff with file
}
}
Running the mainMethod()
gives the exception: Stream was not readable.
in Method2()
I believe the problem is that Method2()
is trying to read theFile
when it is still being used in Method1()
. I thought the using
blocks closed the file automatically? How can I customize the way I am reading theFile
in Method1()
and Method2()
so they don't "overlap"?
Upvotes: 0
Views: 1099
Reputation: 5204
Open the StreamReader once and set the position when in each Method. This way the order of calling methods is not fixed. When you first open the StreamReader the position is set to the beginning by default, so the first call to Seek(0,SeekOrigin.Begin) is redundant but allows for the order of calling to be interchanged in the future.
void mainMethod()
{
Stream theFile = Assembly.GetExecutingAssembly().GetManifestResourcesStream("pathToFile");
using (StreamReader fileUsage = new StreamReader(theFile))
{
Method1(fileUsage);
Method2(fileUsage);
}
}
private static void Method1(StreamReader fileUsage)
{
if (fileUsage != null && fileUsage.BaseStream.CanSeek && fileUsage.BaseStream.CanRead)
{
fileUsage.BaseStream.Seek(0, SeekOrigin.Begin);
fileUsage.DiscardBufferedData();
Console.WriteLine(fileUsage.ReadLine());
}
}
Upvotes: 2
Reputation: 2052
Call me crazy...but can't you simply abstract the using statement out of the methods and into the main program? Like so. Edited to include reseting of position if you choose to do so. (Can go to Here for more information on discarding buffer data)
namespace ConsoleApplication12
{
class Program
{
static void Main(string[] args)
{
Stream theFile = Assembly.GetExecutingAssembly().GetManifestResourceStream("ConsoleApplication12.test.txt");
using (StreamReader fileUsage_1 = new StreamReader(theFile))
{
Method1(fileUsage_1);
ResetPosition(theFile, fileUsage_1); // If needed
Method2(fileUsage_1);
}
Console.ReadLine();
}
private static void Method2(StreamReader fileUsage)
{
var test = fileUsage.ReadLine();
}
private static void Method1(StreamReader fileUsage)
{
var test = fileUsage.ReadLine();
}
private static void ResetPosition(Stream s, StreamReader sr)
{
s.Position = 0;
sr.DiscardBufferedData();
}
}
}
Upvotes: 1
Reputation: 101
Set the Stream.Position as previously stated. set it thus:
file.Seek(System.IO.SeekOrigin.Begin);
Also the Using blocks on the StreamReader close the underlying stream when they exit. You can use the File.ReadAllText method to Open, Read and Close(Dispose) of a File all with that single call:
string jsonString = File.ReadAllText(filePath);
Upvotes: 0
Reputation: 100547
Re-reading whole stream is possible if:
stream.CanSeek == true
)You generally have no control over 1, but you can copy whole srteam into seek-able one if needed (i.e. using Stream.Copy
to MemoryStream
).
To stop reader from closing stream - use constructor that does not take ownership of stream and as reslut will not close stream after using. I.e. StreamReader(...,bool leaveOpen).
Finally you need to seek stream to position where other reader need to start (often beginning) with something like Stream.Position = 0;
Notes
Method2
from the point where Method1
left you don't need to seek, just make sure readers don't close stream.using
/ .Close
call), but such code would look wrong and when one "fixes" it by adding using
it will no longer work correctly.Upvotes: 0