24

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..
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Mike
  • 241
  • 1
  • 2
  • 4
  • 1
    Show your source code. – user366312 Jul 01 '17 at 07:38
  • Release all objects..... – andy Jul 01 '17 at 07:38
  • 1
    Probably, you are not closing the file when you are done writing into it. – user366312 Jul 01 '17 at 07:40
  • The code is very long and messy. Basically one function saves data to text file, then the other function comes in and reads from the file. The whole process repeats again and again and again. My code is beginner and very messy. – Mike Jul 01 '17 at 07:44
  • post the code of both the function and where you're getting the error.. – rshah4u Jul 01 '17 at 07:46
  • try this for simultanous: https://stackoverflow.com/a/3817526/1498401 but it's unlikely that it would work good. Separete reading and writing and dont forget about closing the streams or use `using` blocks – tinamou Jul 01 '17 at 07:54
  • I posted the source code. As you can see both function1 and function2 use the same text file. Function1 creates and saves data from internet into the text file, then function two uses that same text file to do something with it. And the error i get is at the function two when i read the text file. – Mike Jul 01 '17 at 08:06
  • I would like function1 to wait when function2 is doing something. Or function 2 to wait when function 1 is doing something. – Mike Jul 01 '17 at 08:08

6 Answers6

24

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)

rshah4u
  • 441
  • 3
  • 13
  • Will this work for when the whole process starts again? – Mike Jul 01 '17 at 07:43
  • The process of working with files is that, 1) Create 2) Open 3) Write/Read 4) Close. So, I don't see why it won't work.. Even after your second function i.e. Reading the text file you'll have to close it. – rshah4u Jul 01 '17 at 07:44
8

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);
    }
}
Alexander Higgins
  • 6,765
  • 1
  • 23
  • 41
  • 3
    i like this approach, but I would avoid using while(true) in logic like this. In the case that ANY error is thrown during the reading of a file this will continue to retry. So assuming the case where the failure mode is systematic and not random this would create an infinite loop. – Rob S. Apr 20 '20 at 17:49
  • i like this approach, but I would avoid using while(true) in logic like this. In the case that ANY error is thrown during the reading of a file this will continue to retry. So assuming the case where the failure mode is systematic and not random this would create an infinite loop. – Rob S. Apr 20 '20 at 17:50
  • 1
    Thanks Alexander, that was the solution to my problem. – ashilon Apr 22 '21 at 14:24
6

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().

xGeo
  • 2,149
  • 2
  • 18
  • 39
  • Thank you, I will look into that and make the neccesary adjustments accordingly. – Mike Jul 01 '17 at 07:46
  • What if the stream you are using has to be passed to another library? I have to pass my streamwriter to a JsonTextWriter (Newtonsoft.Json) to write out results. – Su Llewellyn May 18 '18 at 16:03
6

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:

  1. Change GET to be awaitable:

    async Task GET(string link, string fileName)
    
  2. 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);
        }
        ...
    
  3. await function1 in the Elapsed event:

    private async void tickTimera1(object source, ElapsedEventArgs e)
    {
        await function1();
        function2();
    }
    
Ofir Winegarten
  • 9,215
  • 2
  • 21
  • 27
  • You are indeed correct about the the overlap in the code. I have however seen the same issue of a file being in use even in Synchronous code. – Alexander Higgins Dec 02 '20 at 16:39
2

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)
1

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);
Matas Vaitkevicius
  • 58,075
  • 31
  • 238
  • 265