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.
Related
I'm working in my own PDF Reader using C# & Patagames/PDFium library and I am able to open files using "OpenFileDialog" and show them on the screen. However, due requirements of the boss I am not allowed to have any buttons in the screen. All we want is to click the any .PDF file (For example, in this route: C:\Users\Adaptabilidad\Desktop\Test.pdf) and launch it & show the PDF document directly, without looking for the directory of the file. I've set my ".exe" as default app, although, the PDF Reader is executed no PDF file is displayed.
I've tried Application.ExecutablePath, Application.StartUpPath after initializing the component and I'm still getting the route of my PDF reader executable (.Exe) but I need to know what the file to be open is (filepath).
How can I get the information about the .pdf file (directory can vary) that is launching my app? You can see my code below if helps.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Patagames;
using System.IO;
namespace aPDF
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "PDF Files (*.pdf)|*.pdf";
if (dialog.ShowDialog() == DialogResult.OK)
{
openfile(dialog.FileName);
}
}
public void openfile(string filepath)
{
byte[] bytes = System.IO.File.ReadAllBytes(filepath);
var stream = new MemoryStream(bytes);
Patagames.Pdf.Net.PdfDocument pdfDocument = Patagames.Pdf.Net.PdfDocument.Load(stream);
pdfViewer1.Document = pdfDocument;
}
}
}
Updates:
I've found a way. One of you guys that commented allowed me to find out how to do it.
What I used is the following sentence in my Program.cs:
public static string[] cmdLine = Environment.GetCommandLineArgs();
public static string cmd = cmdLine[1];
Then, y use "cmd" as filepath.
Why? Environment.GetCommandLineArgs(); returns 2 values, the .exe you're executing (your program) & as second value the file that you've used in order to launch that .exe.
That's it. Thank you for your answers.
I am trying to write a log file, but it constantly says "File being used by another process". Here's my code:
//_logFile = "system.log"
if(!File.Exists(Path.Combine("logs", _logFile)))
{
File.Create(Path.Combine("logs", _logFile)).Close();
sw = File.AppendText(Path.Combine("logs", _logFile));
}
else
{
sw = File.AppendText(Path.Combine("logs", _logFile));
}
When I run it, it points to the File.Create(Path.Combine("logs", _logFile)).Close() line and gives me the error.
Edit:
I changed if(!File.Exists(_logFile)) to if(!File.Exists(Path.Combine("logs", _logFile))) but I still get the same error.
Assuming you don't need access to this stream outside the context of this method, I'd refactor your code to this:
var filePath = Path.Combine("logs", _logFile);
using (var sw = File.AppendText(filePath))
{
//Do whatever writing to stream I want.
sw.WriteLine(DateTime.Now.ToString() + ": test log entry");
}
This way, no matter what happens inside the using block, you know the file will be closed so you can use it again later.
Note that File.AppendText will create the file if it doesn't already exist, so File.Create is not needed.
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.
How do I open (using c#) a file that is already open (in MS Word, for instance)? I thought if I open the file for read access e.g.
FileStream f= new FileStream('filename', FileMode.Open, FileAccess.ReadWrite);
I should succeed, but I get an exception:
"the process cannot access the file
because it is locked ..."
I know there must be a way to read the file irrespective of any locks placed on it, because I can use windows explorer to copy the file or open it using another program like Notepad, even while it is open in WORD.
However, it seems none of the File IO classes in C# allows me to do this. Why?
You want to set FileAccess=Read and FileShare=ReadWrite. Here is a great article on this (along with an explanation of why):
http://coding.infoconex.com/post/2009/04/How-do-I-open-a-file-that-is-in-use-in-C.aspx
Your code is using the FileAccess.Read*Write* flag. Try just Read.
I know this is an old post. But I needed this and I think this answer can help others.
Copying a locked file the way the explorer does it.
Try using this extension method to get a copy of the locked file.
Usage example
private static void Main(string[] args)
{
try
{
// Locked File
var lockedFile = #"C:\Users\username\Documents\test.ext";
// Lets copy this locked file and read the contents
var unlockedCopy = new
FileInfo(lockedFile).CopyLocked(#"C:\Users\username\Documents\test-copy.ext");
// Open file with default app to show we can read the info.
Process.Start(unlockedCopy);
}
catch (Exception ex)
{
Trace.TraceError(ex.Message);
}
}
Extension method
internal static class LockedFiles
{
/// <summary>
/// Makes a copy of a file that was locked for usage in an other host application.
/// </summary>
/// <returns> String with path to the file. </returns>
public static string CopyLocked(this FileInfo sourceFile, string copyTartget = null)
{
if (sourceFile is null)
throw new ArgumentNullException(nameof(sourceFile));
if (!sourceFile.Exists)
throw new InvalidOperationException($"Parameter {nameof(sourceFile)}: File should already exist!");
if (string.IsNullOrWhiteSpace(copyTartget))
copyTartget = Path.GetTempFileName();
using (var inputFile = new FileStream(sourceFile.FullName, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite))
using (var outputFile = new FileStream(copyTartget, FileMode.Create))
inputFile.CopyTo(outputFile, 0x10000);
return copyTartget;
}
}
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.