XML serialization IOexception was unhandled - c#

i have the following code used to serialize a label's content. When i press the "save" button, an xml file is generated. When press the "load" button after i select the same xml file, an error occured, IOexception was unhandled, The process cannot access the file 'C:\datasaved.xml' because it is being used by another process. Is there anything wrong with my code?
Thanks.
public class FormSaving
{
private string major;
public string Majorversion
{
get;
set;
}
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
string savepath;
SaveFileDialog DialogSave = new SaveFileDialog();
// Default file extension
DialogSave.DefaultExt = "txt";
// Available file extensions
DialogSave.Filter = "XML file (*.xml)|*.xml|All files (*.*)|*.*";
// Adds a extension if the user does not
DialogSave.AddExtension = true;
// Restores the selected directory, next time
DialogSave.RestoreDirectory = true;
// Dialog title
DialogSave.Title = "Where do you want to save the file?";
// Startup directory
DialogSave.InitialDirectory = #"C:/";
DialogSave.ShowDialog();
savepath = DialogSave.FileName;
DialogSave.Dispose();
DialogSave = null;
FormSaving abc = new FormSaving();
abc.Majorversion = MajorversionresultLabel.Content.ToString();
FileStream savestream = new FileStream(savepath, FileMode.Create);
XmlSerializer serializer = new XmlSerializer(typeof(FormSaving));
serializer.Serialize(savestream, abc);
}
private void LoadButton_Click(object sender, RoutedEventArgs e)
{
Stream checkStream = null;
Microsoft.Win32.OpenFileDialog DialogLoad = new Microsoft.Win32.OpenFileDialog();
DialogLoad.Multiselect = false;
DialogLoad.Filter = "XML file (*.xml)|*.xml|All files (*.*)|*.*";
if ((bool)DialogLoad.ShowDialog())
{
try
{
if ((checkStream = DialogLoad.OpenFile()) != null)
{
loadpath = DialogLoad.FileName;
}
}
catch (Exception ex)
{
System.Windows.MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
else
{
System.Windows.MessageBox.Show("Problem occured, try again later");
}
FormSaving abc;
FileStream loadstream = new FileStream(loadpath, FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(FormSaving));
abc = (FormSaving)serializer.Deserialize(loadstream);
loadstream.Close();
MajorversionresultLabel.Content = abc.Majorversion;
}

This is the most immediate problem:
FileStream savestream = new FileStream(savepath, FileMode.Create);
XmlSerializer serializer = new XmlSerializer(typeof(FormSaving));
serializer.Serialize(savestream, abc);
You're not closing the stream, so the file can't be reopened for read. Use a using statement:
using (Stream savestream = new FileStream(savepath, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(FormSaving));
serializer.Serialize(savestream, abc);
}
You should take the same approach when loading the file as well, instead of calling Close explicitly... with your current code, if an exception occurs when deserializing, you won't be closing the stream.
You're also opening the file via Dialog.OpenFile, but not closing that stream... and why bother opening it twice? Just read from the stream you've opened.
Finally (for the moment) you're catching an exception (blindly, with no regard for which exceptions are really worth trying to handle) but then continuing regardless. If you've caught an exception, chances are the last part of the method won't execute correctly, so you should either return or throw another exception yourself.

Related

Can't Read CSV from Download Folder in Android Device C# Unity

This script generate a txt file in Download folder on Android device.
public class WriteCSVInDownloadFolder : MonoBehaviour
{
public TMP_Text Text;
private void Start()
{
try
{
var txtpath = GetDownloadFolder() + "/Test.txt";
FileStream file = new FileStream(txtpath, FileMode.Create, FileAccess.Write);
}
catch (IOException e)
{
Text.text = e.Message;
}
}
public static string GetDownloadFolder()
{
string[] temp = (Application.persistentDataPath.Replace("Android", "")).Split(new string[] { "//" }, System.StringSplitOptions.None);
return (temp[0] + "/Download");
}
}
But, when I manually remove this file and execute this script again, I receive an exception: "File already exists"
Therefore , I have tried to use FileMode.Truncate and File.Exists functions, however, I receive another exception: "Could not find file"
Any idea?
Update 1
I tried to solve the problem with Dispose() method, but the problem persist.
TextWriter writer = File.CreateText(path);
writer.Write("Hello World");
writer.Flush();
writer.Dispose();
Update 2
I tried to remove residual entries getting Uri, but not working.
Uri uri = new Uri(txtpath);
if (uri.IsFile)
{
string filename = Path.GetFileName(uri.LocalPath);
Text.text = filename;
File.Delete(uri.LocalPath);
}
Update 3
Current code
private void Awake()
{
try
{
txtpath = FileManager.GetFolder("/Download") + "/Test.txt";
if (File.Exists(txtpath))
{
Text.text = "Exist";
File.Delete(txtpath);
}
else
{
Text.text = "Not existe";
FileStream file = new FileStream(txtpath, FileMode.Create, FileAccess.Write);
}
}
catch (IOException e)
{
Text.text = e.Message;
}
}
Update 4
New: I tried to use Path.Combine.
Exception thrown: "Access to the path "..." is denied".
public class ReadCSVInDownloadFolder : MonoBehaviour
{
public TMP_Text Text;
private string path;
private void Awake()
{
try
{
path = Path.Combine("storage","emulated","0","Download", "Test.csv");
Text.text = File.ReadAllText(path);
}
catch (Exception e)
{
Text.text = e.Message;
}
}
}
While creating your file it has been indexed by the media store.
So there is an entry for the file in the media store.
There are a bunch of sloppy programmed file managers that delete the file but leave the entry.
So first delete that entry and then you go again.

FileSystemWacher is locking some files

I am using this code to monitor creation of files in certain folder:
_watcher = new RecoveringFileSystemWatcher(SourceFolder, "*.xml");
_watcher.Created += (_, e) =>
{
ProcessFile(e.Name);
};
RecoveringFileSystemWatcher is a fileSystemWatcher wrapper. It's constructor is:
public RecoveringFileSystemWatcher (string path, string filter)
{
_containedFSW = new FileSystemWatcher(path, filter);
}
The process works as expected but for some files, randomly, an exception is thrown telling that the file is used by another process.
This is the method that is launched upon file creation:
var nfo = new FileInfo(filePath);
if (nfo.Exists)
{
var archivoXml = nfo.Name;
string archivo = String.Empty;
try
{
string content = Task.Run(async () => await GetFileContent(filePath)).Result;
if (String.IsNullOrEmpty(content))
return false;
XmlDocument xml = new XmlDocument();
xml.LoadXml(content);
//The rest of the method
}
}
the method GetFileContent is this:
private async Task<string> GetFileContent(string filePath)
{
string content = String.Empty;
try
{
Console.Write("ONE - "); InfoLog.Save($"ONE {filePath}");
using (StreamReader sr = new StreamReader(filePath))
{
Console.Write("TWO - "); InfoLog.Save($"TWO {filePath}");
content = await sr.ReadToEndAsync().ConfigureAwait(false);
Console.Write($"THREE {(sr.BaseStream == null ? "Closed" : "Opened")} - "); InfoLog.Save($"THREE {(sr.BaseStream == null ? "Closed" : "Opened")} {filePath}");
sr.Close();
Console.WriteLine($"FOUR {(sr.BaseStream == null ? "Closed" : "Opened")}"); InfoLog.Save($"FOUR {(sr.BaseStream == null ? "Closed" : "Opened")} {filePath}");
}
}
catch (Exception ex)
{
InfoLog.Save($"XML file could be read -> {filePath}. See error log.");
ErrorLog.Save(ex);
}
return content;
}
Look at the log information I am writing to debug the process.
I got one case with a file called 1112186.xml.... this is recorded in the log:
18/12/2018 19:12:10 ONE D:\GestorDocumental\Origen\1112186.xml
18/12/2018 19:12:10 XML file could not be read -> D:\GestorDocumental\Origen\1112186.xml. See error log.
As you see, the exception is thrown at the "using" instruction.
If I see the full log, I can see that file, 1112186.xml, is never used before, so the only chance is that FSW keeps the file opened. I don't know why, but it seems this is happening.
It is clear also that this process is locking the file, because when I exit the console application and then run again, the file can be processed.
Any help about this, please?
thanks
Jaime
I usually use this method to check if file is locked. I got it from one of the link in stackoverflow.
public static bool IsFileClosed(string filepath)
{
bool fileClosed = false;
int retries = 20;
const int delay = 400; // set a delay period = retries*delay milliseconds
if (!File.Exists(filepath))
return false;
do
{
try
{
// Attempts to open then close the file in RW mode, denying other users to place any locks.
FileStream fs = File.Open(filepath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
fs.Close();
fileClosed = true; // success
}
catch (IOException) { }
retries--;
if (!fileClosed)
Thread.Sleep(delay);
}
while (!fileClosed && retries > 0);
return fileClosed;
}
This is a new class called FileTimerWatcher (it will have logger injected):
public FileTimerWatcher(ILogger logger) : base(logger)
{
if (timer == null)
{
// Create a timer with a 1.5 second interval.
// monitor the files after 1.5 seconds.
timer = new Timer(delay);
// Hook up the event handler for the Elapsed event.
timer.Elapsed += new ElapsedEventHandler(ProcessFolder);
timer.AutoReset = true;
timer.Enabled = true;
}
}
private void ProcessFolder(object sender, ElapsedEventArgs e)
{
var LastChecked = DateTime.Now;
string[] files = System.IO.Directory.GetFiles(SourceDirectory, somefilter, System.IO.SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
ProcessFile(file); // process file here
}
}

trying to use SpeechSynthesizer and NAudio but process cannot access the file

I am trying to use SpeechSynthesizer and NAduio, my code is below. I can't seem to get it to work though. I am getting the error message,
The process cannot access the file 'some file.wav' because it is being used by another process.
It happens on the line,
wave = new WaveFileReader(path + fileName);
In the synth_SpeakCompleted method.
I do not understand though what is using the file? The SpeechSynthesizer has completed creating the file as the event has been raised. Obviously I am missing something.
I am only saving the file because I don't know how to go directly from SpeechSynthesizer to NAudio so if there is a solution that doesn't save a file that would be great.
The file is fine and works perfectly when I run it manually.
using NAudio.Wave;
public partial class MainWindow : Window
{
private WaveFileReader wave = null;
private DirectSoundOut output = null;
SpeechSynthesizer synthesizer = null;
private void DrawContent()
{
string path = #"C:\Users\MyPath\";
string fileName = "MyFile.wav";
// delete previous file if it exists
if (File.Exists(path + fileName))
File.Delete(path + fileName);
synthesizer = new SpeechSynthesizer();
synthesizer.Volume = 100; // 0...100
synthesizer.Rate = 3; // -10...10
synthesizer.SetOutputToWaveFile(path + fileName);
synthesizer.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(synth_SpeakCompleted);
synthesizer.SpeakAsync(someText);
}
void synth_SpeakCompleted(object sender, SpeakCompletedEventArgs e)
{
synthesizer.SetOutputToNull();
string path = #"C:\Users\MyPath\";
string fileName = "MyFile.wav";
wave = new WaveFileReader(path + fileName);
output = new DirectSoundOut();
output.Init(new WaveChannel32(wave));
output.Play();
}
private void DisposeWave()
{
if(output != null)
{
if (output.PlaybackState == PlaybackState.Playing)
output.Stop();
output.Dispose();
output = null;
}
if(wave != null)
{
wave.Dispose();
wave = null;
}
}
}

Windows Form XML Serilization Load Dialog

I've got a windows form with save/loading of XML files and it asks the user where they want to save/load it. My problem is I dont know how to change this method to load the file from where the user wants and not where the streamreader specifies.
The code below is of my button and LoadValues Method.
private void Edittask_loadbuttonClick(
object sender, EventArgs e)
{
Stream myStream = null;
var sFile1 = new OpenFileDialog();
sFile1.InitialDirectory = "c:\\";
sFile1.Filter = "xml files (*.xml)|*.xml";
sFile1.FilterIndex = 2;
sFile1.RestoreDirectory = true;
if (sFile1.ShowDialog() == DialogResult.OK)
{
try
{
if ((myStream = sFile1.OpenFile()) != null)
{
using (myStream)
{
var v = LoadValues();
this.load_task1_name.Text =
v.task1_name;
this.load_task1_desc.Text =
v.task1_desc;
this.load_task1_date.Value =
v.task1_date;
this.load_checkbox.Checked =
v.task1_checkbox;
}
}
}
catch (Exception ex)
{
MessageBox.Show(
"Error: Could not read file from disk. Original error: " +
ex.Message);
}
}
}
public Values LoadValues()
{
var serializer = new XmlSerializer(typeof (Values));
using (
TextReader textReader = new StreamReader(
"E:\\hello.xml")
)
{
return
(Values) serializer.Deserialize(textReader);
}
}
I would pass the Stream from the OpenFileDialog to LoadValues(...), and use that to construct your StreamReader:
public Values LoadValues(Stream stream)
{
XmlSerializer serializer = new XmlSerializer(typeof(Values));
using (TextReader textReader = new StreamReader(stream))
{
return (Values)serializer.Deserialize(textReader);
}
}
and
if ((myStream = sFile1.OpenFile()) != null)
{
using (myStream)
{
Values v = LoadValues(myStream);
...
}
}
You need to pass the Stream as a parameter to your function.

C# IOException: The process cannot access the file because it is being used by another process

I have a slight problem. What my application is supose to do, is to watch a folder for any newly copied file with the extention '.XSD' open the file and assign the lines to an array. After that the data from the array should be inserted into a MySQL database, then move the used file to another folder if it's done.
The problem is that the application works fine with the first file, but as soon as the next file is copied to the folder I get this exception for example: 'The process cannot access the file 'C:\inetpub\admission\file2.XPD' because it is being used by another process'.
If two files on the onther hand is copied at the same time there's no problem at all.
The following code is on the main window:
public partial class Form1 : Form
{
static string folder = specified path;
static FileProcessor processor;
public Form1()
{
InitializeComponent();
processor = new FileProcessor();
InitializeWatcher();
}
static FileSystemWatcher watcher;
static void InitializeWatcher()
{
watcher = new FileSystemWatcher();
watcher.Path = folder;
watcher.Created += new FileSystemEventHandler(watcher_Created);
watcher.EnableRaisingEvents = true;
watcher.Filter = "*.XPD";
}
static void watcher_Created(object sender, FileSystemEventArgs e)
{
processor.QueueInput(e.FullPath);
}
}
As you can see the file's path is entered into a queue for processing which is on another class called FileProcessor:
class FileProcessor
{
private Queue<string> workQueue;
private Thread workerThread;
private EventWaitHandle waitHandle;
public FileProcessor()
{
workQueue = new Queue<string>();
waitHandle = new AutoResetEvent(true);
}
public void QueueInput(string filepath)
{
workQueue.Enqueue(filepath);
if (workerThread == null)
{
workerThread = new Thread(new ThreadStart(Work));
workerThread.Start();
}
else if (workerThread.ThreadState == ThreadState.WaitSleepJoin)
{
waitHandle.Set();
}
}
private void Work()
{
while (true)
{
string filepath = RetrieveFile();
if (filepath != null)
ProcessFile(filepath);
else
waitHandle.WaitOne();
}
}
private string RetrieveFile()
{
if (workQueue.Count > 0)
return workQueue.Dequeue();
else
return null;
}
private void ProcessFile(string filepath)
{
string xName = Path.GetFileName(filepath);
string fName = Path.GetFileNameWithoutExtension(filepath);
string gfolder = specified path;
bool fileInUse = true;
string line;
string[] itemArray = null;
int i = 0;
#region Declare Db variables
//variables for each field of the database is created here
#endregion
#region Populate array
while (fileInUse == true)
{
FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read,
FileShare.ReadWrite);
StreamReader reader = new StreamReader(fs);
itemArray = new string[75];
while (!reader.EndOfStream == true)
{
line = reader.ReadLine();
itemArray[i] = line;
i++;
}
fs.Flush();
reader.Close();
reader.Dispose();
i = 0;
fileInUse = false;
}
#endregion
#region Assign Db variables
//here all the variables get there values from the array
#endregion
#region MySql Connection
//here the connection to mysql is made and the variables are inserted into the db
#endregion
#region Test and Move file
if (System.IO.File.Exists(gfolder + xName))
{
System.IO.File.Delete(gfolder + xName);
}
Directory.Move(filepath, gfolder + xName);
#endregion
}
}
The problem I get occurs in the Populate array region. I read alot of other threads and was lead to believe that by flushing the file stream would help...
I am also thinking of adding a try..catch for if the file process was successful, the file is moved to gfolder and if it failed, moved to bfolder
Any help would be awesome
Tx
You're not disposing of your FileStream instance, so a lock remains on the file. Change your code to use using blocks:
using (var fileStream = new FileStream(...))
{
using (var reader = new StreamReader(fileStream))
{
}
}
These using blocks will ensure the instances are correctly disposed of.
Also, why are you calling Flush on the file stream? You're not writing anything with it...
I would suggest :
1° use the using syntax on StreamReader
2° use the using syntax on FileStream

Categories