I've set all the FSW properties in the designer (EnableRaisingEvents = true, filter = *.tif, IncludeSubdirectories = true, path = bla\bla\bla).
The application runs on a Windows Server 2008 R2 Standard machine and watches a local folder for created files. Instead of "C:\" i use the computers network name "GRAHAM".
The problem is that the FSW doesn't always fire when files are created/moved to the watched directory. It seems that sometimes it does, but most times it doesn't.
When debugging and watching that folder from my machine there is also some strange behaviour. If i remotely control the server machine and move files to the watched folder nothing happens. But if I move files into the watched folder from shared network folders the FSW fires, every time.
This makes it really hard for me to find the error/bug. Anyone got any ideas?
This is literally all of the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace Ekonomikompetens_unikt_namn
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)
{
StringBuilder log = new StringBuilder();
try
{
log.Append("--------------------").AppendLine().Append(DateTime.Now).AppendLine().Append("--------------------").AppendLine();
FileInfo file = new FileInfo(e.FullPath);
while (IsFileLocked(file))
{
System.Threading.Thread.Sleep(300);
}
string oFile = e.FullPath;
string nFile = oFile.Insert(oFile.Length - 4, "_" + DateTime.Now.ToString().Replace(" ", "").Replace("-", "").Replace(":", "")).Replace("\\XML Konvertering", "").Replace(#"\\GRAHAM\AnyDoc Invoices", #"\\FAKTURASERVER\AnyDoc");
if (!Directory.Exists(nFile.Substring(0, nFile.LastIndexOf('\\'))))
{
Directory.CreateDirectory(nFile.Substring(0, nFile.LastIndexOf('\\')));
File.Move(oFile, nFile);
Directory.Delete(oFile.Substring(0, oFile.LastIndexOf('\\')));
}
else
{
File.Move(oFile, nFile);
}
log.Append("* Moved and stamped file: ").AppendLine().Append(oFile).Append(" to ").Append(nFile).AppendLine().Append("--------------------").AppendLine();
}
catch (Exception x)
{
log.AppendLine().Append("*** ERROR *** ").Append(x).AppendLine().AppendLine();
}
finally
{
TextWriter tw = new StreamWriter(#"C:\tidslog\log.txt", true, Encoding.Default);
//TextWriter tw = new StreamWriter(#"C:\PROJEKT\tidsstämplarn\log.txt", true, Encoding.Default);
tw.Write(log);
tw.Dispose();
}
}
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
return true;
}
finally
{
if (stream != null)
stream.Close();
}
return false;
}
}
}
Note: The try-catch-finally is probably not really well made, but I'm new to coding and not really sure how to "catch" stuff, the logger has never logged an error though. Since the FSW never fires there isn't a chance for an error to occur. I'm guessing.
Subscribe to the Error event and check the error if any
In case there are large number of file being created or changed,do this
1> Increase InternalBufferSize.
Doc say this:
Increasing the size of the buffer can prevent missing file system
change events. However, increasing buffer size is expensive, because
it comes from non-paged memory that cannot be swapped out to disk, so
keep the buffer as small as possible. To avoid a buffer overflow, use
the NotifyFilter and IncludeSubdirectories properties to filter out
unwanted change notifications.
2> Also you are doing a lot of things in fileSystemWatcher1_Created which can cause the buffer to overflow causing it to miss some events...Use ThreadPool instead.
Related
I am new in WinForms technology. I am using .NET Framework 4.8 , Microsoft Visual Studio 2019. I put file in Resources folder.
I tried something like this
using DevExpress.XtraBars;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace accwf
{
public partial class NhapSoDu : DevExpress.XtraBars.Ribbon.RibbonForm
{
public NhapSoDu()
{
InitializeComponent();
}
private void simpleButton1_Click(object sender, EventArgs e)
{
Console.WriteLine(System.AppDomain.CurrentDomain.BaseDirectory);
Process.Start(".../B01-DN_01_Summary.xlsx");
}
}
}
please guide me finish it.
I do this in one of my applications to open a XLSX file that is an embedded resource in my application
private void buttonOpenTemplate_Click(object sender, EventArgs e)
{
byte[] templateFile = Properties.Resources._01__So_du_tai_khoan; // This is your Excel document in the application Resources
string tempPath = $"{Path.GetTempFileName()}.xlsx";
using (MemoryStream ms = new MemoryStream(templateFile))
{
using(FileStream fs = new FileStream(tempPath, FileMode.OpenOrCreate))
{
ms.WriteTo(fs);
fs.Close();
}
ms.Close();
}
Process.Start(tempPath);
}
This requires a reference to System.IO for access to the MemoryStream and FileStream classes.
You are currently only outputting the base directory. Along with that, you're only looking for files within that base directory. Execution happens from the base directory, so your program is looking for ..\Path\to\exe\B01-DN_01_Summary.xlsx when it should be looking for ..\Path\to\exe\Resources\FilesHere\ImportExcel\B01-DN_01_Summary.xlsx
To note: embedding resources files into your application is not recommend. It's preferable to instead store their locations and allow the application to traverse your directories to find the specified file locations.
Here's an adapted version you can try:
You will need to make sure that the Copy to Output Directory property for you desire file is set to "Copy Always" or "Copy if Newer". This will ensure the directory path is created in your output directory.
namespace accwf
{
public partial class NhapSoDu : DevExpress.XtraBars.Ribbon.RibbonForm
{
public NhapSoDu()
{
InitializeComponent();
}
private void simpleButton1_Click(object sender, EventArgs e)
{
string resourcePath = System.IO.File.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Resources\\FilesHere\\ImportExcel\\B01-DN_01_Summary.xlsx")
if (File.Exists(resourcePath))
{
MessageBox.Show("Exists");
}
else
{
MessageBox.Show("Doesn't Exist");
}
Process.Start(resourcePath);
}
}
}
This is an example of how I get PDF file documentation for a help menu I have:
public void MyMethod()
{
// helpMenuPath is a global var set to something like: Area/MyApp/Resources/
string filePath = helpMenuPath;
string[] fileNames = new string[0]; // Initialize the variable with length of 0. Directory.GetFiles() will allow for this length to be overwritten
// Try/Catch in case bad dir
try
{
fileNames = Directory.GetFiles(filePath);
}
catch (IOException ioe)
{
// error catch for if bad dir
MessageBox.Show($"Error in getting files: {ioe.Message}");
}
// Do something with files ...
}
I'm working on a gradebook program assignment for a class; the details aren't so important, except to know that I need to be able to save a file and recall it later. I know how to serialize, deserialize, etc, and everything's good there. But the problem comes when I try to save. I'm a bit new to the whole saving data scene, and I don't exactly know the techniques, but what I have seems like it should work - except that every time I try it, I get an error.
private static void Save (IList<GradebookEntry> gradebook) {
Console.WriteLine ("Saving changes. Please wait...");
using (IsolatedStorageFile stored = IsolatedStorageFile.GetStore (IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null)) {
try {
using (IsolatedStorageFileStream isoStream = new IsolatedStorageFileStream ("Temp.utc", FileMode.Create, stored)) {
BinaryFormatter bform = new BinaryFormatter ();
bform.Serialize (isoStream, gradebook);
string[] s = stored.GetDirectoryNames ();
stored.DeleteFile ("Gradebook.utc");
stored.MoveFile ("Temp.utc", "Gradebook.utc"); // #!!
}
Console.WriteLine ("Changes saved.");
}
catch (Exception ex) {
Console.WriteLine ("Saving failed. Reason: {0}", ex.Message);
}
finally {
if (stored.FileExists("Temp.utc")) {
stored.DeleteFile ("Temp.utc");
}
}
}
}
The marked line, where I try to move the file, is where I have problems. Everything else works fine, but when I reach that line, it throws an IsolatedStorageException with the message "Operation not permitted". I've looked all over, I've studied MSDN, I've searched all the places I can, but I can't figure out what the problem is. It's probably just something I overlooked, but I'm tearing my hair out here and I could use a bit of help. Thanks.
To expand on archon's comment, the move operation fails because it's inside the using block. Changing the code as follows fixes the problem.
using (IsolatedStorageFileStream isoStream =
new IsolatedStorageFileStream("Temp.utc", FileMode.Create, stored))
{
BinaryFormatter bform = new BinaryFormatter();
bform.Serialize(isoStream, gradebook);
}
stored.DeleteFile("Gradebook.utc");
stored.MoveFile("Temp.utc", "Gradebook.utc");
The reason why it fails is that the using block has the file Temp.utc open, and an open file can't be moved. Once execution leaves the using block, the Dispose method is called on isoStream which causes it to close the open file.
This question already has answers here:
How to copy a file while it is being used by another process
(7 answers)
Closed 9 years ago.
Is it possible to copy a pst file using c# with outlook open?
Here is the code i have got already but it still gives me the error :The process cannot access the file 'filepath' because it is being used by another process.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace outlookPSTCopy
{
class Program
{
static void Main(string[] args)
{
string done = "the file is done copying";//done massage
string copyFrom = args[0];
string copyTo = args[1];
Console.WriteLine(copyTo);
Console.ReadLine();
try
{
//start of test
using (var inputFile = File.Open(copyFrom, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
{
using (var outputFile = new FileStream(copyTo, FileMode.Create))
{
var buffer = new byte[0x10000];
int bytes;
while ((bytes = inputFile.Read(buffer, 0, buffer.Length)) > 0)
{
outputFile.Write(buffer, 0, bytes);
}
}
}
//end of test
//System.IO.File.Copy(copyFrom, copyTo, true);
}
catch (Exception copyError)
{
Console.WriteLine("{0} Second exception caught.", copyError);
}
Console.WriteLine("{0} ", done);
Console.ReadLine();
}
}
}
Thank you for your help!
To create a copy of a file that is locked by another process on Windows, the simplest (and probably only) solution is to use the Volume Shadow Copy Service (VSS).
The Volume Shadow Copy Service is complex and difficult to call from managed code. Fortunately, some fine chaps have created a .NET class library for doing just this. Check out the Alpha VSS project on CodePlex: http://alphavss.codeplex.com.
I am new to C# and have code that will obtain the userName from the LogIn and begin a program in the background if this is the users first time loging into the system. However, today I noticed when running the program and checking my log file that the program skips adding data to the file that is also created on the initial run. Any run after the initial run, the userName is included into the .log file and if the userName does not match what is in the .log file the file is overwritten to include the new userName. Can someone please help me figure out what happened or if I'm missing something?
Thank you in advance.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
namespace User
{
public partial class Form1 : Form
{
public const string dir = #"C:\Numara";
public const string path = dir + #"\Audit.log";
public const string TrackIT = #"C:\Program Files\Numara Software\Numara Track-It!\Track-It! Server\Audit32.exe";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//returns user name
//label1.Text = System.Environment.UserName.ToString();
string userName = System.Environment.UserName; //user name
if (!Directory.Exists(dir))
//directory does not exist
//create it
Directory.CreateDirectory(dir); //creates directory
//by this point directory is created
//now check file
if (!File.Exists(path))
//file does not exist, so create it
File.Create(path);
//Read data from the .log file
string line = System.IO.File.ReadAllText(path);
//if the name of the logged in user
//is the same as the user name of the text file
//then exit program
--------- the debugging stops here and skips to end the program on the first run---------
if (line == userName)
Application.Exit();
else
//clear fields and write new name to file and begin audit
{
//clears fields
using (FileStream stream = new FileStream(#"C:\Numara\Audit.log", FileMode.Create))
{
using (TextWriter writer = new StreamWriter(stream))
{
//writer.Write("");
writer.Write(userName);
}
// writes new name to file
}
StreamReader textIn =
new StreamReader(
new FileStream(path, FileMode.OpenOrCreate, FileAccess.Read));
//begins audit
Process.Start(TrackIT, "/Q");
Application.Exit();
}
}
}
}
File.Create creates a file and returns a FileStream, so it does not close it. Next you want to read it, but it is locked by the File.Create. So exception appears which is not handled and your application quits. Second times the file is already created, so it skips creating and locking it.
So you need to close the file by putting it into using block:
using (File.Create(path))
{
}
Also, you should put all the stuff into try catch blocks to handle IO exceptions - you can never know if one occurs.
You are doing battle with a nasty bug in the 64-bit debugger. Any exceptions in the Load event are swallowed without a diagnostic. The workaround is Project + Properties, Compile tab, Platform Target = x86. Now the debugger will stop at the exception. Fixing it is your next task.
Just in case: avoid catching exceptions that you shouldn't handle. Using try/catch is not typically a real solution. Just a band-aid that spackles the injury.
I would check the value of the userName variable and the line variable on that first run. You could output that to your log file also. My guess is that if the System.Environment.Username variable is empty, you end up in this case where you simply exit.
Another possibility is that you're not properly handling an exception raised from File.Create(). According to the online docs for File.Create(): http://msdn.microsoft.com/en-us/library/aa328775(v=vs.71).aspx there are 7 different exceptions that are thrown. Try catching and logging these exceptions to see if this could be the case.
I've apparently worked myself into a bad coding habit. Here is an example of the code I've been writing:
using(StreamReader sr = new StreamReader(File.Open("somefile.txt", FileMode.Open)))
{
//read file
}
File.Move("somefile.txt", "somefile.bak"); //can't move, get exception that I the file is open
I thought that because the using clause explicitly called Close() and Dispose() on the StreamReader that the FileStream would be closed as well.
The only way I could fix the problem I was having was by changing the above block to this:
using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
{
using(StreamReader sr = new StreamReader(fs))
{
//read file
}
}
File.Move("somefile.txt", "somefile.bak"); // can move file with no errors
Should closing the StreamReader by disposing in the first block also close the underlying FileStream? Or, was I mistaken?
Edit
I decided to post the actual offending block of code, to see if we can get to the bottom of this. I am just curious now.
I thought I had a problem in the using clause, so I expanded everything out, and it still can't copy, every time. I create the file in this method call, so I don't think anything else has a handle open on the file. I've also verified that the strings returned from the Path.Combine calls are correct.
private static void GenerateFiles(List<Credit> credits)
{
Account i;
string creditFile = Path.Combine(Settings.CreditLocalPath, DateTime.Now.ToString("MMddyy-hhmmss") + ".credits");
StreamWriter creditsFile = new StreamWriter(File.Open(creditFile, FileMode.Create));
creditsFile.WriteLine("code\inc");
foreach (Credit c in credits)
{
if (DataAccessLayer.AccountExists(i))
{
string tpsAuth = DataAccessLayer.GetAuthCode(i.Pin);
creditsFile.WriteLine(String.Format("{0}{1}\t{2:0.00}", i.AuthCode, i.Pin, c.CreditAmount));
}
else
{
c.Error = true;
c.ErrorMessage = "NO ACCOUNT";
}
DataAccessLayer.AddCredit(c);
}
creditsFile.Close();
creditsFile.Dispose();
string dest = Path.Combine(Settings.CreditArchivePath, Path.GetFileName(creditFile));
File.Move(creditFile,dest);
//File.Delete(errorFile);
}
Yes, StreamReader.Dispose closes the underlying stream (for all public ways of creating one). However, there's a nicer alternative:
using (TextReader reader = File.OpenText("file.txt"))
{
}
This has the added benefit that it opens the underlying stream with a hint to Windows that you'll be accessing it sequentially.
Here's a test app which shows the first version working for me. I'm not trying to say that's proof of anything in particular - but I'd love to know how well it works for you.
using System;
using System.IO;
class Program
{
public static void Main(string[] args)
{
for (int i=0; i < 1000; i++)
{
using(StreamReader sr = new StreamReader
(File.Open("somefile.txt", FileMode.Open)))
{
Console.WriteLine(sr.ReadLine());
}
File.Move("somefile.txt", "somefile.bak");
File.Move("somefile.bak", "somefile.txt");
}
}
}
If that works, it suggests that it's something to do with what you do while reading...
And now here's a shortened version of your edited question code - which again works fine for me, even on a network share. Note that I've changed FileMode.Create to FileMode.CreateNew - as otherwise there could still have been an app with a handle on the old file, potentially. Does this work for you?
using System;
using System.IO;
public class Test
{
static void Main()
{
StreamWriter creditsFile = new StreamWriter(File.Open("test.txt",
FileMode.CreateNew));
creditsFile.WriteLine("code\\inc");
creditsFile.Close();
creditsFile.Dispose();
File.Move("test.txt", "test2.txt");
}
}
Note - your using blocks do not need to be nested in their own blocks - they can be sequential, as in:
using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
using(StreamReader sr = new StreamReader(fs))
{
//read file
}
The order of disposal in this case is still the same as the nested blocks (ie, the StreamReader will still dispose before the FileStream in this case).
I would try to use FileInfo.Open() and FileInfo.MoveTo() instead of File.Open() and File.Move(). You could also try to use FileInfo.OpenText(). But these are just suggestions.
Is there any possibility that something else has a lock to somefile.txt?
A simple check from a local (to the file) cmd line
net files
may well give you some clues if anything else has a lock.
Alternatively you can get something like FileMon to take even more details, and check that your app is releasing properly.
Since this doesn't seem to be a coding issue, I'm going to put my syadmin hat on and offer a few suggestions.
Virus scanner on either the client or server that's scanning the file as it's created.
Windows opportunistic locking has a habit of screwing things up on network shares. I recall it being mostly an issue with multiple read/write clients with flat file databases, but caching could certainly explain your problem.
Windows file open cache. I'm not sure if this is still a problem in Win2K or not, but FileMon would tell you.
Edit: If you can catch it in the act from the server machine, then Sysinternal's Handle will tell you what has it open.