I'm trying to make a config file from an XML file, but I can't figure out how to save the file after I add to it. I can read from the file fine, so I know it's not an issue with where it's located, but I still don't know how to save it.
I've looked around for about 2 hours and can't figure out the problem. I'm know my way around c# but am completely new to XML.
public async Task CreateReaction(string name, DiscordMessage message, DiscordEmoji emoji, DiscordRole role)
{
string path = #"E:\Visual Studio\repos\JustHangoutBot\bin\Debug\netcoreapp1.1\configs\reactions.xml";
XDocument doc = XDocument.Load(path);
await message.CreateReactionAsync(emoji);
XElement root = new XElement(name);
root.Add(new XElement("MessageID", message.Id));
root.Add(new XElement("ReactionID", emoji.Id));
root.Add(new XElement("RoleID", role.Id));
doc.Element("Reactions").Add(root);
byte[] byteArray = Encoding.UTF8.GetBytes(path);
MemoryStream stream = new MemoryStream(byteArray);
doc.Save(stream);
}
I think the problem is somewhere in the last three lines. I've seen tutorials of people saving the file by just using doc.Save("reactions.xml") for example, but I get the error of not being able to convert from string to Stream.
Any help would be appreciated. Thank you in advance!
This will do it:
using (var fileStream = System.IO.File.OpenWrite("path to the file you want to write"))
{
doc.Save(fileStream);
}
When you do this:
byte[] byteArray = Encoding.UTF8.GetBytes(path);
MemoryStream stream = new MemoryStream(byteArray);
doc.Save(stream);
What's happening is
You're opening the file at path and reading it into a byte array.
You're creating a MemoryStream that has those bytes as its content
You're saving that document to the MemoryStream.
Under the hood a MemoryStream is just an array of bytes in memory. So it's writing the file to memory, not to a file.
File.OpenWrite(path) opens a FileStream with the specified path. If the file doesn't exist it creates it. If the file does exist it will overwrite it.
So when you call doc.Save(fileStream) you're writing to the file.
Related
I have a very interesting problem that I hope I can solve using .Net, simply I have a zip file in google storage which I want to decompress and move to a different bucket, but I don't have enough memory nor storage to save the whole file and decompress. To solve this issue I have to read the central directory part of the zip file at the end of the file and then do streaming decompress. Did anyone work on a similar issue?
So far I figured to get the last 1024 bytes from the file using the following code:
var fileInfo = _storage.GetObject(BucketName, fileName, new GetObjectOptions { Projection = Projection.Full });
var stream = new MemoryStream();
_storage.DownloadObject(BucketName, fileName, stream, new DownloadObjectOptions { Range = new System.Net.Http.Headers.RangeHeaderValue((long)(fileInfo.Size - 1024), (long)(fileInfo.Size)) });
The problem is I can't read the central directory from this stream:
ZipArchive z = new ZipArchive(stream);
You can try to adapt sunzip to your needs. It reads a zip file as a stream and decompresses it.
I am creating an XML file on the fly.
One of it's nodes contains a ZIP file encoded as a BASE64 string.
I then create another ZIP file.
I add this XML file and a few other JPEG files.
I output the file to the browser.
I am unable to open the FINAL ZIP file.
I get: "Windows cannot open the folder. The Compressed(zipped) Folder'c:\path\file.zip' is invalid."
I am able to save my original XML file to the file system.
I can open that XML file, decode the ZIP node and save to the file system.
I am then able to open that Zip file with no problems.
I can create the final ZIP file, OMIT my XML file, and the ZIP file opens no problem.
I seem to only have an issue with I attempt to ZIP an XML file that has a node with ZIP content encoded as a BASE64 string.
Any ideas? Code snipets are below. Heavily edited.
XDocument xDoc = new XDocument();
XDocument xDocReport = new XDocument();
XElement xNodeReport;
using (FileStream fsData = new FileStream(strFullFilePath, FileMode.Open, FileAccess.Read)) {
xDoc = XDocument.Load(fsData);
xNodeReport = xDoc.Element("Data").Element("Reports").Element("Report");
//SNIP
//create XDocument xDocReport
//SNIO
using (MemoryStream zipInMemoryReport = new MemoryStream()) {
using (ZipArchive zipFile = new ZipArchive(zipInMemoryReport, ZipArchiveMode.Update)) {
//Add REPORT to ZIP file
ZipArchiveEntry entryReport = zipFile.CreateEntry("data.xml");
using (StreamWriter writer = new StreamWriter(entryReport.Open())) {
writer.Write(xDocReport.ToString());
} //END USING report entry
}
xNodeReport.Value = System.Convert.ToBase64String(zipInMemoryReport.GetBuffer());
//I am able to write this file to disk and manipulate it no problem.
//File.WriteAllText("c:\\users\\snip\\desktop\\Report.xml",xDoc.ToString());
}
//create ZIP for response
using (MemoryStream zipInMemory = new MemoryStream()) {
using (ZipArchive zipFile = new ZipArchive(zipInMemory, ZipArchiveMode.Update)) {
//Add REPORT to ZIP file
ZipArchiveEntry entryReportWrapper = zipFile.CreateEntry("Report.xml");
//THIS IS THE STEP THAT makes the Zip "invalid". Although i can open and manipulate this source file no problem.
//********
using (StreamWriter writer = new StreamWriter(entryReportWrapper.Open())) {
xDoc.Save(writer);
}
//Add JPEG(s) to report
//Create Charts
if (chkDLSalesPrice.Checked) {chartDownloadSP.SaveImage(entryChartSP.Open(), ChartImageFormat.Jpeg);}
if (chkDLSalesDOM.Checked) {chartDownloadDOM.SaveImage(entryChartDOM.Open(), ChartImageFormat.Jpeg);}
if (chkDLSPLP.Checked) {chartDownloadSPLP.SaveImage(entryChartSPLP.Open(), ChartImageFormat.Jpeg);}
if (chkDLSPLP.Checked) {chartDownloadLP.SaveImage(entryChartLP.Open(), ChartImageFormat.Jpeg);}
} // END USING ziparchive
Response.Clear();
Response.AppendHeader("content-disposition", "attachment; filename=file.zip");
Response.ContentType = "application/zip";
Response.BinaryWrite(zipInMemory.GetBuffer());
Response.End();
Without a good, minimal, complete code example, it's impossible to know for sure what bugs are in the code. But there are at least two apparent errors in the code snippet you posted, one of which could easily be responsible for the "invalid .zip" error:
In the statement writer.Write(xDocReport.ToString());, the variable xDocReport has not been initialized to anything useful, at least not in the code you posted. So you'll get an empty XML document in the archive.
Since the code example is incomplete, it's possible you just omitted from the code example in your question the initialization of that variable to something else. In any case, even if you didn't that would just lead to an empty XML document in the archive, not an invalid archive.
More problematic though…
You are calling GetBuffer() on your MemoryStream objects, instead of ToArray(). You want the latter. The former gets the entire backing buffer for the MemoryStream object, including the uninitialized bytes past the end of the valid stream. Since a valid .zip file includes a CRC value at the end of the file, adding extra data beyond that causes anything trying to read the file as a .zip archive to miss the correct CRC, reading the uninitialized data instead.
Replace your calls to GetBuffer() with calls to ToArray() instead.
If the above does not lead to a solution for your problem, you should edit your post, to provide a better code example.
One last comment: there is no point in initializing a variable like xDoc to an empty XDocument object when you're going to just replace that object with a different one (e.g. by calling XDocument.Load()).
This is what i would like to do:
Get a 64base byte array from database (which is actually in pdf format). This works.
Then i would like to show the pdf in a webbrowser component.
I first started with saving the pdf to a file.pdf and then open it:
byte[] bitjes = isc.GetFileById(fileid); // Getting the bytes
FileStream stream = new FileStream(#"C:\NexusPDF\" + filename, FileMode.CreateNew);
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(bitjes, 0, bitjes.Length);
writer.Close();
webBrowser.Navigate(#"C:\NexusPDF\" + filename);
But that gave me all sorts of problems involving read/write acces. So i figured i have to use the memorystream class to solve this problem.
byte[] bitjes = isc.GetFileById(fileid);
MemoryStream memstream = new MemoryStream(bitjes);
BinaryWriter writer = new BinaryWriter(memstream);
writer.Write(bitjes, 0, bitjes.Length);
writer.Close();
But here's where i'm stuck! I can't just show this in a webBrowser component can i?
Do i have to use the binaryreader before i can show the pdf?
Am i approaching this problem the right way, or are there better alternatives?
Main thing is that i don't want to save the file on disk.
Any help will be appreciated.
You may be able to use the data URL scheme. This URL scheme specifies the content inline.
webBrowser.Navigate("data:application/pdf;base64," + X);
Where X is the base 64 string.
No need to convert the base 64 PDF string into a byte array!
See http://www.ietf.org/rfc/rfc2397.txt for more details.
I'm needing to create a zipped document containing files that exist on the server. I am using the Ionic.Zip to do so, and to create a new Package (which is the zip file) I have to have either a path to a physical file or a stream. I am trying to not create an actual file that would be the zip file, instead just create a stream that would exist in memory or something. how can i do this?
Create the package using a MemoryStream then.
You can try the save method in the ZipFile Class. It can save to a stream
try this.
using (MemoryStream ms = new MemoryStream())
{
using (Ionic.Zip.ZipFile zipFile = new Ionic.Zip.ZipFile())
{
zipFile.AddFiles(filesToBeZipped, false, "NewFolder");//filesTobeZipped is a List<string>
zipFile.Save(ms);
}
}
You'll want to use the .AddEntry method on the ZipFile you've created specifying a name and the byte[] containing the actual file data.
ex.
ZipFile zipFile = new ZipFile();
zipFile.AddEntry(file.FileName, file.FileData);
where file.FileName will be the entry name (in the zip file) and file.FileData is the byte array.
here is my code
// Read the data from the file
XmlSerializer serializer = new XmlSerializer(typeof(HighScoreData));
data = (HighScoreData)serializer.Deserialize(stream);
im currently doing a saving highscore for my game. but it get an error of "there is an error in xml document (0, 0).
care to help or enlighten?
i have had this problem before and a byte order mark was present at the beginning of the file. Check your XML file in a hex editor and see if there are three characters at the beginning. You could simply do something like the following with your raw xml
if (xml.StartsWith(ByteOrderMarkUtf8))
{
xml = xml.Remove(0, ByteOrderMarkUtf8.Length);
}
then read that into the stream
or you could do something like this when creating your stream
byte[] bytes = Encoding.UTF8.GetBytes(xml);
MemoryStream stream = new MemoryStream(bytes);
hopefully that helps