I had developed a filewatcher program to monitor a folder, if there are any changed of the file, it will copy the file to another folder.
But I found that there will be error message when writing the original file (e.g. file being prcoess by another application...) it seems that the file locked when running [System.IO.File.Copy] copying to another folder.
Is there any solution can avoid the original file locked by the filewatcher/System.IO.File.Copy? Thanks.
The following is my code:
private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
{
DateTime lastWriteTime = File.GetLastWriteTime(e.FullPath);
if (lastWriteTime != lastRead)
{
txtLog.Text += e.ChangeType + ": " + e.FullPath + "\r\n";
txtLog.Focus();
txtLog.Select(txtLog.TextLength, 0);
txtLog.ScrollToCaret();
try
{
string myPath = e.FullPath;
string myFile = e.Name;
System.IO.FileInfo myFileInfo = new System.IO.FileInfo(myFile);
string myAttibs = myFileInfo.Attributes.ToString();
System.IO.File.Copy(myPath, #"D:\\Folder\\Output\\" + myFile, true);
lastRead = lastWriteTime;
}
catch (System.IO.IOException ex)
{
System.IO.IOException myex = ex;
}
catch (System.Exception ex)
{
System.Exception myex = ex;
}
}
}
I ran into the same problem. I am not fond of my solution, as it feels hackish. But it works:
FileSystemWatcher fsWatcher = new FileSystemWatcher();
fsWatcher.Created += new FileSystemEventHandler( fsWatcher_Created );
private void fsWatcher_Created( object sender, FileSystemEventArgs e )
{
RaiseFileFoundEvent( e.FullPath );
while ( !TestOpen( e.FullPath ) ) ;
RaiseFileCopyDoneEvent( e.FullPath );
}
private bool TestOpen( string filename )
{
try
{
FileStream fs = new FileStream( filename, FileMode.Open,
FileAccess.Write, FileShare.None );
fs.Close();
return true;
}
catch ( Exception )
{
return false;
}
}
private void RaiseFileFoundEvent( string fullPath )
{
// a file is found, but the copy is not guaranteed to be finished yet.
}
private void RaiseFileCopyDoneEvent( string fullPath )
{
// the file is found, and we know the copy is done.
}
There's not a good way to solve this problem. How should the program behave if you're in the middle of copying the file to a new location when another application wants to write to it?
If you're willing to copy a corrupted file (that was written-to while you were copying), you'll have to write your own Copy method that uses FileShare.ReadWrite.
Related
I have json file that I want to share between two processess. So I created a memory mapped file as follows.
private void CreateMemoryMappedFile()
{
var info = Directory.CreateDirectory(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "/" + model.Data.Settings.OrcaUISpecificSettings.TimeOutFolder);
string path = Path.Combine(info.FullName + #"\" + model.Data.Settings.OrcaUISpecificSettings.File);
FullPath = path;
try
{
mmf = MemoryMappedFile.CreateFromFile(path, FileMode.CreateNew, "MyMemoryFile", 1024 * 1024);
}
catch (Exception ex)
{
}
}
public MemoryMappedViewStream GetAccessor()
{
MemoryMappedViewStream FileMapView = null;
if (FileMapView != null)
{
return FileMapView;
}
FileMapView = mmf.CreateViewStream();
return FileMapView;
}
And to read and write to the files I am doing the following
public void WriteToMemoryMappedFile(string Data)
{
try
{
mutex.WaitOne();
byte[] bytes = Encoding.ASCII.GetBytes(Data);
var accessor = GetAccessor();
accessor.Write(bytes, 0, Data.Length);
mutex.ReleaseMutex();
}
catch (Exception ex)
{
}
}
public string ReadFromMemoryMappedFile()
{
mutex.WaitOne();
var accessor = GetAccessor();
using (BinaryReader binReader = new BinaryReader(accessor))
{
byte[] reader = binReader.ReadBytes((int)accessor.Length);
string result = Encoding.Default.GetString(reader);
mutex.ReleaseMutex();
return result.Replace("NULL", "");
}
}
My problem is I have an Activity Monitor for my app. So after x amount of time I am updating the json file with InActiveStatus. Along the same lines I am listening to any file changes(Look at D_IDle event). Problem is If a normal file is changed I get the FileSytemWatcher changed event firing just fine. But when I use a Memory Mapped File to update the status, the FileSystemWatcher changed event never gets fired please help.
private void D_IsIdle(object sender, EventArgs e)
{
MonitorDirectory();
//AppViewModel.SerializeData("InActive");
AppViewModel.SerializeDataToMemoryMap("InActive");
d.IsIdle -= D_IsIdle;
}
public void MonitorDirectory()
{
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(AppViewModel.GetDriectory());
fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileSystemWatcher.Filter = "*.json";
fileSystemWatcher.Changed += FileSystemWatcher_Changed;
fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
//IT NEVER COMES HERE
}
Using FileSystemWatcher with memory mapped files must be some kind of anti-pattern:). If you are on a local system, use one of the process synchronization primitives (e.g. semaphores) to signal change.
My guess is that the FileSystemWatcher triggers when the file handle is closed to avoid other processed reading partially written files.
I'm making a WPF C# Application and I need to copy a file. As the title says whenever I select any file it says its open in another process, so I'm guessing its something to do with my code.
I've attempted to rewrite the File.Copy code to be able to be able to track the progress of the copying.
My file copying code
public static void CopyFile(string file, string destination, ProgressBar progressCallback)
{
try
{
if (!Directory.Exists(destination)) Directory.CreateDirectory(destination);
} catch (IOException e)
{
MessageBox.Show("There was an error while creating the resource packs directory " + e.Message, "Canno't create directory", MessageBoxButton.OK);
return;
}
int halfAMeg = (int)(1024 * 1024 * 0.4);
FileStream strIn = null;
FileStream strOut = null;
try
{
strIn = new FileStream(file, FileMode.Open);
strOut = new FileStream(Path.Combine(destination, file), FileMode.Create);
}
catch (IOException e)
{
MessageBox.Show("There was an error while copying the file: " + e.Message, "Canno't copy file", MessageBoxButton.OK);
return;
}
byte[] buf = new byte[halfAMeg];
while (strIn.Position < strIn.Length)
{
int len = strIn.Read(buf, 0, buf.Length);
strOut.Write(buf, 0, len);
progressCallback.Maximum = Int32.MaxValue;
progressCallback.Value = (int)(Int32.MaxValue / (strIn.Position / strIn.Length));
}
strIn.Close();
strOut.Close();
}
Any help would be greatly appreciated.
EDIT 10/22: This question was made years ago when I greatly underestimated my C++ ability. I apologise for the poor code and poorly written question!
In my project i need to create an excel file in users desktop. Code written in my visual studio is.
string sPathTestData1 = "\\AdaptiveModulations.xls";
string sPathTestData = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\AdaptiveModulations" + sPathTestData1;
string sheet = "Sheet1";
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\AdaptiveModulations";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
ExcelUtils.createExcelFile(sPathTestData,sheet);
}
else
{
ExcelUtils.setExcelFile(sPathTestData,sheet);
}
This code is working perfectly in my system and creating folder with excel file but when i copied the exe from C:\Visual Studio 2015\Projects\AMCalculator\AMCalculator\bin\Debug folder and saved in another machine it showing error can anyone help on this
I have added try/catch blocks in my classes
In ExcelUtils Class :
public static void createExcelFile(String filepath, String sheetName)
{
try
{
using (FileStream stream = new FileStream(filepath, FileMode.Create, FileAccess.ReadWrite))
{
workBook = new HSSFWorkbook();
workSheet = workBook.CreateSheet(sheetName);
workBook.Write(stream);
stream.Close();
}
}
catch (Exception e) {
Console.WriteLine("Unable to Create File. Exception is : " + e);
}
}
public static void setExcelFile(string filepath, string sheetName)
{
try
{
Console.WriteLine("File Path is : " + filepath);
workBook = WorkbookFactory.Create(new FileStream(
Path.GetFullPath(filepath),
FileMode.Open, FileAccess.Read,
FileShare.ReadWrite));
workSheet = workBook.GetSheet(sheetName);
}
catch (Exception e)
{
Console.WriteLine("Unable to Load File. Exception is : " + e);
}
}
In My main class :
if (!File.Exists(sPathTestData))
{
Directory.CreateDirectory(path);
try
{
ExcelUtils.createExcelFile(sPathTestData, sheet);
}
catch (FileNotFoundException fe)
{
Console.WriteLine("Unable to Create File. Exception is : " + fe);
}
}
else
{
try
{
ExcelUtils.setExcelFile(sPathTestData, sheet);
}
catch (FileNotFoundException fe)
{
Console.WriteLine("Unable to Load File. Exception is : " + fe);
}
}
I create an empty file and try to copy the contents from an existing to the newly created file. When i do that i am getting an IOexception
private void button1_Click(object sender, EventArgs e)
{
String test = textBox1.Text.ToString();
if (string.IsNullOrEmpty(textBox1.Text))
{
MessageBox.Show("Enter the filename");
}
else
{
StreamWriter File = new StreamWriter(test);
MessageBox.Show(test + " Has been created");
}
}
private void button2_Click(object sender, EventArgs e)
{
String test = textBox1.Text.ToString();
try
{
File.Copy(#"D:\\Study this.txt", test);
}
catch (IOException)
{
MessageBox.Show("IO error occured");
}
}
You will need to close the Stream so in the else statement add File.Close(); that will release the newly created file. That section of the code will now look like this:
StreamWriter File = new StreamWriter(test);
File.Close();
MessageBox.Show(test + " Has been created");
replace line StreamWriter File = new StreamWriter(test); with below
using (File.Create(test)) ;
or with
using (StreamWriter writer = new StreamWriter(test)){}
reason for above change is you need to propery close the opend stream object before the copy.
using block will handle that for you.
I am creating a file using file stream, but before that i am applying if condition to see if the file exist or not. When i click on button and if supppose file is there it deletes the file. Its ok, and again if i press the button the file gets created. At first time it works well.
Now the file is created, again if I press the button and it should delete but it is trhowing an exception saying that*The process cannot access the file 'C:\Hello1' because it is being used by another process.*
Below is my code
private void button2_Click(object sender, EventArgs e)
{
string fileName = #"C:\Hello1";
if
(File.Exists(fileName))
{
File.Delete(fileName);
MessageBox.Show("File is deleted");
}
else
{
FileInfo createFile = new FileInfo(fileName);
FileStream create = createFile.Create();
MessageBox.Show("Created");
}
}
So why I am not able to delete second time, My text file is not open also but still it is showing the exception.
You're never closing your stream that created the file. Put your FileStream in a using statement, which will automatically clean up the open file handle.
using(FileStream create = createFile.Create())
{
//code here
}
The file stream is still opened when you're trying second time, try this:
private void button2_Click(object sender, EventArgs e)
{
string fileName = #"C:\Hello1";
if
(File.Exists(fileName))
{
File.Delete(fileName);
MessageBox.Show("File is deleted");
}
else
{
FileInfo createFile = new FileInfo(fileName);
using(FileStream create = createFile.Create())
{
MessageBox.Show("Created");
}
}
}
Oh yes i got the answer,
I need to use
private void button2_Click(object sender, EventArgs e)
{
string fileName = #"C:\Hello1";
if
(File.Exists(fileName))
{
File.Delete(fileName);
MessageBox.Show("File is deleted");
}
else
{
FileInfo createFile = new FileInfo(fileName);
FileStream create = createFile.Create();
MessageBox.Show("Created");
create.Close();
}
}
We need to use create.Close();
Here is an example I used to write a local log:
StreamWriter log;
string fpath = string.Format(#"{0}\{1}.txt",GetDirectory(),DateTime.Now.ToString("yyy-MM-dd"));
if (!File.Exists(fpath))
{
log = new StreamWriter(fpath);
}
else
{
log = File.AppendText(fpath);
}
log.WriteLine(string.Format("{0} ==> {1}",DateTime.Now.ToString("MM/dd/yyy HH:mm:ss"), Message));
log.Dispose();
log = null;