Just started with writing unit tests and I am now, blocked with this situation:
I have a method which has a FileStream object and I am trying to pass a "string" to it.
So, I would like to convert my string to FileStream and I am doing this:
File.WriteAllText(string.Concat(Environment.ExpandEnvironmentVariables("%temp%"),
#"/test.txt"), testFileContent); //writes my string to a temp file!
new FileStream(string.Concat(Environment.ExpandEnvironmentVariables("%temp%"),
#"/test.txt"), FileMode.Open) //open that temp file and uses it as a fileStream!
close the file then!
But, I guess there must be some very simple alternative to convert a string to a fileStream.
Suggestions are welcome! [Note there are other answers to this question in stackoverflow but none seems to be a straight forward solution to that]
Thanks in advance!
First of all change your method to allow Stream instead of FileStream. FileStream is an implementation which, as I remember, does not add any methods or properties, just implement abstract class Stream. And then using below code you can convert string to Stream:
public Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
As FileStream class provides a stream for a file and hence it's constructor requires the path of the file,mode, permission parameter etc. to read the file into stream and hence it is used to read the text from file into stream. If we need to convert string to stream first we need to convert string to bytes array as stream is a sequence of bytes. Below is the code.
//Stream is a base class it holds the reference of MemoryStream
Stream stream = new MemoryStream();
String strText = "This is a String that needs to beconvert in stream";
byte[] byteArray = Encoding.UTF8.GetBytes(strText);
stream.Write(byteArray, 0, byteArray.Length);
//set the position at the beginning.
stream.Position = 0;
using (StreamReader sr = new StreamReader(stream))
{
string strData;
while ((strData= sr.ReadLine()) != null)
{
Console.WriteLine(strData);
}
}
Related
From what I understand, the Formatter converts a serializable object into a stream of bytes and the Stream (e.g. FileStream) does the actual writing of those bytes into a file. Example code:
public static void SaveData(MySerializableData data)
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(SavePath, FileMode.Create);
formatter.Serialize(stream, data);
stream.Close();
}
However at other times, I'm also seeing this type of code:
void Save()
{
string data = "Value 1";
StreamWriter writer = new StreamWriter("MySaveFile.txt", true);
writer.Write(data);
}
Why is it that in the second case, we abandon the 2-step process of saving? Why do we sometimes use only StreamWriter, but at other times use both the formatter and a stream object?
Thank you!
BinaryFormatter serializes a class into a byte array and writes it to a stream. It's useful when you want to save/load classes with it's data. Serializtion stores metadata about the class graph that is storing.
StreamWriter is a stream that has specific functions to write a string into a file.
Consider this example:
MemoryStream mstr = new MemoryStream();
string datastr = "hello!";
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(mstr, datastr);
mstr.Seek(0, SeekOrigin.Begin);
string resultString = Encoding.ASCII.GetString(mstr.ToArray());
If you inspect resultString you will find that it contains something like this:
"\0\u0001\0\0\0????\u0001\0\0\0\0\0\0\0\u0006\u0001\0\0\0\u0006hello!\v"
Well, that's not what you would want to have in a text file, right? As you see serialization is not intended to store raw data but class instances.
Now check this:
MemoryStream mstr = new MemoryStream();
StreamWriter sw = new StreamWriter(mstr);
string datastr = "hello!";
sw.Write(datastr);
mstr.Seek(0, SeekOrigin.Begin);
sw.Close();
string resultString = Encoding.ASCII.GetString(mstr.ToArray());
If you now inspect resultString it will contain:
"hello!"
As you see it's very different, that's what you would expect in a text file.
You can also store raw binary data with a stream:
byte[] data = new byte[]{ 1,2,3,4 };
var fs = File.Create("out.dat"); //this creates a new file and creates a filestream
fs.Write(data, 0, data.Length);
fs.Close();
If you now inspect the file with a binary editor you will see it contains:
0x01, 0x02, 0x03, 0x04
There are many types of streams with different purposes (per example, the MemoryStream that I used in the examples, a binary stream that stores it's data into an array in memory) and a ton of classes that use streams for many things, in this case you have mixed the concepts of serialization and data storage using streams, those are two different things.
How did the MemoryStream close when it has not reached the end of its using statement?
MusicDataStore musicData = MusicDataStore.TestData();
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream memStream = new MemoryStream())
{
formatter.Serialize(memStream, musicData);
using (StreamReader reader = new StreamReader(memStream))
{
memStream.Position = 0;
Console.WriteLine(reader.ReadToEnd());
}
//deserialize
memStream.Position = 0;
MusicDataStore input = (MusicDataStore)formatter.Deserialize(memStream);
}
I should be able to deserialize the memStream but it cannot be read because it is closed.
When I tried removing the StreamReader block I can successfully deserialize the memStream. Why? What's happening to memStream in StreamReader block?
StreamReader takes ownership of the Stream it's given, and will close it when it is disposed (most of the types which take another IDisposable type in their constructor will do this).
This StreamReader constructor takes a boolean saying whether to leave the stream open after the StreamReader is disposed as its last parameter:
using (var reader = new StreamReader(memStream, Encoding.UTF8, true, 1024, true))
{
...
}
(Those other parameters are the defaults which StreamReader(Stream) uses, from the referencesource.)
As Marc Gravell rightly notes in the comments, we've said to use UTF-8 encoding, but it looks like your stream is binary and definitely not UTF-8 text! So expect this to fail in practice. It may be more useful to look at the output of BitConverter.ToString(memStream.GetBuffer(), 0, memStream.Length) (or more simply but less efficiently BitConverter.ToString(memStream.ToArray())).
I am trying to create a file using FileHelpers and then write that file out using SshNet all in memory.
So far I have the following:
var engine = new FileHelperEngine<MyObject>();
MemoryStream ms = new MemoryStream();
StreamWriter sw = new StreamWriter(ms);
engine.WriteStream(sw, MyData);
SshHelper ssh = new SshHelper("","","");
ssh.WriteFile("MyPath", sw.BaseStream);
However my issue is with the WriteFile method since it requires a Stream parameter and when I run my code I am getting an empty file.
How can I convert my StreamWriter (sw variable) into a Stream parameter?
EDIT:
I've tried both(not at the same time):
ms.Seek(0, SeekOrigin.Begin);
ms.Position = 0;
and it still writes a 0 byte file.
I further tested by using FileHelper to write to my local disk to verify that I have data. (Which I do)
your MemoryStream is the stream, the StreamWriter is just writing to it. Try passing ms in, instead of sw.
Before WriteFile try setting the Position of your Stream to 0: ms.Seek( 0, SeekOrigin.Begin )
I have a file with size 10124, I am adding a byte array, which has length 4 in the beginning of the file.
After that the file size should become 10128, but as I write it to file, the size decreased to 22 bytes. I don't know where is the problem
public void AppendAllBytes(string path, byte[] bytes)
{
var encryptedFile = new FileStream(path, FileMode.Open, FileAccess.Read);
////argument-checking here.
Stream header = new MemoryStream(bytes);
var result = new MemoryStream();
header.CopyTo(result);
encryptedFile.CopyTo(result);
using (var writer = new StreamWriter(#"C:\\Users\\life.monkey\\Desktop\\B\\New folder (2)\\aaaaaaaaaaaaaaaaaaaaaaaaaaa.docx.aef"))
{
writer.Write(result);
}
}
How can I write bytes to the file?
The issue seems to be caused by:
using a StreamWriter to write binary formatted data. The name does not inthuitively suggest this, but the StreamWriter class is suited for writing textual data.
passing an entire stream instead of the actual binary data. To obtain the bytes stored in a MemoryStream, use its convenient ToArray() method.
I suggest you the following code:
public void AppendAllBytes(string path, byte[] bytes)
{
var fileName = #"C:\\Users\\life.monkey\\Desktop\\B\\New folder (2)\\aaaaaaaaaaaaaaaaaaaaaaaaaaa.docx.aef";
using (var encryptedFile = new FileStream(path, FileMode.Open, FileAccess.Read))
using (var writer = new BinaryWriter(File.Open(fileName, FileMode.Append)))
using (var result = new MemoryStream())
{
encryptedFile.CopyTo(result);
result.Flush(); // ensure header is entirely written.
// write header directly, no need to put it in a memory stream
writer.Write(bytes);
writer.Flush(); // ensure the header is written to the result stream.
writer.Write(result.ToArray());
writer.Flush(); // ensure the encryptdFile is written to the result stream.
}
}
The code above uses the BinaryWriter class which is better suited for binary data. It has a Write(byte[] bytes) method overload that is used above to write an entire array to the file. The code uses regular calls to the Flush() method that some may consider not needed, but these guarantee in general, that all the data written prior the call of the Flush() method is persisted within the stream.
I'm trying to convert a .db file to binary so I can stream it across a web server. I'm pretty new to C#. I've gotten as far as looking at code snippets online but I'm not really sure if the code below puts me on the right track. How I can write the data once I read it? Does BinaryReader automatically open up and read the entire file so I can then just write it out in binary format?
class Program
{
static void Main(string[] args)
{
using (FileStream fs = new FileStream("output.bin", FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
long totalBytes = new System.IO.FileInfo("input.db").Length;
byte[] buffer = null;
BinaryReader binReader = new BinaryReader(File.Open("input.db", FileMode.Open));
}
}
}
}
Edit: Code to stream the database:
[WebGet(UriTemplate = "GetDatabase/{databaseName}")]
public Stream GetDatabase(string databaseName)
{
string fileName = "\\\\computer\\" + databaseName + ".db";
if (File.Exists(fileName))
{
FileStream stream = File.OpenRead(fileName);
if (WebOperationContext.Current != null)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "binary/.bin";
}
return stream;
}
return null;
}
When I call my server, I get nothing back. When I use this same type of method for a content-type of image/.png, it works fine.
All the code you posted will actually do is copy the file input.db to the file output.bin. You could accomplish the same using File.Copy.
BinaryReader will just read in all of the bytes of the file. It is a suitable start to streaming the bytes to an output stream that expects binary data.
Once you have the bytes corresponding to your file, you can write them to the web server's response like this:
using (BinaryReader binReader = new BinaryReader(File.Open("input.db",
FileMode.Open)))
{
byte[] bytes = binReader.ReadBytes(int.MaxValue); // See note below
Response.BinaryWrite(bytes);
Response.Flush();
Response.Close();
Response.End();
}
Note: The code binReader.ReadBytes(int.MaxValue) is for demonstrating the concept only. Don't use it in production code as loading a large file can quickly lead to an OutOfMemoryException. Instead, you should read in the file in chunks, writing to the response stream in chunks.
See this answer for guidance on how to do that
https://stackoverflow.com/a/8613300/141172