Stream into package, package into WordDocument and then back again - c#

I do not understand all the mechanics surrounding Streams and even less around the System.IO.Package class.
I have a .docx document as a binary in a DataBase and I wan't to fetch it, modify somewhat and then save it.
I currently have the method that modifies the document in a seperate library because it will be used in many places.
This is how I tried to do this:
byte[] doc = getDocFromDB();
using (MemoryStream mem = new MemoryStream())
{
mem.Write(doc, 0, doc.Length);
Package pack = Package.Open(mem, FileMode.Open, FileAccess.ReadWrite);
filler.FillTemplate(ref pack, someIrreleventData);
string filePath = Path.GetTempPath() + "docname.docx";
using (FileStream file = new FileStream(filePath, FileMode.Create))
{
mem.WriteTo(file);
file.Flush();
file.Close();
}
Process.Start(filePath);
}
With the library code going something like this:
public void FillTemplate(ref Package package, XElement data)
{
WordprocessingDocument document = WordprocessingDocument.Open(package);
//add the data to the document
//should I do document.close() or document.dispose() here?
}
The document just comes out just as it was saved into the DB without all the extra data added in.
I assumed as I opened the Package with a memory stream all the changes to the package would be saved into the stream as well.
What am I doing wrong and how can I do it better.
EDIT
I was wrong, there isn't anything broken with my code. Problem was that someIrreleventData part was null and both the fetcher there and the code inside FillTemplate method didn't handle the exception correctly.

I don't see any place where you call Flush() and/or Close() on the Package before trying to save it to file...
try changing
mem.Write(doc, 0, doc.Length);
mem.Position = 0; // new, perhaps this is relevant for Package.Open ?
Package pack = Package.Open(mem, FileMode.Open, FileAccess.ReadWrite);
filler.FillTemplate(ref pack, someIrreleventData);
pack.Flush(); pack.Close(); // new
mem.Position = 0; // new
AND: yes, you should call document.Close() .
Calling .Dispose() is a good idea though it would even be better if you used as using block which takes care of that and several other things...

Related

How can I write a Integer to a FileStream in C#?

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);
}

Placing a string in memory and saving it later

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);
}
}

Is it possible to write a packaging.package to a stream without having to save it to a file first?

I have a System.IO.Packaging.Package in memory (it is a WordprocessingDocument) and want to stream it down to browser to save it. The word document has been modified by the MVC-based application and the resulting file has been modified for the current request.
I understand the package represents a 'zip' file containing a number of parts. These parts include headers, footers and main body document. I've modified each individually and now want to stream the package back to the user.
I can get the individual part streams... package.GetPart(new Uri("/word/document.xml", UriKind.Relative)).GetStream()
However I'm missing how to get an output stream on the entire document (package)- without writing to the file system.
Thanks in advance
No- what I think I need is something like this... I've already read in the template document and made modifications in memory. Now I want to stream a modified document (leaving the template un-touched) back to the user.
MemoryStream stream = new MemoryStream();
WordprocessingDocument docOut =
WordprocessingDocument.Create( stream, WordprocessingDocumentType.Document);
foreach (var part in package.GetParts())
{
using (StreamReader streamReader = new StreamReader(part.GetStream()))
{
PackagePart newPart = docOut.Package.CreatePart(
part.Uri, part.ContentType );
using (StreamWriter streamWriter = new StreamWriter(newPart.GetStream(FileMode.Create)))
{
streamWriter.Write(streamReader.ReadToEnd());
}
}
}
Unfortunately- this produces a 'corrupt' word document...
OpenXmlPackage.Close Method saves all changes in all parts to the underlying store. If you opened the package from a stream, just use that stream:
public Stream packageStream() {
var ms = new MemoryStream();
var wrdPk = WordprocessingDocument.Create(ms, WordprocessingDocumentType.Document);
// Build the package ...
var docPart = wrdPk.AddMainDocumentPart();
docPart.Document = new Document(
new Body(new Paragraph(new Run(new Text("Hello world.")))));
// Flush all changes
wrdPk.Close();
return ms;
}

Create a temporary file from stream object in c#

Given a stream object which contains an xlsx file, I want to save it as a temporary file and delete it when not using the file anymore.
I thought of creating a class that implementing IDisposable and using it with the using code block in order to delete the temp file at the end.
Any idea of how to save the stream to a temp file and delete it on the end of use?
Thanks
You could use the TempFileCollection class:
using (var tempFiles = new TempFileCollection())
{
string file = tempFiles.AddExtension("xlsx");
// do something with the file here
}
What's nice about this is that even if an exception is thrown the temporary file is guaranteed to be removed thanks to the using block. By default this will generate the file into the temporary folder configured on the system but you could also specify a custom folder when invoking the TempFileCollection constructor.
You can get a temporary file name with Path.GetTempFileName(), create a FileStream to write to it and use Stream.CopyTo to copy all data from your input stream into the text file:
var stream = /* your stream */
var fileName = Path.GetTempFileName();
try
{
using (FileStream fs = File.OpenWrite(fileName))
{
stream.CopyTo(fs);
}
// Do whatever you want with the file here
}
finally
{
File.Delete(fileName);
}
Another approach here would be:
string fileName = "file.xslx";
int bufferSize = 4096;
var fileStream = System.IO.File.Create(fileName, bufferSize, System.IO.FileOptions.DeleteOnClose)
// now use that fileStream to save the xslx stream
This way the file will get removed after closing.
Edit:
If you don't need the stream to live too long (eg: only a single write operation or a single loop to write...), you can, as suggested, wrap this stream into a using block. With that you won't have to dispose it manually.
Code would be like:
string fileName = "file.xslx";
int bufferSize = 4096;
using(var fileStream = System.IO.File.Create(fileName, bufferSize, System.IO.FileOptions.DeleteOnClose))
{
// now use that fileStream to save the xslx stream
}
// Get a random temporary file name w/ path:
string tempFile = Path.GetTempFileName();
// Open a FileStream to write to the file:
using (Stream fileStream = File.OpenWrite(tempFile)) { ... }
// Delete the file when you're done:
File.Delete(tempFile);
EDIT:
Sorry, maybe it's just me, but I could have sworn that when you initially posted the question you didn't have all that detail about a class implementing IDisposable, etc... anyways, I'm not really sure what you're asking in your (edited?) question. But this question: Any idea of how to save the stream to temp file and delete it on the end of use? is pretty straight-forward. Any number of google results will come back for ".NET C# Stream to File" or such.
I just suggest for creating file use Path.GetTempFileName(). but others depends on your usage senario, for example if you want to create it in your temp creator class and use it just there, it's good to use using keyword.

iTextSharp + FileStream = Corrupt PDF file

I am trying to create a pdf file with iTextSharp. My attempt writes the content of the pdf to a MemoryStream so I can write the result both into file and a database BLOB. The file gets created, has a size of about 21kB and it looks like a pdf when opend with Notepad++. But my PDF viewer says it's currupted.
Here is a little code snippet (only tries to write to a file, not to a database):
Document myDocument = new Document();
MemoryStream myMemoryStream = new MemoryStream();
PdfWriter myPDFWriter = PdfWriter.GetInstance(myDocument, myMemoryStream);
myDocument.Open();
// Content of the pdf gets inserted here
using (FileStream fs = File.Create("D:\\...\\aTestFile.pdf"))
{
myMemoryStream.WriteTo(fs);
}
myMemoryStream.Close();
Where is the mistake I make?
Thank you,
Norbert
I think your problem was that you weren't properly adding content to your PDF. This is done through the Document.Add() method and you finish up by calling Document.Close().
When you call Document.Close() however, your MemoryStream also closes so you won't be able to write it to your FileStream as you have. You can get around this by storing the content of your MemoryStream to a byte array.
The following code snippet works for me:
using (MemoryStream myMemoryStream = new MemoryStream()) {
Document myDocument = new Document();
PdfWriter myPDFWriter = PdfWriter.GetInstance(myDocument, myMemoryStream);
myDocument.Open();
// Add to content to your PDF here...
myDocument.Add(new Paragraph("I hope this works for you."));
// We're done adding stuff to our PDF.
myDocument.Close();
byte[] content = myMemoryStream.ToArray();
// Write out PDF from memory stream.
using (FileStream fs = File.Create("aTestFile.pdf")) {
fs.Write(content, 0, (int)content.Length);
}
}
I had similar issue. My file gets downloaded but the file size will be 13Bytes. I resolved the issue when I used binary writer to write my file
byte[] bytes = new byte[0];
//pass in your API response into the bytes initialized
using (StreamWriter streamWriter = new StreamWriter(FilePath, true))
{
BinaryWriter binaryWriter = new BinaryWriter(streamWriter.BaseStream);
binaryWriter.Write(bytes);
}
Just some thoughts - what happens if you replace the memory stream with a file stream? Does this give you the result you need? This will at least tell you where the problem could be.
If this does work, how do the files differ (in size and binary representation)?
Just a guess, but have you tried seeking to the beginning of the memory stream before writing?
myMemoryStream.Seek(0, SeekOrigin.Begin);
Try double checking your code that manipulates the PDF with iText. Make sure you're calling the appropriate EndText method of any PdfContentByte objects, and make sure you call myDocument.Close() before writing the file to disk. Those are things I've had problems with in the past when generating PDFs with iTextSharp.
documentobject.Close();
using (FileStream fs = System.IO.File.Create(path)){
Memorystreamobject.WriteTo(fs);
}

Categories