I am trying to add a logfile to a program I am making, but when I tell the main thread to exit (using Application.ExitThread()), logstrmWriter is suddenly null before it ever gets there. This is a very simple script.
private static FileStream appLogStream;
internal static string logFile;
internal static StreamWriter logstrmWriter;
public static void Main()
{
logFile = Application.StartupPath + #"\Archiver.log";
appLogStream = new FileStream(logFile, FileMode.Append, FileAccess.Write, FileShare.Read);
TextWriter logtxtWriter = Console.Out;
StreamWriter logstrmWriter = new StreamWriter(appLogStream);
if(!console) Console.SetOut(logstrmWriter);
Application.ApplicationExit += new EventHandler(OnApplicationExit);
Application.Run();
}
internal static void OnApplicationExit(object sender, EventArgs e)
{
active = false; Console.WriteLine("Main thread is shutting down. Sending Interrupt...");
Archiver.Stop(); Console.WriteLine("Shutdown. Log and Exit");
Console.WriteLine();
logstrmWriter.Flush();
logstrmWriter.Close();
logstrmWriter.Dispose();
}
You're creating a local variable that hides the static variable in question. As such, you never initialize logstrmWriter at all.
TextWriter logtxtWriter = Console.Out;
/* StreamWriter */ logstrmWriter = new StreamWriter(appLogStream); // Remove the redeclaration here!
if(!console) Console.SetOut(logstrmWriter);
Related
I need to monitor when a file (*.wav) is being executed.
I know about the filesystemwatcher class. However does this class notify when a file is being used? I also came across Monitor when an exe is launched. While I realise that this has to do with an exe, is there a way to be notified that a wav file has been executed?
No, you can't get an Event when non executable files such as mp3, wav, txt and etc are opened.
But actually can check if file is opened write now...
static void Main(string[] args)
{
using (BackgroundWorker bw = new BackgroundWorker())
{
bw.DoWork += Bw_DoWork;
bw.RunWorkerAsync();
}
Console.WriteLine("Press Q to exit");
while (Console.ReadKey(true).Key!=ConsoleKey.Q){}
}
private static bool[] opened;
private static void Bw_DoWork(object sender, DoWorkEventArgs e)
{
var files = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.mp3");
opened = new bool[files.Length];
while (true)
for (int i = 0; i < files.Length; i++)
try
{
using (var fs = File.Open(files[i], FileMode.Open, FileAccess.Read, FileShare.None))
opened[i] = false;
}
catch{ opened[i] = true; }
}
P.S. I know it's ugly :D
I think it's pretty obvious in the title ; I want to copy a file without waiting for the result.
Functionaly I want this :
static void Main(string[] args)
{
string strCmdText = #"/C xcopy c:\users\florian\desktop\mytestfile.fil p:\";
System.Diagnostics.Process.Start("CMD.exe", strCmdText);
Console.WriteLine("Finished !");
}
Basically my main thread is released after few milliseconds.
I try to do like this :
static void Main(string[] args)
{
var t = Task.Run(() => Copy(#"c:\Users\florian\Desktop\mytestfile.fil", "p:"));
}
private static void Copy(string source, string destination)
{
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
SourceStream.CopyToAsync(DestinationStream);
}
}
}
My mytestfile.fil is created in my destination folder but its size is 0kb.
Regards,
Basically my main thread is released after few milliseconds. I try to do like this
You must keep the process alive somehow. The easiest way to do this - if you actually have to do the file copy on a thread of its own - is to execute your Copy method on a foreground thread:
class Program
{
static void Main(string[] args)
{
System.Threading.Thread thread = new System.Threading.Thread(()=> Copy(#"c:\Users\florian\Desktop\mytestfile.fil", "p:"));
thread.Start();
}
private static void Copy(string source, string destination)
{
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
SourceStream.CopyTo(DestinationStream);
}
}
}
}
...or you could execute it on the main thread since your application doesn't seem to anything else:
class Program
{
static void Main(string[] args)
{
string source = #"c:\Users\florian\Desktop\mytestfile.fil";
string destination = "p";
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
SourceStream.CopyTo(DestinationStream);
}
}
}
}
A third option is to make your method async and wait for it to complete synchronously in the Main method:
class Program
{
static void Main(string[] args)
{
CopyAsync(#"c:\Users\florian\Desktop\mytestfile.fil", "p:").Wait();
}
private static async Task CopyAsync(string source, string destination)
{
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
await SourceStream.CopyToAsync(DestinationStream);
}
}
}
}
Note that you should not use the asyncronous CopyToAsync method unless you actiually await it. Don't mix synchronous and asynchronous code :)
OK more than one error.
Your program exits before the copy completes. you need something like:
CopyToAsync was not awaited
class Program
{
private static void Main(string[] args)
{
var source = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
source.Cancel();
};
try
{
MainAsync(args, source.Token).GetAwaiter().GetResult();
return;
}
catch (OperationCanceledException)
{
return;
}
}
static async Task MainAsync(string[] args, CancellationToken token)
{
var t = Task.Run(() => Copy(#"c:\test.txt", #"c:\dest\"));
Console.WriteLine("doing more stuff while copying");
await t;
Console.WriteLine("Finished !");
}
private static void Copy(string source, string destination)
{
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
SourceStream.CopyTo(DestinationStream);
}
}
}
}
Your Main method returns before the Task has completed, so your application ends.
It seems like this might be an instance of the XY problem.
Keep in mind that the OS/framework is basically giving your process its own "space" to run in, so the following:
static void Main(string[] args)
{
var t = Task.Run(() => Copy(#"c:\Users\florian\Desktop\mytestfile.fil", "p:"));
}
private static void Copy(string source, string destination)
{
using (FileStream SourceStream = File.Open(source, FileMode.Open))
{
using (FileStream DestinationStream = File.Create(destination + source.Substring(source.LastIndexOf('\\'))))
{
SourceStream.CopyToAsync(DestinationStream);
}
}
}
is no different in terms of performance than just doing
static void Main(string[] args)
{
Copy(#"c:\Users\florian\Desktop\mytestfile.fil", "p:");
}
Since your console application fundamentally isn't doing anything other than copying the file, the extra thread just adds overhead.
Also, if you're using asynchronous operations inside the Copy method, you should declare your method async Task rather than void because otherwise you can't use the await keyword inside the Copy method or wait for the Copy method to complete elsewhere in code. So:
private static async Task Copy(string source, string destination)
As written, this has a blatant race condition and probably won't work correctly because DestinationStream and SourceStream may be disposed of before SourceStream.CopyToAsync(DestinationStream) has actually finished. You need to do
await SourceStream.CopyToAsync(DestinationStream);
inside your method to prevent this.
If you're launching the Copy operation with
System.Diagnostics.Process.Start(...);
you're already effectively running this asynchronously from the perspective of the program that launched it because the program that launched it doesn't wait for the process to complete before it continues. Incidentally, I assume that that console application will do something other than just launch the process, correct? (If not, it seems a little redundant).
I have written a windows service that periodically calls an ExcelReader.exe( this exe reads data from an excel). Now the problem is that when i'm running ExcelReader.exe directly it is able to read data from excel but when i am calling it through windows service, i was able to call but ReadExcel was not performing full job. Since my service does not have any GUI and even ExcelReader.exe is console program do i need to enable service to "interact with desktop"
Here is my code:
protected override void OnStart(string[] args)
{
AddToFile(path, "starting service");
//set time interval for watch
timer.Interval = 6 * 1000;
timer.Enabled = true;
// Add handler for Elapsed event
timer.Elapsed += new System.Timers.ElapsedEventHandler(OnElapsedTime);
}
protected override void OnStop()
{
timer.Enabled = false;
AddToFile(path, "stop service");
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
AddToFile(path,"Add another entry");
Process p = new Process();
p.StartInfo.FileName = #"D:\ExcelReader.exe";
p.Start();
}
Here is ExcelReader code:
namespace ExcelReader
{
class Program
{
public static string path = #"D:\\Excel Reader log .txt";
public static BindingList<myTeam> TeamList = new BindingList<myTeam>();
static void Main(string[] args)
{
write(path, "console program");
readexcel();
}
public static void readexcel()
{
MyExcel dailystatus = new MyExcel();
IList<myTeam> datasource = (BindingList<myTeam>) TeamList;
MyExcel.InitializeExcel();
datasource = MyExcel.ReadMyExcel();
foreach (myTeam member in datasource)
{
string memberdetails = member.Name + " " + member.TaskPerformedToday + " " + member.Progress;
write(path, memberdetails);
//(path, memberdetails);
}
//CloseExcel();
}
public static void write(string path, string contents)
{
//set up a filestream
FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);
//set up a streamwriter for adding text
StreamWriter sw = new StreamWriter(fs);
//find the end of the underlying filestream
sw.BaseStream.Seek(0, SeekOrigin.End);
//add the text
sw.WriteLine(contents);
//add the text to the underlying filestream
sw.Flush();
//close the writer
sw.Close();
}
}
}
output of ExcelReader.exe (when executed directly):
console program
Name Task Performed Today Progress
sanj windows service not completed
kumar service completed
output when service call the same function:
starting service
console program
so why is it that windows service is unable to perform all ExcelReader.exe instructions.
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
please tell me how to lock file in c#
Thanks
Simply open it exclusively:
using (FileStream fs =
File.Open("MyFile.txt", FileMode.Open, FileAccess.Read, FileShare.None))
{
// use fs
}
Ref.
Update: In response to comment from poster: According to the online MSDN doco, File.Open is supported in .Net Compact Framework 1.0 and 2.0.
FileShare.None would throw a "System.IO.IOException" error if another thread is trying to access the file.
You could use some function using try/catch to wait for the file to be released. Example here.
Or you could use a lock statement with some "dummy" variable before accessing the write function:
// The Dummy Lock
public static List<int> DummyLock = new List<int>();
static void Main(string[] args)
{
MultipleFileWriting();
Console.ReadLine();
}
// Create two threads
private static void MultipleFileWriting()
{
BackgroundWorker thread1 = new BackgroundWorker();
BackgroundWorker thread2 = new BackgroundWorker();
thread1.DoWork += Thread1_DoWork;
thread2.DoWork += Thread2_DoWork;
thread1.RunWorkerAsync();
thread2.RunWorkerAsync();
}
// Thread 1 writes to file (and also to console)
private static void Thread1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 20; i++)
{
lock (DummyLock)
{
Console.WriteLine(DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss") + " - 3");
AddLog(1);
}
}
}
// Thread 2 writes to file (and also to console)
private static void Thread2_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 20; i++)
{
lock (DummyLock)
{
Console.WriteLine(DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss") + " - 4");
AddLog(2);
}
}
}
private static void AddLog(int num)
{
string logFile = Path.Combine(Environment.CurrentDirectory, "Log.txt");
string timestamp = DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss");
using (FileStream fs = new FileStream(logFile, FileMode.Append,
FileAccess.Write, FileShare.None))
{
using (StreamWriter sr = new StreamWriter(fs))
{
sr.WriteLine(timestamp + ": " + num);
}
}
}
You can also use the "lock" statement in the actual writing function itself (i.e. inside AddLog) instead of in the background worker's functions.