System.IO.IOException: '由于其正在被另一个进程使用,因此无法访问文件“@.txt”。'

25
我刚开始学编程,有一个问题:如果我有两个函数,一个用于创建文本文件并将内容写入,而另一个用于打开同一文本文件并从中读取。 我遇到的错误是:
System.IO.IOException:“由于正在被另一个进程使用,因此无法访问文件'@.txt'。”
我尝试为每个函数设置单独的计时器,但仍然无法正常工作。 我认为最好的方法是在函数一结束之前不启动函数二。
你能帮我实现这个吗? 非常感谢! Mike 源代码:
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..
}

1
展示你的源代码。 - user366312
释放所有对象..... - andy
1
可能是因为你在写入文件完成后没有关闭它。 - user366312
请发布函数代码和出现错误的位置。 - rshah4u
我希望当function2正在执行某些操作时,function1能够等待。或者当function1正在执行某些操作时,function2能够等待。 - Mike
显示剩余3条评论
6个回答

24

编辑完文件后,您需要关闭它。

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

关闭后,您可以再次使用它(进行阅读)


这对于整个流程重新开始时有效吗? - Mike
与文件一起工作的过程是:1)创建 2)打开 3)写入/读取 4)关闭。所以,我不明白为什么它不会工作... 即使在第二个函数(读取文本文件)之后,您还必须将其关闭。 - rshah4u

8
问题在于有时文件锁关闭后不会立即释放。您可以尝试运行循环以读取文件。在循环内部,放置一个try catch语句,如果文件成功读取,则从循环中跳出。否则,请等待几毫秒并再次尝试读取文件:
string originalText = null;
while (true)
{
    try
    {
        originalText = File.ReadAllText(@"C:\Users\...\fileName.txt", Encoding.Default);
        break;
    }
    catch 
    { 
        System.Threading.Thread.Sleep(100);
    }
}

3
我喜欢这种方法,但我会避免在这样的逻辑中使用while(true)。如果在读取文件期间抛出任何错误,它将继续重试。因此,假设故障模式是系统性的而不是随机的,这将创建一个无限循环。 - Rob S.
我喜欢这种方法,但我会避免在这样的逻辑中使用while(true)。如果在读取文件期间抛出任何错误,它将继续重试。因此,假设故障模式是系统性的而不是随机的,这将创建一个无限循环。 - Rob S.
1
谢谢你,亚历山大。那就是我的问题的解决方案。 - ashilon

6

在编写完文本文件后,在执行第二个函数之前应首先关闭它:

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

只是为了阐述一下:
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();
}

重点是,在您完成文件的任何操作后,必须关闭FileStream。您可以通过myFileStream.Close()来实现。
此外,File.Create(filename)返回一个FileStream对象,然后您可以使用Close()方法关闭它。

谢谢,我会研究一下并相应地进行必要的调整。 - Mike
如果你正在使用的流必须传递给另一个库怎么办?我必须将我的流编写器传递给JsonTextWriter(Newtonsoft.Json)以写出结果。 - Su Llewellyn

6
实际上,这不是关闭/处理流的问题,File.WriteAllTextFile.ReadAllText在内部执行了这一过程。
问题出在错误使用async/await模式上。因为GET是异步的,但从未被等待,导致function1完成并移动到function2之前,并没有将所有内容实际写入文件中。
按照现有方式编写,GET无法等待,因为它是async void,除非你正在处理事件或确实知道自己在做什么,否则不应该使用此操作。
因此,要么完全删除async/await的使用,要么在整个过程中都使用async
  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();
    }
    

你的确是对的,代码中存在重叠。然而,我曾经在同步代码中遇到过文件正在使用的相同问题。 - Alexander Higgins

2
创建一个文件,然后关闭它。之后可以将数据保存到该文件中。 我按照以下方式执行。
if (!File.Exists(filePath))
{
    File.Create(filePath).Close();
}
File.WriteAllText(filePath, saveDataString)

1
在一个单元测试中,我必须创建一个临时文件,并在之后删除它,但是我一直收到上述错误。
没有任何答案起作用。 解决方案是:
var path = $"temp.{extension}";
        using (File.Create(path))
        {
        }


        File.Delete(path);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接