FileSystemWatcher: System.IO.IOException ("File used by another process") - c#

Currently i'm working on an application, that should watch a specific directory for changes (say a new file was created) and then in turn upload the file to Sharepoint. Thatfore i'm using the FileSystemWatcher class which throws an event with the path to the created file, which in turn i use in another method to upload the file. The problem is: While in debug mode in Visual Studio i realized that the first file i create in the watched directory gets uploaded perfectly, even if i drag multiple files into the directory at once all are uploaded, BUT when i do it one file after another i get an exception that the second file is already in use. So i drag File1.txt into the directory, it works, but then, when i drag file2.txt into the directory right after i get a System.IO.IOException while trying to create a filestream to upload to Sharepoint telling me that file2.txt is in use by another process.
The code for the FileSystemWatcher:
public void StartWatcher()
{
FileSystemWatcher fsw = new FileSystemWatcher(this.path);
fsw.IncludeSubdirectories = true;
fsw.EnableRaisingEvents = true;
fsw.Created += new FileSystemEventHandler(CreateFile);
try
{
while (true)
{
fsw.WaitForChanged(WatcherChangeTypes.All);
}
}
catch
{ }
fsw.EnableRaisingEvents = false;
}
The CreateFile() method called by
fsw.Created += new FileSystemEventHandler(CreateFile);
looks like this:
private void CreateFile(object sender, FileSystemEventArgs e)
{
path = String.Format(e.FullPath);
filename = Path.GetFileName(path);
Stream fs = File.OpenRead(#path);
SPAPI spobj = new SPAPI();
spobj.SPUploader(fs, filename);
fs.Close();
}
The exception is thrown at
Stream fs = File.OpenRead(#path);
BUT only when a second file is dragged into the directory after the first one. The strange thing is that not the first file is in use, but the second one that i want to open as a stream. So it's not the stream that is still open and causing the exception. It seems that the second file is in use by the FileSystemWatcher. But why does the first file work just fine but the exception is just thrown when a second file is dragged into the directory?

You can modify and use like this. I hope this helps you
private void CreateFile(object sender, FileSystemEventArgs e)
{
int until = 5;
int i = 0;
bool success = false;
while (!success && i < until)
{
try
{
path = String.Format(e.FullPath);
filename = Path.GetFileName(path);
using (Stream fs = File.OpenRead(#path);)
{
SPAPI spobj = new SPAPI();
spobj.SPUploader(fs, filename);
}
success = true;
}
catch
{
i++;
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
}

Related

How to create a basic package to store images?

How can I create a basic package to store images, like a zip file?
All I want to do is to store 20000 images inside one package. It will be easier for my hard disk.
Also, I need to be able to enter and exit from that package, read/write , add/remove files, using C# code.
Another file format is .iso that is close to what I want, but is complicated to operate with.
I want something very basic, not complicated. Basic as a library if possible.
Is there such a thing?
If you decide to go with the virtual hard disk the steps are the following:
In Computer management right click Disk management and in the local menu click 'Create VHD'. Create a virtual hard disk with the parameters you prefer. I recommend the .vhdx and dynamically expanding flavor. After this you have a mounted, un-initialized, un formatted hard drive.
Prepare it with the necessary and usual steps. As the result you will have a hard drive with an assigned drive letter.
Use it as any hard drive you have.
After reboot it will not be automatically mounted, you have to do it manually in Disk Management or use a scheduled task to mount the drive. Here's the script for that: https://gallery.technet.microsoft.com/scriptcenter/How-to-automatically-mount-d623ce34
You can unmount it at Disk Management as well.
You can copy the file yourdiskname.vhd(x) to other computers and use it.
Thank you all for your input
It helped me decide and it direction me to this answer I find after many web search battles.
I find a practical solution, but not that efficient as I want it.
Is moving slow-ish when cycling the images from inside a zip file, because it is unpacking each of them. I must re-think the code and unzip all into a stream or some lists. I will see. For now, is working and I am very happy :)
Here is the result I came up with:
//My code so far - not very efficient but is working.
using Ionic.Zip;
using Ionic.Zlib;
string zipPath = "0Images.zip";
void CountZipFiles()
{
using (ZipFile zip = new ZipFile(zipPath))
{
totalzipFiles = zip.Count-1;
}
}
Image emptyImage = Image.FromFile("emptyFemale.jpg");
void ReadZipImage()
{
using (ZipFile zip = new ZipFile(zipPath))
{
MemoryStream tempS = new MemoryStream();
for (int i = 0; i < zip.Count; i++)
{
if (i == countMyZipImages)
{
label1.Text = zip[i].FileName;
if (zip[i].FileName.Contains(".niet"))
{
pictureBox1.Image = emptyImage;
}
else
{
zip[i].Extract(tempS);
pictureBox1.Image = Image.FromStream(tempS);
}
}
}
}
}
int totalzipFiles = 0, countMyZipImages = 0;
private void button2_Click(object sender, EventArgs e)
{
countMyZipImages--;
if (countMyZipImages < 0) countMyZipImages = totalzipFiles;
textBox1.Text = countMyZipImages.ToString();
ReadZipImage();
}
private void button3_Click(object sender, EventArgs e)
{
countMyZipImages++;
if (countMyZipImages > totalzipFiles) countMyZipImages = 0;
textBox1.Text = countMyZipImages.ToString();
ReadZipImage();
}
// and this is a HELP file for later use - hopefully will help others too. ;)
How to add Ionic.Zip.dll in c#.net project and use it:
To add a reference, right click (in Solution Explorer on your project) Reference folder and select Add Reference.
Then browse and add the file Ionic.Zip.dll
//Important to add this using's too after referencing.
using Ionic.Zip;
using Ionic.Zlib;
private void CreateZIP_Click(object sender, EventArgs e)
{
using (ZipFile zip = new ZipFile())
{
// add this map file into the "images" directory in the zip archive
zip.AddFile("c:\\images\\personal\\7440-N49th.png", "images");
// add the report into a different directory named "files" in the archive
zip.AddFile("c:\\Reports\\2008-Regional-Sales-Report.pdf", "files");
zip.AddFile("ReadMe.txt");
zip.Save("MyZipFile.zip");
Exception ex = new Exception();
label1.Text = ex.Message;
}
}
//You can extract to a stream, or a fizical file !
private void button5_Click(object sender, EventArgs e)
{
using (ZipFile zip = new ZipFile("0Images.zip"))
{
MemoryStream tempS = new MemoryStream(); //stream
//{
foreach (ZipEntry ze in zip) //foreach
{
// check if you want to extract the image.name
if (ze.FileName == "00002 Riley Reid.jpg")
{
ze.Extract(tempS);
pictureBox1.Image = Image.FromStream(tempS);
}
}
//OR
for (int i = 0; i < zip.Count; i++) //for
{
if (i == countMyZipImages)
{
zip[i].Extract(tempS);
pictureBox1.Image = Image.FromStream(tempS);
}
}
//}
}
}
This is a free library I find on internet! I like it because is very little - 435kb. Here is a link I find for others if they want to use it. Dropbox - Ionic.Zip.dll[^]

System.IO.IOException: 'The process cannot access the file '#.txt' because it is being used by another process.'

I am new to programming and I have a question. If I have two functions, one creates a text file and writes into it, while the other opens the same text file and reads from it.
The error I get is:
System.IO.IOException: 'The process cannot access the file '#.txt'
because it is being used by another process.'
I have tried setting seperate timers to each of the functions but it still does not work. I think the best way would be that the function two does not start until function one ends.
Can you help me achieve this?
Thank you very much!
Mike
Source code:
public Form1() {
InitializeComponent();
System.Timers.Timer timerButtona1 = new System.Timers.Timer();
timerButtona1.Elapsed += new ElapsedEventHandler(tickTimera1);
timerButtona1.Interval = 3003;
timerButtona1.Enabled = true;
}
private async void tickTimera1(object source, ElapsedEventArgs e) {
function1();
function2();
}
void function1() {
List<string> linki = new List<string>();
linki.Add("https://link1.net/");
linki.Add("https://link2.net/");
linki.Add("https://link3.net/");
List<string> fileNames = new List<string>();
fileNames.Add("name1");
fileNames.Add("name2");
fileNames.Add("name3");
for (int x = 0; x < fileNames.Count; x++) {
GET(linki[x], fileNames[x]);
//System.Threading.Thread.Sleep(6000);
}
}
async void GET(string link, string fileName) {
var ODGOVOR = await PRENOS_PODATKOV.GetStringAsync(link);
File.WriteAllText(#"C:\Users\...\" + fileName + ".txt", ODGOVOR);
}
void function2() {
string originalText = File.ReadAllText(#"C:\Users\...\fileName.txt", Encoding.Default);
dynamic modifiedText = JsonConvert.DeserializeObject(originalText);
//then i then i read from the same text files and use some data from it..
}
You will have to close the file after editing it.
var myFile = File.Create(myPath);
//myPath = "C:\file.txt"
myFile.Close();
//closes the text file for eg. file.txt
//You can write your reading functions now..
After closing it you can again use it(for reading)
The issue is sometimes file locks don't get released immediately after they are closed.
You can try run a loop to read the file. Inside the loop put a try catch statement and if the file reads successfully break from the loop. Otherwise, wait a few milliseconds and try to read the file again:
string originalText = null;
while (true)
{
try
{
originalText = File.ReadAllText(#"C:\Users\...\fileName.txt", Encoding.Default);
break;
}
catch
{
System.Threading.Thread.Sleep(100);
}
}
after writing your text file, you should close it first before proceeding to your second function:
var myFile = File.Create(myPath);
//some other operations here like writing into the text file
myFile.Close(); //close text file
//call your 2nd function here
Just to elaborate:
public void Start() {
string filename = "myFile.txt";
CreateFile(filename); //call your create textfile method
ReadFile(filename); //call read file method
}
public void CreateFile(string filename) {
var myFile = File.Create(myPath); //create file
//some other operations here like writing into the text file
myFile.Close(); //close text file
}
public void ReadFile(string filename) {
string text;
var fileStream = new FileStream(filename, FileMode.Open,
FileAccess.Read); //open text file
//vvv read text file (or however you implement it like here vvv
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
text = streamReader.ReadToEnd();
}
//finally, close text file
fileStream.Close();
}
The point is, you have to close the FileStream after you are done with any operations with your file. You can do this via myFileStream.Close().
Moreover, File.Create(filename) returns a FileStream object which you can then Close().
Actually this is not a problem of closing/disposing the stream, File.WriteAllText and File.ReadAllText does that internally.
The issue is because a wrong use of the async/await pattern.
GET is async but never awaited, thus causing function1 to finish and move on to function2 before all content was actually written to the file.
The way it is written GET is not awaitable because it is async void which should never be used unless you're dealing with event or really know what you're doing.
So, either remove the use of async/await completely or be async all the way:
Change GET to be awaitable:
async Task GET(string link, string fileName)
await it in the now async function1:
async Task function1()
{
...
for (int x = 0; x < fileNames.Count; x++)
{
await GET(linki[x], fileNames[x]);
//System.Threading.Thread.Sleep(6000);
}
...
await function1 in the Elapsed event:
private async void tickTimera1(object source, ElapsedEventArgs e)
{
await function1();
function2();
}
Create a file and then close it. After can save data into that file.
I did as below.
if (!File.Exists(filePath))
{
File.Create(filePath).Close();
}
File.WriteAllText(filePath, saveDataString)
In one of the unit tests, I had to create a temp file and then remove it after, and I was getting the above error.
None of the answers worked.
Solution that worked was:
var path = $"temp.{extension}";
using (File.Create(path))
{
}
File.Delete(path);

How to monitor a logfile that seems to be open all the time (much like notepad++ does)?

I'm trying to build a small program to monitor my pfirewall.log, but I can't seem to open it.
I found quite many (simple) answers, that all kinda say
// use FilesystemWatcher
// open FileStream
// read from last position to end
// output new lines
The problem here is: The file seems to always be opened by another process already. I guess that's the windows process writing to the file, since it's getting written to all the time, as Notepad++ shows me.
Which means, Notepad++ can for some reason do what I can not: Read the file despite it being opened already.
I initialize my monitor in the constructor:
public FirewallLogMonitor(string path)
{
if (!File.Exists(path))
throw new FileNotFoundException("Logfile not found");
this.file = path;
this.lastPosition = 0;
this.monitor = new FileSystemWatcher(Path.GetDirectoryName(path), Path.GetFileName(path));
this.monitor.NotifyFilter = NotifyFilters.Size;
}
And try to read the file on monitor.Changed event:
private void LogFileChanged(object sender, FileSystemEventArgs e)
{
using (FileStream stream = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (StreamReader reader = new StreamReader(stream))
{
stream.Seek(this.lastPosition, SeekOrigin.Begin);
var newLines = reader.ReadToEnd();
this.lastPosition = stream.Length;
var filteredLines = filterLines(newLines);
if (filteredLines.Count > 0)
NewLinesAvailable(this, filteredLines);
}
}
It always throws the IOException on new FileStream(...) to tell me the file is already in use.
Since Notepad++ does it, there has to be a way I can do it too, right?
**Edit: ** A button does this:
public void StartLogging()
{
this.IsRunning = true;
this.monitor.Changed += LogFileChanged;
this.monitor.EnableRaisingEvents = true;
}
**Edit2: ** This is not a duplicate of FileMode and FileAccess and IOException: The process cannot access the file 'filename' because it is being used by another process, since that one assumes I have control over the writing process. Will try the other suggestions, and report back with results.
If i understand your question you can use the notepad++ itself with a plugin to monitor you need to go to:
plugins -> Document Moniter -> Start to monitor
if you dont have this plugin you can download it here:
http://sourceforge.net/projects/npp-plugins/files/DocMonitor/

The process cannot access the file 'C:\PCLtoMove\print.pcl' because it is being used by another process. Windows service

I have a folder named PCLtoMove. I have applied a filewatcherSystem in this folder to move files from this folder to another folder. first time when I start windows service It works fine but from next time it gives exception-
The process cannot access the file 'C:\PCLtoMove\fileName.pcl' because it is being used by another process.
my code to move file is -
private void SavionFileWatcher_Created(object sender, System.IO.FileSystemEventArgs e)
{
try
{
string sourcePath = e.FullPath;
string destination = ConfigurationManager.AppSettings["destination"] + e.Name;
File.Move(sourcePath, destination);
}
catch (Exception ex)
{
this.EventLog.WriteEntry(ex.Message, EventLogEntryType.Information);
}
}
please tell me whats wrong I am doing.
I got the solution by adding following code to the above code. Its confirms that the file is completely moved or created.
FileStream fs = new FileStream(sourcePath, FileMode.Open, FileAccess.ReadWrite);
fs.ReadByte();
fs.Seek(0, SeekOrigin.Begin);
fs.Dispose();
File.Move(sourcePath,destination);
break;

File access error with FileSystemWatcher

I am using File Watcher (.NET) and always getting an below error-
file is being used by another process.
The above error only comes in Network sharing, i.e. Watch Directory is shared and if someone puts the file into that directory then only this error occurs. It works fine when I put the file from my m/c to watch directory(locally).
This is how my below code looks, the error comes in first line itself. I have tried all the solutions given on net but nothing seems to working. The only solution worked when I put Thread.Sleep(500), but after that it is unable to pick the next file. Any suggestion would be a great help.
try
{
using (Stream stream = File.Open(xmlPath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
XmlTextReader xmlTextReader = new XmlTextReader(stream);
document = XDocument.Load(xmlTextReader);
........ // my code
xmlTextReader.Close();
stream.Close();
}
}
catch (Exception exception)
{
EventLog.WriteEntry("Application", exception.ToString(), EventLogEntryType.Error);
}
I think you will find that the the file is not acessable hence why the wait works..
Take a look at this code and see if this helps...
// Consider having a List<String> named _changedFiles
private void OnChanged(object source, FileSystemEventArgs e)
{
lock (_changedFiles)
{
if (_changedFiles.Contains(e.FullPath))
{
return;
}
}
// do your stuff
System.Timers.Timer timer = new Timer(1000) { AutoReset = false };
timer.Elapsed += (timerElapsedSender, timerElapsedArgs) =>
{
lock (_changedFiles)
{
_changedFiles.Remove(e.FullPath);
}
};
timer.Start();
}
from:
FileSystemWatcher Changed event is raised twice

Categories