Click here to Skip to main content
15,887,083 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
My program consists of the following steps:
1. read in any new image from a source folder
2. process image (detect objects and deskew them)
3. save deskewed object images in a target folder
...repeat

The idea is that while scanning stamps the program outputs each stamp individually or grouped if the stamps are clustered. The user should be able to continuously make scans while they are being processed.

The program behaves in three distinct ways, based on three ways of detecting new images in the target folder. In practice only the third way will be used. The first two can hopefully help explain what is happening and why.

1. Drag-and-drop
All works fine when drag-and-dropping an image into the folder manually; I can do this indefinitely and the outputs are correct.

2. Copy paste
When copy and pasting an image locally in the target folder the program halts immediately, showing following exception:
System.IO.IOException: 'Unable to access the file xxx because it is being used by another process.'

This same exception occurs when copy-pasting images within the target folder.

3. Output from scan program
I use the ScanSnap SV600 which saves unprocessed scans of stamps in the target folder. Now here comes the case that baffles me: my processing program alternates in its behaviour. The first scan always succeeds every time I start the program in Debug mode. But reading in the subsequent scan within that same run of the processing program fails in the case when the previous Debug session succeeded. In other words: one out of two times the program behaves as desired. And the other times it halts on the second scan, giving me the above error.

To detect new images I use:
C#
var fileSystemWatcher = new FileSystemWatcher(@inputDir)
{
    Filter = "*.jpg",
    NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite,
    EnableRaisingEvents = true
};
fileSystemWatcher.Created += new FileSystemEventHandler(OnFileCreated);


What I have tried:

Furthermore this is part of the code before processing begins. It is not the most beautiful and feels a bit 'hacky' using `Thread.Sleep()`. Maybe here is a clue?

C#
private void OnFileCreated(object sender, FileSystemEventArgs e)
{
    sw.Restart();
    string imagePath = e.FullPath;
    inputFiles.AddToQ(imagePath);
    Console.WriteLine("{0} is queued.", e.FullPath);

    int number = 0;
    if (!int.TryParse(setCluster.Text.Trim(), out number))
    {
        MessageBox.Show("Please enter a valid number for Clustering.");
        setCluster.Text = "20";
    }
    else
    {
        while (inputFiles.Inspect() != imagePath) Thread.Sleep(100);
        try
        {
            lock (locker)
            {
                Bitmap incoming = new Bitmap(inputFiles.Process());
                Console.WriteLine("{0} is being processed.", e.FullPath);

                if (currentScan.Image != null) currentScan.Image = null;
                currentScan.Invoke((Action)
                delegate ()
                {
                    currentScan.Image = (Image)new Bitmap(e.FullPath);
                    currPathText.Text = imagePath;
                });

                // processing step
                Bitmap resized = new Bitmap(incoming, new
                    Size(Convert.ToInt32(incoming.Width / Variables.ScalingFact),
                    Convert.ToInt32(incoming.Height / Variables.ScalingFact)));
                .....
Posted
Comments
[no name] 31-Jan-24 17:11pm    
Too "busy" in the "on file create" event handler. Add the file names to a concurrent queue and have a seperate "background worker" thread do the lifting on demand.
dageraad 2-Feb-24 4:38am    
Yes refactoring is a good advice. But it was not causing the issue at hand.

1 solution

This is simple. You're trying to read the file before the copy process has completed and closed the file.

You just have to TRY opening the file. If it throws an exception because it's in use already, wait a bit and try again. Keep trying until you either open the file or exhaust some retry limit you arbitrarily pick.
 
Share this answer
 
Comments
dageraad 1-Feb-24 14:32pm    
I tried just that but the `catch` seems unreachable. After the exception the program just halts. I tried catching different kinds of Exceptions but IOException should work. As seen in code I tried an extensive IsFileLocked check too.

int retryCount = 0;
bool fileOpenedSuccessfully = false;

while (!fileOpenedSuccessfully && retryCount < maxRetries)
{
    try
    {
        using (FileStream fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read, FileShare.None))
        {
            fileOpenedSuccessfully = true;
        }
        //if (!IsFileLocked(imagePath))
        //{
        //    fileOpenedSuccessfully = true;
        //}
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception: {ex.GetType().Name}, Message: {ex.Message}");
        Thread.Sleep(retryDelayMilliseconds);
        retryCount++;
    }
}

if (fileOpenedSuccessfully)
{
    .....
Dave Kreskowiak 1-Feb-24 16:06pm    
This works fine:
        private Task AttemptToOpenAsync(string filepath)
        {
            return Task.Factory.StartNew(() =>
            {
                bool available = false;

                while (!available)
                {
                    available = IsAvailable(filepath);
                    Log($"IsAvailable: {available}");

                    if (!available)
                    {
                        Thread.Sleep(1000);
                    }
                }

                return available;
            });
        }

        private bool IsAvailable(string filepath)
        {
            bool result = false;

            try
            {
                using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.None))
                {
                    result = true;
                }
            }
            catch (FileNotFoundException ex)
            {
                // Log(ex.Message);
            }
            catch (IOException ex)
            {
                // Log(ex.Message);
            }

            return result;
        }
dageraad 2-Feb-24 4:36am    
No way, it works very fine! Thanks a lot this is great :D

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900