I have a program that creates a huge string, too large for StringBuilder to handle. I want to store it in memory, then, at a later date, save it to a user defined directory.
I have tried a StreamWriter but I need to declare the directory as I create it and that is problem because I get the directory later on, if the user selects the "Save to text file".
Basically I need it to:
-Create instance of whatever it is (public and in a class scope, can not be in a method scope)
-Add a string to instance
-Then, later on, whenever the user decides, save that to a file. I am aware it will take up a large amount of RAM and I believe it will only be around 50-100Mb, which isn't too bad.
public class ImageProcessor
{
MemoryStream ms = new MemoryStream();
StreamWriter sw;
public Bitmap Rendering(string bmpPath)
{
sw = new StreamWriter(ms, System.Text.Encoding.UTF8);
using (ms)
sw.Write(Convert.ToString(ArGBformat)); //Error is here
}
}
`
Here's a code snippet that may help you. I just tested it in VS 2012:
using (MemoryStream ms = new MemoryStream)
{
StreamWriter sw = new StreamWriter(ms, System.Text.Encoding.UTF8)
sw.WriteLine("This is a test.");
sw.WriteLine("This is a second line.");
sw.Flush();
using (FileStream fs = new FileStream("Test.txt", FileMode.Create))
{
ms.CopyTo(fs);
}
sw.Close();
}
The file contents are:
This is a test.
This is a second line.
You'll want to modify this to fit your program's design, but the basic idea is using a StreamWriter to write the text to the MemoryStream, and then writing the MemoryStream to the file with the MemoryStream.CopyTo method (which takes a Stream).
Be careful with how you construct things - if you close the StreamWriter it will close the MemoryStream as well (the first time I tested this I had the StreamWriter in a using block inside the MemoryStream using block, and then got an error trying to access a closed stream).
Hopefully this will at least get you going in the right direction.
EDIT
You'll need to initialize the StreamWriter in a method, not as a field variable.
Something like this:
public class ImageProcessor
{
MemoryStream ms = new MemoryStream();
StreamWriter sw;
public Bitmap Rendering(string bmpPath)
{
sw = new StreamWriter(ms, System.Text.Encoding.UTF8);
}
}
Related
I was wondering if someone can help me solve a issue I have run into while playing with FileStreams. I have been trying to send an integer, 50, to a FileStream and write its value onto a File. However, it writes 2 to the file instead of 50. I know the ASCII representation of 50 is 2, so am not sure if this is part of the issue. If anyone has any pointers, I'd really appreciate it!
Here is my relevant code:
From the main function:
string testMessage = "Testing writing some arbitrary string to a streama";
int tmL = testMessage.Length;
byte bb = Convert.ToByte(tmL);
SendByteStrem(bb);
And here is my streaming function:
public static void SendByteStrem(byte c){
using (Stream ioStream = new FileStream(#"C:\Users\db0201\Desktop\stream.txt", FileMode.OpenOrCreate)){
ioStream.WriteByte(c);
}
}
As you haven't explicitly stated your goal, i will answer the question for what it is.
The easiest way to write to a file would be to use File.WriteAllText which essentially opens a StreamWriter (which in-turn is open a FileStream) and calls Write
Creates a new file, write the contents to the file, and then closes
the file. If the target file already exists, it is overwritten.
File.WriteAllText(fileName, "50")
or
var myInt = 50;
File.WriteAllText(fileName, myInt.ToString())
If you wanted to use the StreaWriter exclusively
using (varwriter = new StreamWriter(fileName))
writer.Write(myInt.ToString());
If you wanted more configuration over the underlying FileStream
using (var writer = new StreamWriter(new FileStream(fileName, FileMode.CreateNew)))
writer.Write(myInt.ToString());
if you just want to use a FileStream then things get a bit more manual as you will need to convert things to bytes
using (var stream = new FileStream(fileName, FileMode.CreateNew))
{
var bytes = Encoding.UTF8.GetBytes(myInt.ToString());
stream.Write(bytes, 0, bytes.Length);
}
I'm using the following lines of code in order to write credentials of users to a text file. It's supposed to create the directory inside AppData (which it does) but it doesn't write the credentials to the text file, it leaves it blank!
public void RegisterUserCreds()
{
string[] creds = { Username.Text, Password.Text };
string roaming = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
if (!Directory.Exists(roaming + "/Launcher"))
Directory.CreateDirectory(roaming + "/Launcher");
string specificFolder = roaming + "/Launcher/user_info.txt";
var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite);
var sw = new StreamWriter(fs);
sw.WriteLine(Username.Text);
fs.Close();
}
What's the problem? Thanks!
Just use the using statement when operating on streams:
public static void RegisterUserCreds()
{
string[] creds = { Username.Text, Password.Text };
string roaming = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
if (!Directory.Exists(roaming + "/Launcher")) Directory.CreateDirectory(roaming + "/Launcher");
string specificFolder = roaming + "/Launcher/user_info.txt";
using (var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (var sw = new StreamWriter(fs))
{
sw.WriteLine(Username.Text);
}
}
}
In your code you were closing the file stream before the stream writer was able to flush the changes you want to write so the file was created empty.
You're closing the wrong stream. When you create new stream objects and pass an existing stream to the constructor, that new stream now "owns" the old stream. When you dispose of the newer stream it will automatically dispose of the older one.
In your situation, you're closing the "fs" stream, but the "sw" stream might not have actually written to it yet (it has it's own internal buffer). If you were to close the "sw" stream instead, it would flush it's buffer (into the "fs" stream), and then it would call fs.Dispose() for you to make sure it did the same thing.
There's a much better way, that would help you avoid doing things out-of-order like this, as well as make sure you're calling Dispose() even if exceptions get thrown (streams implement IDisposable, so you're supposed to always call their Dispose() method when you're done with them so they can internally "clean up"). The using statement is perfect for this, since it will call Dispose() even if an exception is thrown (it's a shortcut for wrapping the code with try/finally blocks):
using (var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (var sw = new StreamWriter(fs))
{
sw.WriteLine(Username.Text);
}
}
This is the same as this:
try
{
var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite);
try
{
var sw = new StreamWriter(fs);
sw.WriteLine(Username.Text);
}
finally
{
sw.Dispose();
}
}
finally
{
fs.Dispose();
}
Even though sw.Dispose() will call fs.Dispose() for you, there is no harm in calling fs.Dispose() again. Why is it important to call Dispose()? Let's say an exception was thrown during sw.WriteLine() (e.g. out of disk space, I/O error, etc.)... the file would stay open until your app terminated. The using (or the try/catch version) would make sure the file was closed no matter what.
(side note: with streams, Dispose() and Close() do the same thing, you don't need to call both. Close() just calls Dispose() -- MS included a method called Close() because that was what people were used to with a file API, but the .NET IDisposable interface uses a method called Dispose())
(another side note: starting with .NET 4.5, many of the stream classes have an additional constructor that has a new "leaveOpen" parameter... passing true would tell that stream to NOT dispose of the original stream automatically)
I have an array list which contains 100 lines.
When i try to export it into a text file (txt), the output is only 84 lines and it stops in the middle of the 84th line.
When I looked at the file size it showed exactly sharp 4.00KB as if there is some kind of a limit to the stream writer. I tried using different parameters etc. but it kept happening.
Here is the code:
FileStream fs = new FileStream(path, FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
ArrayList chartList = GetChart(maintNode);
foreach (var line in chartList)
{
sw.WriteLine(line);
}
fs.Close();
Console.WriteLine("Done");
Thanks for the help!
You need to call StreamWriter.Flush or set StreamWriter.AutoFlush to true. That said, if you use using statment, everything should work fine.
using(StreamWriter sw = new StreamWriter(fs))
{
ArrayList chartList = GetChart(maintNode);
foreach (var line in chartList)
{
sw.WriteLine(line);
}
}
Using statement calls Dispose which will flush the buffer to the FileStream and also closes the file stream. So you don't need to close it manually.
Then I recommend List<T> over ArrayList. ArrayList shouldn't be used, it is not type safe and should be avoided if you're in .Net2.0 or greater.
Also consider using File.WriteAllLines method, so that you don't need these many lines of code. Everything is managed by WriteAllLines method itself.
I'm attempting to use StreamReader and StreamWriter to grab a temporary output log (.txt format) from another application.
The output log is always open and constantly written to.
Unhelpfully if the application closes or crashes, the log file ends up deleted - hence the need for a tool that can grab the information from this log and save it.
What my program currently does is:
Create a new .txt file, and stores the path of that file as the
string "destinationFile".
Finds the .txt log file to read, and stores the path of that file as
the string "sourceFile"
It then passes those two strings to the method below.
Essentially I'm trying to read the sourceFile one line at a time.
Each time one line is read, it is appended to destinationFile.
This keeps looping until the sourceFile no longer exists (i.e. the application has closed or crashed and deleted its log).
In addition, the sourceFile can get quite big (sometimes 100Mb+), and this program may be handling more than one log at a time.
Reading the whole log rather than line by line will most likely start consuming a fair bit of memory.
private void logCopier(string sourceFile, string destinationFile)
{
while (File.Exists(sourceFile))
{
string textLine;
using (var readerStream = File.Open(sourceFile,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
using (var reader = new StreamReader(readerStream))
{
while ((textLine = reader.ReadLine()) != null)
{
using (FileStream writerStream = new FileStream(destinationFile,
FileMode.Append,
FileAccess.Write))
using (StreamWriter writer = new StreamWriter(writerStream))
{
writer.WriteLine(textLine);
}
}
}
}
}
The problem is that my WPF application locks up and ceases to respond when it reaches this code.
To track down where, I put a MessageBox just before the writerStream line of the code to output what the reader was picking up.
It was certainly reading the log file just fine, but there appears to be a problem with writing it to the file.
As soon as it reaches the using (FileStream writerStream = new FileStream part of the code, it stops responding.
Is using the StreamWriter in this manner not valid, or have I just gone and dome something silly in the code?
Am also open to a better solution than what I'm trying to do here.
Simply what I understand is you need to copy a file from source to destination which may be deleted at any time.
I'll suggest you to use FileSystemWatcher to watch for source file changed event, then just simply copy the whole file from source to destination using File.Copy.
I've just solved the problem, and the issue was indeed something silly!
When creating the text file for the StreamWriter, I had forgotten to use .Dispose();. I had File.Create(filename); instead of File.Create(filename).Dispose(); This meant the text file was already open, and the StreamWriter was attempting to write to a file that was locked / in use.
The UI still locks up (as expected), as I've yet to implement this on a new thread as SteenT mentioned. However the program no longer crashes and the code correctly reads the log and outputs to a text file.
Also after a bit of refinement, my log reader/writer code now looks like this:
private void logCopier(string sourceFile, string destinationFile)
{
int num = 1;
string textLine = String.Empty;
long offset = 0L;
while (num == 1)
{
if (File.Exists(sourceFile))
{
FileStream stream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using (new StreamReader(stream))
{
stream.Seek(offset, SeekOrigin.Begin);
TextReader reader2 = new StreamReader(stream);
while ((textLine = reader2.ReadLine()) != null)
{
Thread.Sleep(1);
StreamWriter writer = new StreamWriter(destinationFile, true);
writer.WriteLine(textLine);
writer.Flush();
writer.Close();
offset = stream.Position;
}
continue;
}
}
else
{
num = 0;
}
}
}
Just putting this code up here in case anyone else is looking for something like this. :)
for an application that uses a File as some sort of global storage for device reservations in a firm I need a way to read and write to a file (or lock a file, read from it, write to it, and unlock it). A little code snippet will shot what I mean:
FileStream in = new FileStream("storage.bin", FileMode.Open);
//read the file
in.Close();
//!!!!!
//here is the critical section since between reading and writing, there shouldnt
//be a way for another process to access and lock the file, but there is the chance
//because the in stream is closed
//!!!!!
FileStream out = new FileStream("storage.bin", FileMode.Create);
//write data to file
out.Close();
this should get something like this
LockFile("storage.bin");
//read from it...
//OVERwrite it....
UnlockFile("storage.bin");
the method should be absolute safe, since the program should run on 2000 devices at the same time
Simply holding a FileStream open with exclusive (not shared) access will prevent other processes from accessing the file. This is the default when opening a file for read/write access.
You can 'overwrite' a file that you currently hold open by truncating it.
So:
using (var file = File.Open("storage.bin", FileMode.Open))
{
// read from the file
file.SetLength(0); // truncate the file
// write to the file
}
the method should be absolute safe, since the program should run on 2000 devices at the same time
Depending on how often you're writing to the file, this could become a chokepoint. You probably want to test this to see how scalable it is.
In addition, if one of the processes tries to operate on the file at the same time as another one, an IOException will be thrown. There isn't really a way to 'wait' on a file, so you probably want to coordinate file access in a more orderly fashion.
You need a single stream, opened for both reading and writing.
FileStream fileStream = new FileStream(
#"c:\words.txt", FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None);
Alternatively you can also try
static void Main(string[] args)
{
var text = File.ReadAllText(#"C:\words.txt");
File.WriteAllText(#"C:\words.txt", text + "DERP");
}
As per http://msdn.microsoft.com/en-us/library/system.io.fileshare(v=vs.71).aspx
FileStream s2 = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.None);
You need to pass in a FileShare enumeration value of None to open on the FileStream constructor overloads:
fs = new FileStream(#"C:\Users\Juan Luis\Desktop\corte.txt", FileMode.Open,
FileAccess.ReadWrite, FileShare.None);
I ended up writing this helper class to do this:
public static class FileHelper
{
public static void ReplaceFileContents(string fileName, Func<String, string> replacementFunction)
{
using (FileStream fileStream = new FileStream(
fileName, FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None))
{
StreamReader streamReader = new StreamReader(fileStream);
string currentContents = streamReader.ReadToEnd();
var newContents = replacementFunction(currentContents);
fileStream.SetLength(0);
StreamWriter writer = new StreamWriter(fileStream);
writer.Write(newContents);
writer.Close();
}
}
}
which allows you to pass a function that will take the existing contents and generate new contents and ensure the file is not read or modified by anything else whilst this change is happening
You are likely looking for FileStream.Lock and FileStream.Unlock
I think you just need to use the FileShare.None flag in the overloaded Open method.
file = File.Open("storage.bin", FileMode.Open, FileShare.None);