write to csv file gets cut when writing using file.writeallbytes - c#

I am trying to read a CSV file and storing it in object.
I then write the object into a file using bytes
File.WriteAllBytes("some.csv",ObjectToByteArray(items));
private byte[] ObjectToByteArray(Object obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
return encoding.GetBytes(ms.ToString());
}
The file doesnt get written completely and it gets cut. I sense this is due to stream size restrictions.
How to ensure the entire file is being written correctly. When I use CSVwriter it still doesnt seem to work.

Related

Writing to MemoryStream not working as expected

I'm using the DryWetMidi library to process some MIDI data.
First I get the MIDI Data as a MemoryStream from the Clipboard:
MemoryStream ms = (MemoryStream)Clipboard.GetDataObject().GetData("Standard MIDI File");
MidiFile mid = MidiFile.Read(ms);
Then I do some stuff with the midi:
mid.RemoveNotes(n => n.NoteName == NoteName.FSharp);
Now I want to write it back to the Clipboard. I managed to do this like this:
using (FileStream file = new FileStream("file.mid", FileMode.Create, FileAccess.
{
mid.Write(file);
}
using (MemoryStream ms2 = new MemoryStream())
using (FileStream file = new FileStream("file.mid", FileMode.Open, FileAccess.Read))
{
byte[] bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
ms2.Write(bytes, 0, (int)file.Length);
Clipboard.Clear();
Clipboard.SetData(midiFormat, ms2);
}
File.Delete("file.mid");
As you can see, first I write the MIDI to a file, then I read that file into a MemoryStream which I then write into the Clipboard. This makes not much sense, because it would be simpler to write it to a MemoryStream directly. Also, I don't want to write a file to the users file system. But there's the problem. I tried it like this:
using (MemoryStream ms2 = new MemoryStream())
{
mid.Write(ms2);
}
This doesn't give me an error, but the MemoryStream is completely empty. Calling ms2.Length results in a System.ObjectDisposedException.
How can I write the midi directly into the MemoryStream?
EDIT: Here's the link to the DryWetMidi Write() Method.
Second Edit: Here's a piece of code that won't work:
MemoryStream ms = (MemoryStream)Clipboard.GetDataObject().GetData(midiFormat);
MidiFile mid = MidiFile.Read(ms);
mid.RemoveNotes(n => n.NoteName == NoteName.FSharp);
MemoryStream ms2 = new MemoryStream();
mid.Write(ms2);
var T = ms2.Length; //This will throw an exception
Third Edit: I am 100% sure that the code posted is exactly the same I'm running. Here's the StackTrace. (Gist because formatting was terrible on SO).
As far as I can see, DryWetMidi uses BinaryWriter to write to stream. And the default behaviour of BinaryWriter is that when it is disposed, It'll dispose the stream as well.
You can't read from MemoryStream when it's disposed but you can call ToArray().
byte[] result;
using (MemoryStream ms2 = new MemoryStream())
{
mid.Write(ms2);
result = ms2.ToArray();
}

Convert object to CSV and then compress without touching physical storage

Scenario
I have a object that I convert to a flat CSV and then compress and upload to a filestore.
I could easily do this by following the below steps.
Convert object to CSV file.
Compress file
Upload file.
However
I do not want the penalty that comes with touching physical storage so would like to do all this in memory.
Current Incorrect Implementation
Convert object to CSV byte array
Compress byte array
Upload byte array to file store
Problem
What i'm essentially doing is compressing a byte array and uploading that. which is obviously wrong. (Because when the compressed Gzip file is uncompressed, it contains a byte array of the csv and not the actual csv itself.)
Is it possible to create a file like "file.csv" in memory and then compress that in memory, instead of compressing a byte array?
The problem I'm having is it would seem I can only name the file and specify its extension when saving to a physical location.
Code Example of Current Implementation
public byte[] Example(IEnumerable<object> data)
{
// Convert Object to CSV and write to byte array.
byte[] bytes = null;
using (var ms = new MemoryStream())
{
TextWriter writer = new StreamWriter(ms);
var csv = new CsvWriter(writer);
csv.WriteRecords(data);
writer.Flush();
ms.Position = 0;
bytes = ms.ToArray();
}
//Compress byte array
using (var compressedStream = new MemoryStream(bytes))
using (var resultStream = new MemoryStream())
using (var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
{
zipStream.CopyTo(resultStream);
zipStream.Close();
var gzipByteArray = resultStream.ToArray();
//Upload to AzureStorage
new AzureHelper().UploadFromByteArray(gzipByteArray, 0, gzipByteArray.Length);
}
}
Wrap the Stream you use for the upload in a GZipStream, write your CSV to that, and the then you'll have uploaded the compressed CSV.

.Net C# DocX librairy : how to serialize a DocX document?

When using the DocX librairy, i am generating the docx document on server then download it.
For that, i need to convert my document in an array of bytes.
To do that, i was previousloy saving the document as a physical file like this :
// Save all changes to this document.
document.SaveAs(GENERATED_DOCX_LOCATION);
return System.IO.File.ReadAllBytes(GENERATED_DOCX_LOCATION);
but i would rather not do that. Is it possible to serialize this object to download it without saving it physically ?
I already tried that :
private byte[] ObjectToByteArray(object obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
With :
return this.ObjectToByteArray(document);
But obviously, DocX doesn't implement ISerializable.
EDIT : the code below doesn't work either
byte[] byteArray = null;
using (var stream = new MemoryStream())
{
document.SaveAs(stream);
byteArray = stream.ToArray();
}
return byteArray;
Try this, replace my c:\temp... path with your document location and this will get and write the file for you from the byte array
void Main()
{
byte[] bytes = System.IO.File.ReadAllBytes(#"C:\temp\test.csv");
using (var bw = new BinaryWriter(File.Open(#"C:\temp\test2.csv", FileMode.OpenOrCreate)))
{
bw.Write(bytes);
bw.Flush();
}
}
There was no way to do it via the original DocX library.
It's a shame as this library uses a MemoryStream to manupulate the datas.
To solve my problem i simply added a new public readonly property to expose the private MemoryStream variable, then i used this simple code :
Code added in the DocX project :
public MemoryStream DocumentMemoryStream { get { return this.memoryStream; } }
Code in my main function :
return document.DocumentMemoryStream.ToArray();

c# Microsoft.Office.Interop.Word.Document to Stream

I have a active document :
Microsoft.Office.Interop.Word.Document document = Globals.ThisAddIn.Application.ActiveDocument;
How I can convert this to stream?
Or even better, how to send active document to rest web service?
Thanks
Which rest-service? If it's SharePoint or the like i'm used to just calling the SaveAs function as follows:
Microsoft.Office.Interop.Word.Document document = Globals.ThisAddIn.Application.ActiveDocument;
document.SaveAs("https://www.contoso.sharepoint.com/Documents/Document1.docx");
Edit: P.S. You can serialize anything to Stream.
found an answer here
public static MemoryStream SerializeToStream(object o)
{
MemoryStream stream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, o);
return stream;
}
public static object DeserializeFromStream(MemoryStream stream)
{
IFormatter formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
object o = formatter.Deserialize(stream);
return o;
}
Save to a temp file then read file content as required by the rest service, e.g. byte array. Or use Open XML SDK if older Word formats are not required.

string serialization and deserialization problem

I'm trying to serialize/deserialize string. Using the code:
private byte[] StrToBytes(string str)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, str);
ms.Seek(0, 0);
return ms.ToArray();
}
private string BytesToStr(byte[] bytes)
{
BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
return Convert.ToString(bfx.Deserialize(msx));
}
This two code works fine if I play with string variables.
But If I deserialize a string and save it to a file, after reading the back and serializing it again, I end up with only first portion of the string.
So I believe I have a problem with my file save/read operation. Here is the code for my save/read
private byte[] ReadWhole(string fileName)
{
try
{
using (BinaryReader br = new BinaryReader(new FileStream(fileName, FileMode.Open)))
{
return br.ReadBytes((int)br.BaseStream.Length);
}
}
catch (Exception)
{
return null;
}
}
private void WriteWhole(byte[] wrt,string fileName,bool append)
{
FileMode fm = FileMode.OpenOrCreate;
if (append)
fm = FileMode.Append;
using (BinaryWriter bw = new BinaryWriter(new FileStream(fileName, fm)))
{
bw.Write(wrt);
}
return;
}
Any help will be appreciated.
Many thanks
Sample Problematic Run:
WriteWhole(StrToBytes("First portion of text"),"filename",true);
WriteWhole(StrToBytes("Second portion of text"),"filename",true);
byte[] readBytes = ReadWhole("filename");
string deserializedStr = BytesToStr(readBytes); // here deserializeddStr becomes "First portion of text"
Just use
Encoding.UTF8.GetBytes(string s)
Encoding.UTF8.GetString(byte[] b)
and don't forget to add System.Text in your using statements
BTW, why do you need to serialize a string and save it that way?
You can just use File.WriteAllText() or File.WriteAllBytes. The same way you can read it back, File.ReadAllBytes() and File.ReadAllText()
The problem is that you are writing two strings to the file, but only reading one back.
If you want to read back multiple strings, then you must deserialize multiple strings. If there are always two strings, then you can just deserialize two strings. If you want to store any number of strings, then you must first store how many strings there are, so that you can control the deserialization process.
If you are trying to hide data (as indicated by your comment to another answer), then this is not a reliable way to accomplish that goal. On the other hand, if you are storing data an a user's hard-drive, and the user is running your program on their local machine, then there is no way to hide the data from them, so this is as good as anything else.

Categories