0

I've created a service worker which reads in serial port information and creates a .csv file to save the results to.

However, when i attempt to write to the file it says that the process cannot access the file, despite (from my knowledge) the file not being open, used by another external process or the filestream being open (i'm using System.IO.File.WriteAllLines()). What could the problem be?

static string InsturmentFile = $"{Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)}\\TestLogger\\";

public static void StartConnector()
    {
        Directory.CreateDirectory(InsturmentFile);
    }


public static string FullFilePath(this string fileName)
    {
        return $"{InsturmentFile}\\{fileName}";
    }


public static List<string> LoadFile(this string file)
    {
        if (!System.IO.File.Exists(file))
        {
            return new List<string>();
        }

        return System.IO.File.ReadAllLines(file).ToList();
    }

    public static List<InstrumentRawReading> ConvertToInstrumentRawReadingModel(this List<string> lines)
    {
        List<InstrumentRawReading> output = new List<InstrumentRawReading>();


        foreach (string line in lines)
        {
            string[] cols = line.Split(',');
            InstrumentRawReading u = new InstrumentRawReading();
            string spacer = " "; 
            var now = DateTime.Now;
            now = DateTime.Parse(cols[0]);
            foreach (var reading in u.Readings)
            {                                   
                reading.Name = cols[1];
            }
            output.Add(u);
        }


        return output;
    }

public static void SaveReadingsLogToFile(this List<InstrumentRawReading> models, string fileName)
    {
        try
        {
            List<string> lines = new List<string>();

            foreach (InstrumentRawReading u in models)
            {
                foreach (var rd in u.Readings)
                {
                    lines.Add($"{rd.Time},{u.SerNo},{rd.Name},{rd.Rdg},{rd.Units}");
                }

            }
            System.IO.File.WriteAllLines(fileName.FullFilePath(), lines);

        }
        catch (Exception ex)
        {
            Console.WriteLine("SaveReadingsLogToFile: " + ex.Message.ToString());
            throw;
        }

    }

This is the full file creation class which i'm using the create the .csv file, it is being created and populated with one reading, however it seems that on the subsequent calls of the method it just stops working.

Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
Sskaara
  • 21
  • 1
  • 4
  • 1
    Some suggestions here https://stackoverflow.com/questions/31950107/file-readalllines-quickly-followed-by-file-writealllines-causes-exception-du suggest that it could be an anti-virus program. The original author found that elsewhere in the code, a file was being opened via a StreamReader or similar, and wasn't being disposed of correctly. – NibblyPig Oct 17 '19 at 12:29
  • Do you execute any of this code asynchronously? I believe that `WriteAllLines` locks the file for reading and writing during the duration of the write. – Martin Oct 17 '19 at 12:30
  • What's the full and actual error message? It might not be another process actually using the file, it could just be ACLs preventing access. Check the the ACLs on the folder where you're wanting to write the file. – AlwaysLearning Oct 17 '19 at 12:32
  • As i've created a service worker to do this i'm using - async Task ExecuteAsync(CancellationToken), at the highest level which i have a switch statement in, this calls a method which creates the reading. The only async method in the whole call chain is the initial ExecuteAsync method. Could this be the cause of it? – Sskaara Oct 17 '19 at 12:38
  • SaveReadingsLogToFile: The process cannot access the file 'C:\ProgramData\TestLogger\InstrumentRawReadingLog.csv' because it is being used by another process. is the full error – Sskaara Oct 17 '19 at 12:42
  • @Sskaara That would depend upon how the program flows. Certainly, if two Tasks are attempting to access the same file simultaneously then that is going to cause an issue if the file has a read\write lock (which it will) – Martin Oct 17 '19 at 12:45
  • I changed the program to insure that all the method subsequent to the initial ExecuteTask are also async and the error is still being thrown. – Sskaara Oct 17 '19 at 12:50
  • How do you use the below code? Could you provide the code with me? – Jack J Jun Oct 18 '19 at 06:29
  • Better to use a `FileStream` with a `StreamWriter` as you get more control over locks (e.g. you can lock the file for writing only, and allow other processes to read the file, and so on). – Stephen Kennedy Oct 20 '19 at 20:46

2 Answers2

1

If the error is Process cannot access the file because it is being used by another process then it IS used by another process no matter what you say.

You can use Process Explorer a nice tool from Microsoft that you can search literal for your file and it will tell you which process has the lock on your file.

Click Find / Find Handle or DLL.. and just type in your file name

Franck
  • 4,438
  • 1
  • 28
  • 55
  • 1
    You can also get this same message when your own process has locked the file, so the error message can be misleading about _which_ process has locked the file. It can be the current, running process – Martin Oct 17 '19 at 12:31
  • I've used Process Explorer already to try and identify if it's being used to no avail. – Sskaara Oct 17 '19 at 12:34
  • @Martin Yes but in that case it will be a different threadId that is trying to access the file being used by another threadId of the same process. Doesn't change that this also show up in Process Explorer. – Franck Oct 17 '19 at 12:38
  • @Sskaara If it's not found it mean the handle is closed when you are doing the search. That mean you do have a lock but it doesn't last very long. – Franck Oct 17 '19 at 12:39
  • Ahh i see, that makes sense. How would you suggest i go about finding out what exactly is causing the issue? – Sskaara Oct 17 '19 at 12:41
  • `File.WriteAllLines()` do not lock files once it complete. A non closed `StreamReader` is often the cause – Franck Oct 17 '19 at 14:01
  • Maybe you read/write it from several thread without locks.... – Tomas Kubes Oct 20 '19 at 20:41
1

So one of the issues with my approach was that the serial port information was being read in so quickly and in multiple places that the calls became almost simultaneous. A quick fix(hack) was the add a slight delay before or after the call which seemed to do the job, however an easier fix would be to limit the number of calls made to the function from the serial port, as this would ensure that the file is always open for use, as the SaveReadingLogToFile() isn't being called multiple times from different threads/places. The best fix for this i feel, would be to write the operations to a queue and/or add a lock around the writing of the file.

Sskaara
  • 21
  • 1
  • 4