I want to read all XML files in a directory, deserialize them into class objects, and finally return all the objects in a list.
I'm using .NET.
public List<EngineProfile> ReadAllEngineProfiles()
{
List<EngineProfile> result = new();
DirectoryInfo directoryInfo = new(pathToDirectory);
var serializer = new XmlSerializer(typeof(EngineProfile));
foreach (var file in directoryInfo.GetFiles("*.xml"))
{
//TODO: DeSerialize the file
EngineProfile engine = new EngineProfile();
engine.EngineName = file.Name; //just to test
//attempt to Deserialize the file (ERROR)
engine = serializer.Deserialize(file)
result.Add(engine);
}
return result;
}
The above method can read all the XML files but when I try to Deserialize the files, it gives me an error as it expects a Stream object.
The error says: "..cannot convert from 'System.IO.FileInfo' to 'System.IO.Stream'.
How can I deserialize? Is there any other way to read all files and deserialize them?
Please help.
Related
I am trying to read json file from cloud storage and trying to convert that into Google.Cloud.DocumentAI.V1.Document.
I have done POC, but its throwing exception Google.Protobuf.InvalidProtocolBufferException: 'Protocol message end-group tag did not match expected tag.'
First I am reading .Json file into MemoryStream and trying to Merge in to Document.
using Google.Cloud.DocumentAI.V1;
public static void StreamToDocument()
{
byte[] fileContents = File.ReadAllBytes("C:\\upload\\temp.json");
using (Stream memoryStream = new MemoryStream(fileContents))
{
Document doc = new Document();
var byteArray = memoryStream;
doc.MergeFrom(byteArray);
}
}
Error Message I am getting is
Is there any other way I can achieve this ?
The code that you've specified there expects the data to be binary protobuf content. For JSON, you want:
string json = File.ReadAllText("C:\\upload\\temp.json");
Document document = Document.Parser.ParseJson(json);
I´m coding in C# and I have a project that the user will
be able to upload a .zip file and in that file will a .xml be read
and chapters based on xml tags will de displayed dynamic.
Right now it is hardcoded a specific file and in that file
that specific .xml file.
How do I read .xml file from a zip file and display that dynamic in C#?
Microsoft documentation has an exemple on this. Extracting specific file from a zip Archive and unzip them in a directory:
https://learn.microsoft.com/en-us/dotnet/standard/io/how-to-compress-and-extract-files#example-2-extract-specific-file-extensions.
Then you next step will be to process the all or some file from the directory, https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.getfiles?view=netframework-4.7.2#System_IO_Directory_GetFiles_System_String_System_String_
If you don't want to unzip, you can directly open the ZipArchiveEntry, with : https://learn.microsoft.com/en-us/dotnet/api/system.io.compression.ziparchiveentry.open?view=netframework-4.7.2
With multiple Xml files in the zip all serialisation of myTypethe codes should boil down to :
string zipPath = #".\result.zip";
List<myType> listResults ;
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
XmlSerializer serializer = new XmlSerializer(typeof(myType);
listResults =
archive
.Entries
.Where(entry => entry.FullName
.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
.Select(entry => (myType)serializer.Deserialize(entry.Open()))
.ToList();
}
For any missing reference in your project follow the light bulb 💡!
Add the System.IO.Compression.FileSystem assembly to your project references. Once you did that, you can open an archive like this:
static void Main(string[] args)
{
var zipPath = "Path-To-Your-Zipfile";
using (var archive = ZipFile.OpenRead(zipPath))
{
var xmlFile = archive.Entries.FirstOrDefault(e => e.FullName.EndsWith(".xml"));
if(xmlFile == null)
return;
using (var stream = xmlFile.Open())
{
using (var reader = new StreamReader(stream))
{
var fileContents = reader.ReadToEnd();
}
}
}
}
I am developing a tool to reads a XMl(input) which contains paths to some folders and files and generate a XML(output) based on the information of all files mentioned in the path. I tried the a code which reads the input xml file where i have give path to a certain folder within a certain tag. The tool works perfectly if i have mentioned only one path in the input xml. But on adding another path the previous the previous contents written to the XML(output) generated are overwritten.I have given the code below for the button event which generates the output XML on click and method that writes details to the XML. I an not sure how to append or where to append in the method that i write details to xml. Please help me out.
public bool GenerateReportFile(InputFile inputFile, string xmlfile)\\button clicked to perform operation
{
//try
//{
//
foreach (var folder in inputFile.FolderList)
{
List<string> foldersList = GetSubFolders(folder);
foldersList.Add(folder);
UpdateFileInfomation(foldersList);
SetVariable(folder);
Serialize(xmlfile, typeof(DeploymentInfo), filesInformation);
}
private static void Serialize(string xmlFilePath, Type type, object obj)\\method that writes contents to xml
{
if (obj == null)
return;
if (!Directory.Exists(Path.GetDirectoryName(xmlFilePath)))
Directory.CreateDirectory(Path.GetDirectoryName(xmlFilePath));
try
{
XmlSerializer serializer = new XmlSerializer(type);
TextWriter textWriter = new StreamWriter(xmlFilePath);\\this line creates a new XML file every time. this is where i need to handle things to avoid overwriting for every path mentioned in my input xml but i am unable to
serializer.Serialize(textWriter, obj);
textWriter.Close();
}
catch (Exception ex)
{
throw ex;
}
}
If your intention is to serialize objects of the same type at a single location you can add them to a list and serialize it instead.
Here is a tutorial:
http://www.dotnetperls.com/serialize-list
Edit:
This only works for Binary Serialization, not XML
You would need to rework your functions a bit:
Your GenerateReportFile should generate the list of objects and pass it to your Serialize
I am trying to serialize my Report class info to an XML. At this point I think all of the serialize and deserialize code works, but for the initial write, I'm having trouble performing the serialize, because the XML file doesn't exist yet.
for an empty text file, i can use:
StreamWriter sw = File.CreateText(#"path");
sw.Close();
this is my code block for the serializing. the exception (Directory not found) is getting thrown on the StreamWriter line. I'd like to simply add an if(!File.Exists(xmlPath))...create empty XML. Or maybe there is a more correct way to do this.
public void SerializeToXML(Report newReport)
{
XmlSerializer serializer = new XmlSerializer(typeof(Report));
TextWriter textWriter = new StreamWriter(xmlPath);
serializer.Serialize(textWriter, newReport);
textWriter.Close();
}
The StreamWriter(String) constructor will create the file if it does not already exist:
If the file exists, it is overwritten; otherwise, a new file is created.
However, it will not create any inexistent directories in your path.
DirectoryNotFoundException: The specified path is invalid, such as being on an unmapped drive.
To create any required directories, you can include the following code (at the beginning of your SerializeToXML method):
var dir = Path.GetDirectoryName(xmlPath);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
First to make sure the directory exist you can use:
Directory.CreateDirectory(#"c:\directory\subdirectory");
You don't have to check if directory already exist.
A easy way to convert public classes to XML is to use the following snippet:
public static string ToXml<T>(T obj)
{
using (var ms = new MemoryStream())
using (var sr = new StreamReader(ms))
{
var xmlSer = new XmlSerializer(typeof(T));
xmlSer.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin);
return sr.ReadToEnd();
}
}
Then you could just use the following code to write it to a file:
var xmlString = Util.ToXml(report);
File.WriteAllText(#"path", xmlString);
(this example is without error handling)
Also, in your code you forgot to close/dispose the TextWriter. I would recommend using the using-statement to handle it for you.
CreateText, and the StreamWriter, will create files if they don't exist, but they won't create directories that don't already exist for you. Is your path correct?
Try Checking with a Directory.Exists(Path.GetDirectoryName(xmlPath)).
Read sequentially through the XML files (e.g. C:\Application\XML) and get the xml for all the files.
You can read XML files as shown below:
List<string> files = Directory.GetFiles("c:\\MyDir", "*.xml").ToList();
foreach(string fileLocation in files)
{
XmlDocument obj = new XmlDocument();
obj.Load(filelocation);
//Your code to place the xml in a queue.
}
What you need to do is implement a producer-consumer model. Have a look here: http://www.albahari.com/threading/part4.aspx and scroll down to the "Producer/Consumer Queue" part.
For some classic C# XML API read here: http://msdn.microsoft.com/en-us/magazine/cc302158.aspx
foreach (var file in Directory.EnumerateFiles(path, "*.xml"))
{
var xdoc = XDocument.Load(file);
...
}