C# 线程挂在关闭文件上

问题描述 投票:0回答:3

我有一个线程调用静态方法来使用 WindowsAPICodePack ShellPropertyWriter 和 BackgroundWorker 更新文件属性。该线程为包含 1000 多个文件的文件夹中的每个文件调用以下方法,并在第 700 次更新后挂起在 ShellPropertyWriter.close() 上。

与文件本身无关,尝试使用之前成功更新的不同文件。

    public static bool ShellPropertyUpdate(VideoEntry mediaEntry)
    {
        try
        {
            ShellFile mediafile = ShellFile.FromFilePath(mediaEntry.FilePath);
            ShellPropertyWriter pw = mediafile.Properties.GetPropertyWriter();
            pw.WriteProperty(SystemProperties.System.Music.Artist, mediaEntry.Actor);
            pw.WriteProperty(SystemProperties.System.Music.Genre, mediaEntry.Genre);
            pw.WriteProperty(SystemProperties.System.Rating, mediaEntry.Rating);
            pw.Close();
        }
        catch (Exception ex)
        {
           return false;
        }
        return true;
    }

    private void mnuWriteMetadataToFiles_Click(object sender, EventArgs ev)
    {
        this.WorkerThread = new BackgroundWorker();
        this.WorkerThread.DoWork += new DoWorkEventHandler(WorkerThread_WriteMetadataToFiles);
        this.WorkerThread.ProgressChanged += new ProgressChangedEventHandler(WorkerThread_ProgressChanged);
        this.WorkerThread.RunWorkerCompleted += (s, e) => WorkerThread_Completed("Writing metadata to files", s, e);
        this.WorkerThread.WorkerReportsProgress = true;
        this.WorkerThread.WorkerSupportsCancellation = true;
        this.WorkerThread.RunWorkerAsync(WMPlayer);
    }

    private void WorkerThread_WriteMetadataToFiles(object sender, DoWorkEventArgs e)
    {
        int counter = 0;
        BackgroundWorker worker = (BackgroundWorker)sender;
        MediaPlayer wmp = (MediaPlayer)e.Argument;

        // ... Loop with the foreach video in the library and write it to file.
        foreach (VideoEntry entry in wmp.Videos)
        {
            if (worker.CancellationPending)
            {
                e.Cancel = true;
            }
            else
            {
                worker.ReportProgress(counter, "Updating '" + entry.Filename + "'" + Environment.NewLine + "Processing file");
                if (VideoToFile.ShellPropertyUpdate(entry))
                {
                    result &= true;
                }
                counter++;
            }
        }
        e.Result = result;
    }
c# multithreading
3个回答
3
投票

以前从未听说过这个集会,但对我来说,它闻起来就像手柄疲惫一样。试试这个:

using (ShellFile mediafile = ShellFile.FromFilePath(mediaEntry.FilePath))
{
    ShellPropertyWriter pw = mediafile.Properties.GetPropertyWriter();
    pw.WriteProperty(SystemProperties.System.Music.Artist, mediaEntry.Actor);
    pw.WriteProperty(SystemProperties.System.Music.Genre, mediaEntry.Genre);
    pw.WriteProperty(SystemProperties.System.Rating, mediaEntry.Rating);
    pw.Close();
}

这里每个文件句柄都会立即关闭,而不是由垃圾收集器自行决定。

ShellFile
必须实现
IDisposable
才能正常工作,否则此代码将无法编译。我相当确定
ShellFile
实现了它。


0
投票

显然这确实与文件本身有关。我取出了几个问题文件,线程继续处理,直到下一个问题文件。我不知道该文件出了什么问题,但我愿意继续更新问题文件。有没有办法停止/杀死线程?我无法使用 DoWorkEventArgs.cancel() 因为线程挂起并且不会返回。


0
投票

我遇到了同样的问题,但就我而言,我有理由相信它与用于创建 ShellFile 对象的任何特定文件无关。相反,只要 ShellFile 对象被 Dispose,就会发生异常:如果我使用“using”块限制对象的范围,则异常将在该块存在时立即发生;如果我在对象上手动调用 .Dispose() ,异常就会立即发生。 我设法通过从 aybe 的 Microsoft-WindowsAPICorePack (1.1) 版本更改为 contre 的版本 (1.1.5) 来解决此问题

我使用 dotnet remove package 删除了已安装的两个 aybe 软件包(...Core 和 ...Shell)。然后我使用添加了 contre 包 dotnet 添加包 Microsoft-WindowsAPICodePack-Core --版本 1.1.5 dotnet 添加包 Microsoft-WindowsAPICodePack-Shell --版本 1.1.5 然后我必须更新我的 project.csproj 文件,以便目标框架现在设置为 net8.0-windows 代替 net8.0

在执行此操作时,我还必须调整 launch.json,使“program”属性现在指向 /net8.0-windows/ 子文件夹。

© www.soinside.com 2019 - 2024. All rights reserved.