I'm stumped on why I can't validate the XML file to a schema and then deserialize the xml into an class.
I can do either or. i.e. if I comment out the ValidateXML then the ConvertToObject works and vice versa. If leave both in that I get an error : "There is an error in XML document (0, 0)" (Usually when I get this error I usually have left the document open prior to deserializing it.
My main logic
foreach (var myFile in Directory.EnumerateFiles(#"C:MyFolder", "*.xml"))
{
try
{
using (var fileStream = new FileStream(myFile, FileMode.Open, FileAccess.Read))
{
if (ValidateXML(fileStream))
{
CreateObjects(fileStream);
goodCounter++;
}
else
{
sb.AppendLine("Validation failed for: " + myFile);
badCounter++;
}
}
}
catch
{
sb.AppendLine(myFile);
}
}
My validate method:
private bool ValidateXML(Stream stream)
{
try
{
XmlDocument xDoc = new XmlDocument();
xDoc.Load(stream);
xDoc.Schemas.Add(null, #"C:My_XSD.xsd");
ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);
xDoc.Validate(eventHandler);
return true;
}
catch
{
return false;
}
}
static void ValidationEventHandler(object sender, ValidationEventArgs e)
{
switch (e.Severity)
{
case XmlSeverityType.Error:
//Console.WriteLine("Error: {0}", e.Message);
throw new Exception(e.Message);
//break;
case XmlSeverityType.Warning:
//Console.WriteLine("Warning {0}", e.Message);
throw new Exception(e.Message);
//break;
}
}
Kevin was right...
fileStream.Seek(0, SeekOrigin.Begin);
Related
Context
I've written a class to handle settings for my ASP.NET MVC app. However after testing how it handles a malformed/ missing XML file the exception it seems to throw is uncatchable and it repeats endlessly without catching or moving on with execution.
I've disabled the V.S. Debug Dialog popup in the past but again it seems repeat the same segment of code. I do not have a loop anywhere else that calls this property and there is default behavior if the property doesn't return a valid value.
Breakpoints beyond the failing function are not reached, however the breakpoint on or before the XML exception are repeatedly reached...
P.S. there is a lot of failed testing code left over to get a workaround working.
Screenshot:
Screenshot:
EDIT: I must clarify I have tried alternate XML parsing tools, any XMLException here is not caught.
Code ['Setting container' Property]:
private static Settings _singletonSettings;
public static Settings SettingsContainer
{
get
{
if (_singletonSettings == null)
{
_singletonSettings = new Settings();
_singletonSettings .LoadSettings();
}
return _singletonSettings;
}
private set
{
_singletonSettings = value;
}
}
Code ['LoadSettings function']:
public void LoadSettings()
{
string filePath = "Config/Settings.txt";
if (!Directory.Exists(Path.GetDirectoryName(filePath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
}
if (File.Exists(filePath))
{
try
{
SettingsContainer = LoadViaDataContractSerialization<Settings>(filePath); // Desperately trying to catch the exception.
}
catch (Exception ex)
{
Log.GlobalLog.WriteError("LoadViaDataContractSerialization() error:\n" + ex.Message + "\nStackTrace: \n" + ex.StackTrace);
}
}
else
{
File.Create(filePath);
}
if (SettingsContainer == null)
{
SettingsContainer = new Settings();
}
}
Code ['LoadViaDataContractSerialization']:
public static T LoadViaDataContractSerialization<T>(string filepath)
{
try
{
T serializableObject;
using (var fileStream = new FileStream(filepath, FileMode.Open))
{
try
{
using (var reader = XmlDictionaryReader.CreateTextReader(fileStream, new XmlDictionaryReaderQuotas())) //All execution stops here with the
{
var serializer = new DataContractSerializer(typeof(T));
serializableObject = (T)serializer.ReadObject(reader, true);
reader.Close();
}
}
catch (XmlException ex)
{
Log.GlobalLog.WriteError("LoadViaDataContractSerialization() XML Fail: Message: " + ex.Message + "\n StackTrace: " + ex.StackTrace);
return default(T);
}
fileStream.Close();
}
return serializableObject;
}
catch (Exception ex)
{
Log.GlobalLog.WriteError("LoadViaDataContractSerialization() Fail: Message: " + ex.Message + "\n StackTrace: " + ex.StackTrace);
return default(T);
}
}
Looks like the issue lay with a lack of understanding in 'return default(T)'.
I'm not sure why it was repeating but by removing the try catch blocks that returned 'default(T)' and responding to the exception 'return new settings()' it allowed the properties value to not be null and function as intended.
Code LoadViaDataContractSerialization:
public static T LoadViaDataContractSerialization<T>(string filepath)
{
T serializableObject;
using (var fileStream = new FileStream(filepath, FileMode.Open))
{
using (var reader = XmlDictionaryReader.CreateTextReader(fileStream, new XmlDictionaryReaderQuotas()))
{
var serializer = new DataContractSerializer(typeof(T));
serializableObject = (T)serializer.ReadObject(reader, true);
reader.Close();
}
fileStream.Close();
}
return serializableObject;
}
Code LoadSettings:
public void LoadSettings()
{
string filePath = "Config/Settings.txt";
if (!Directory.Exists(Path.GetDirectoryName(filePath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
}
if (File.Exists(filePath))
{
try
{
SettingsContainer = LoadViaDataContractSerialization<Settings>(filePath);
}
catch (Exception ex) //only exception needed
{
Log.GlobalLog.WriteError("LoadViaDataContractSerialization() error:\n" + ex.Message + "\nStackTrace: \n" + ex.StackTrace);
SettingsContainer = new Settings();//<---this was the fix
}
}
else
{
File.Create(filePath);
}
if(SettingsContainer == null)
{
SettingsContainer = new Settings();
}
}
Thank you to 'Generic Snake' for pointing me at the right place.
I have a append-only log file which is monitored by a FileSystemWatcher. When the file is changed, Read() is called for the LogFile object.
The log file should be read line by line.
The goal is to read only changes i.e. lines add to the log file (skip already readed lines).
Thus the StreamReader should start to read from the position where it ended on the previous read.
My solution so far doesn't work. When I add
1
2
3
4
line by line in Notepad++ to my textfile & save each time when a line was added, the Debug output is
Initial read
1 //OK
2 //OK
3 //OK
1 //looks like the log file is read again from the beginning
2
3
4
Output should be
Initial read
1
2
3
4
Any ideas to solve this problem?
Console code
public class LogFile
{
public List<string> Contents { get; }
string _fullPath;
long position;
public LogFile(string fullPath)
{
if (File.Exists(fullPath))
{
_fullPath = fullPath;
Contents = new List<string>();
Read();
}
else
{
throw new FileNotFoundException($"{fullPath} not found");
}
}
public void Read(FileSystemWatcher fsw = null)
{
if (fsw != null)
fsw.EnableRaisingEvents = false; //set to false to prevent Changed event be fired twice
FileStream fs = null;
StreamReader sr = null;
try
{
fs = new FileStream(_fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
try
{
sr = new StreamReader(fs, Encoding.UTF8);
if (Contents.Count == 0)
{
Debug.WriteLine($"Initial read");
AddToContents(_fullPath, sr);
position = fs.Length; //store the length of the stream
}
else
{
sr.DiscardBufferedData();
sr.BaseStream.Seek(position, SeekOrigin.Begin);
AddToContents(_fullPath, sr);
position = fs.Length; //store the length of the stream
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error while reading from {_fullPath}");
//log exception
}
finally
{
if (sr != null)
sr.Close();
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error while opening {_fullPath}");
//log exception
}
finally
{
if (fs != null)
fs.Close();
if (fsw != null)
fsw.EnableRaisingEvents = true; //set raise events for the filesystemwatcher to true
}
}
private List<string> AddToContents(string fullPath, StreamReader sr)
{
List<string> newLines = new List<string>();
try
{
while (!sr.EndOfStream)
{
try
{
string line = sr.ReadLine();
if (line != string.Empty)
{
Contents.Add(line);
newLines.Add(line);
Debug.WriteLine(line);
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error processing line in {fullPath}");
throw;
}
}
return newLines;
}
catch (Exception ex)
{
Debug.WriteLine($"Error while reading from {fullPath}");
throw;
}
}
}
class Program
{
static LogFile file;
static FileSystemWatcher fsw;
static void Main(string[] args)
{
string path = #"C:\Temp\test.txt";
file = new LogFile(path);
CreateWatcher(path);
Console.ReadKey();
}
private static FileSystemWatcher CreateWatcher(string fileNameFullPath)
{
fsw = new FileSystemWatcher(Path.GetDirectoryName(fileNameFullPath)); //constructor only accepts directory path
fsw.IncludeSubdirectories = false;
fsw.Filter = Path.GetFileName(fileNameFullPath); //filter for the given file
fsw.NotifyFilter = NotifyFilters.LastWrite;
fsw.EnableRaisingEvents = true;
fsw.Changed += Fsw_Changed;
return fsw;
}
private static void Fsw_Changed(object sender, FileSystemEventArgs e)
{
if (file != null)
file.Read(fsw);
}
}
Problem is
position = fs.Length; //store the length of the stream
You should store current position of the stream into position field not length of stream because sometimes FileStream.Length is zero (I don't know why)
this.position = fs.Position;
and check if FileStream.Length is zero skip that change
fs = new FileStream(this._fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
if (fs.Length != 0)
{
try
{
sr = new StreamReader(fs);
if (this.Contents.Count == 0)
{
......
Now it's working
I run a Method, there're three part, part 1 and 3 are all the same to "read text file",
and part2 is to save string to text file,
// The Save Path is the text file's Path, used to read and save
// Encode can use Encoding.Default
public static async void SaveTextFile(string StrToSave, string SavePath, Encoding ENCODE)
{
// Part1
try
{
using (StreamReader sr = new StreamReader(SavePath, ENCODE))
{
string result = "";
while (sr.EndOfStream != true)
result = result + sr.ReadLine() + "\n";
MessageBox.Show(result);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
// Part2
try
{
using (FileStream fs = new FileStream(SavePath, FileMode.Create))
{
using (StreamWriter sw = new StreamWriter(fs, ENCODE))
{
await sw.WriteAsync(StrToSave);
await sw.FlushAsync();
sw.Close();
}
MessageBox.Show("Save");
fs.Close();
}
}
// The Run End Here And didn't Continue to Part 3
catch (Exception e)
{
Console.WriteLine(e);
}
// Part3
try
{
using (StreamReader sr = new StreamReader(SavePath, ENCODE))
{
string result = "";
while (sr.EndOfStream != true)
result = result + sr.ReadLine() + "\n";
MessageBox.Show(result);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
But I find it strange that the process end at the place where Part2 complete, and the process directly end but didn't continue on Part3,
What's the reason to this condition? Generally the process should go through whole method but should not stop in the middle
(one more question)
And is there some other way can do the purpose of part2, and also can continue to part3 to comlplete whole method?
It could be because you are writing an async void method and you are calling some async methods in part 2. Try to change the async methods in part 2 to non-async methods:
using (StreamWriter sw = new StreamWriter(fs, ENCODE))
{
sw.Write(StrToSave);
sw.Flush(); // Non-async
sw.Close(); // Non-async
}
Does it behave as you expect now?
The problem is you are telling your app to await the methods, but never getting the Task result or a giving it a chance to complete. From what you've shown so far, you don't need the async stuff anyway, and greatly simplify the code:
public static void SaveTextFile(string StrToSave, string SavePath, Encoding ENCODE)
{
//Part1
try
{
MessageBox.Show(File.ReadAllText(SavePath, ENCODE));
}
catch (Exception e)
{
Console.WriteLine(e);
}
//Part2
try
{
File.WriteAllText(SavePath, StrToSave, ENCODE);
MessageBox.Show("Save");
}
catch (Exception e)
{
Console.WriteLine(e);
}
//Part3
try
{
MessageBox.Show(File.ReadAllText(SavePath, ENCODE));
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
If at all returning within try/catch/finally in not considered a structured programming how can I return from the below code block ?
public static string ReadFile()
{
StreamReader streamReader = null;
try
{
try
{
streamReader = new StreamReader(#"C:\Users\Chiranjib\Downloads\C# Sample Input Files\InputParam.txt"); //Usage of the Verbatim Literal
return streamReader.ReadToEnd();
}
catch (FileNotFoundException exfl)
{
string filepath = #"C:\Users\Chiranjib\Downloads\C# Sample Input Files\LogFiles.txt";
if (File.Exists(filepath))
{
StreamWriter sw = new StreamWriter(filepath);
sw.WriteLine("Item you are searching for {0} just threw an {1} error ", exfl.FileName, exfl.GetType().Name);
Console.WriteLine("Application stopped unexpectedly");
}
else
{
throw new FileNotFoundException("Log File not found", exfl);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
return string.Empty;
}
//Code inside finally gets executed even if the catch block returns when an exception happens
finally
{
//Resource de-allocation happens here
if (streamReader != null)
{
streamReader.Close();
}
Console.WriteLine("Finally block executed");
}
}
catch (FileNotFoundException ex)
{
Console.WriteLine("Log file not found ");
Console.WriteLine("Original exception " + ex.GetType().Name);
Console.WriteLine("Inner Exception " + ex.InnerException.GetType().Name);
}
finally
{
if (streamReader != null)
{
streamReader.Close();
}
Console.WriteLine("Finally block executed");
}
return streamReader.ReadToEnd() ?? string.Empty;
}
Thing is if I at all close the streamReader object before even getting it's value I would not be able to obtain a returned result.
But again it does not allow me to put a return in finally.
Please help me understand and overcome this difficulty in a standard way.
The easiest way for you to resolve this would be to just declare a variable inside your code and then read that out at the end.
For example.
public static string ReadFile()
{
var stringFile = "";
StreamReader streamReader = null;
try
{
try
{
streamReader = new StreamReader(#"C:\Users\Chiranjib\Downloads\C# Sample Input Files\InputParam.txt"); //Usage of the Verbatim Literal
stringFile = streamReader.ReadToEnd();
return stringFile
}
catch (FileNotFoundException exfl)
{
string filepath = #"C:\Users\Chiranjib\Downloads\C# Sample Input Files\LogFiles.txt";
if (File.Exists(filepath))
{
StreamWriter sw = new StreamWriter(filepath);
sw.WriteLine("Item you are searching for {0} just threw an {1} error ", exfl.FileName, exfl.GetType().Name);
Console.WriteLine("Application stopped unexpectedly");
}
else
{
throw new FileNotFoundException("Log File not found", exfl);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
return string.Empty;
}
//Code inside finally gets executed even if the catch block returns when an exception happens
finally
{
//Resource de-allocation happens here
if (streamReader != null)
{
streamReader.Close();
}
Console.WriteLine("Finally block executed");
}
}
catch (FileNotFoundException ex)
{
Console.WriteLine("Log file not found ");
Console.WriteLine("Original exception " + ex.GetType().Name);
Console.WriteLine("Inner Exception " + ex.InnerException.GetType().Name);
}
finally
{
if (streamReader != null)
{
streamReader.Close();
}
Console.WriteLine("Finally block executed");
}
return stringFile;
}
This should then read out your file by executing the following code
static void Main(string[] args)
{
var file = ReadFile();
Console.WriteLine(file);
Console.ReadLine();
}
I think you could eliminate several of those try/catch sequences and take care of disposing StreamWriter and StreamReader by using "using" statements. Here's an example:
using System;
using System.IO;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var fileContents = ReadFile();
Console.ReadLine(); // cause program to pause at the end
}
public static string ReadFile()
{
try
{
using (var streamReader = new StreamReader(
#"C:\MyTestFile.txt"))
{
var fileContents = streamReader.ReadToEnd();
Console.WriteLine("File was read successfully");
return fileContents;
}
}
catch (FileNotFoundException fileNotFoundException)
{
LogReadFileException(fileNotFoundException);
}
catch (DirectoryNotFoundException directoryNotFoundException)
{
LogReadFileException(directoryNotFoundException);
}
catch (IOException ioException)
{
LogReadFileException(ioException);
}
// If we get here, an exception occurred
Console.WriteLine("File could not be read successfully");
return string.Empty;
}
private static void LogReadFileException(Exception exception)
{
string logFilePath = #"C:\MyLogFile.txt";
using (var streamWriter = new StreamWriter(logFilePath,
append: true))
{
var errorMessage = "Exception occurred: " +
exception.Message;
streamWriter.WriteLine(errorMessage);
Console.WriteLine(errorMessage);
}
}
}
}
When I try to open a .txt file it only shows its location in my textbox.
I am out of ideas:( hope you can help me...
code:
private void OpenItem_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog();
System.IO.StringReader OpenFile = new System.IO.StringReader(openFileDialog1.FileName);
richTextBox1.Text = OpenFile.ReadToEnd();
OpenFile.Close();
}
A StringReader reads the characters from the string you pass to it -- in this case, the file's name. If you want to read the contents of the file, use a StreamReader:
var OpenFile = new System.IO.StreamReader(openFileDialog1.FileName);
richTextBox1.Text = OpenFile.ReadToEnd();
Use File.ReadAllText
richTextBox1.Text = File.ReadAllText(openFileDialog1.FileName);
I'd use the File.OpenText() method for reading text-files. You should also use using statements to properly dispose the object.
if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
// Make sure a file was selected
if ((myStream = openFileDialog1.OpenFile()) != null) {
// Open stream
using (StreamReader sr = File.OpenText(openFileDialog1.FileName))
{
// Read the text
richTextBox1.Text = sr.ReadToEnd();
}
}
}
catch (Exception ex)
{
MessageBox.Show("An error occured: " + ex.Message);
}
}
That's easy. This is what you need to do:
1) Put using System.IO; above namespace.
2) Create a new method:
public static void read()
{
StreamReader readme = null;
try
{
readme = File.OpenText(#"C:\path\to\your\.txt\file.txt");
Console.WriteLine(readme.ReadToEnd());
}
// will return an invalid file name error
catch (FileNotFoundException errorMsg)
{
Console.WriteLine("Error, " + errorMsg.Message);
}
// will return an invalid path error
catch (Exception errorMsg)
{
Console.WriteLine("Error, " + errorMsg.Message);
}
finally
{
if (readme != null)
{
readme.Close();
}
}
}
3) Call it in your main method: read();
4) You're done!