4

所以我正在编写一个快速应用程序来根据纵横比将我的壁纸整齐地分类到文件夹中。一切都很顺利,直到我尝试实际移动文件(使用 FileInfo.MoveTo())。应用程序抛出异常:

System.IO.IOException 该进程无法访问该文件,因为它正被另一个进程使用。

唯一的问题是,我的计算机上没有运行其他进程打开该特定文件。我想也许是因为我使用文件的方式,也许是不同线程上的一些内部系统子例程,或者当我尝试移动文件时文件打开了。果然,在上面几行,我设置了一个属性,该属性调用一个打开文件进行读取的事件。我假设至少其中一些是异步发生的。反正有没有让它同步运行?我必须更改该属性或重写大部分代码。

以下是一些相关的代码,请原谅蹩脚的 Visual C# 默认名称,这还不是真正的发布质量软件:

private void button1_Click(object sender, EventArgs e)
{
    for (uint i = 0; i < filebox.Items.Count; i++)
    {
        if (!filebox.GetItemChecked((int)i)) continue;

        //This calls the selectedIndexChanged event to change the 'selectedImg' variable
        filebox.SelectedIndex = (int)i;

        if (selectedImg == null) continue;

        Size imgAspect = getImgAspect(selectedImg);

        //This is gonna be hella hardcoded for now
        //In the future this should be changed to be generic
        //and use some kind of setting schema to determine
        //the sort/filter results

        FileInfo file = ((FileInfo)filebox.SelectedItem);

        if (imgAspect.Width == 8 && imgAspect.Height == 5)
        {
            finalOut = outPath + "\\8x5\\" + file.Name;
        }
        else if (imgAspect.Width == 5 && imgAspect.Height == 4)
        {
            finalOut = outPath + "\\5x4\\" + file.Name;
        }
        else
        {
            finalOut = outPath + "\\Other\\" + file.Name;
        }

        //Me trying to tell C# to close the file
        selectedImg.Dispose();
        previewer.Image = null;

        //This is where the exception is thrown
        file.MoveTo(finalOut);
    }
}

//The suspected event handler
private void filebox_SelectedIndexChanged(object sender, EventArgs e)
{
    FileInfo selected;
    if (filebox.SelectedIndex >= filebox.Items.Count || filebox.SelectedIndex < 0) return;
    selected = (FileInfo)filebox.Items[filebox.SelectedIndex];

    try
    {
        //The suspected line of code
        selectedImg = new Bitmap((Stream)selected.OpenRead());
    }
    catch (Exception) { selectedImg = null;  }

    if (selectedImg != null)
        previewer.Image = ResizeImage(selectedImg, previewer.Size);
    else
        previewer.Image = null;
}

我有一个长期的解决方案(无论如何这可能更有效),但它仍然存在更多问题:/

任何帮助将不胜感激。

4

3 回答 3

1

由于您将您selectedImg用作类范围的变量,因此它在位图打开时保持对文件的锁定。我将使用一个using statement然后Clone将位图放入您正在使用的变量中,这将释放位图在文件上保留的锁。

像这样的东西。

using ( Bitmap img  = new Bitmap((Stream)selected.OpenRead()))
{
    selectedImg = (Bitmap)img.Clone();
}
于 2013-12-25T20:04:03.490 回答
0

新答案:

我查看了执行 OpenRead() 的行。显然,这会锁定您的文件。最好提供文件路径而不是流,因为您无法处理流,因为位图会变得错误。

我在您的代码中查看的另一件事可能是一种不好的做法,那就是绑定到 FileInfo。更好地创建一个数据传输对象/值对象并绑定到这种类型的集合 - 一些具有您需要在控件中显示的属性的对象。这将有助于避免文件锁定。

另一方面,您可以做一些技巧:为什么不显示拉伸到屏幕分辨率的图像并压缩它们,这样图像尺寸会比实际尺寸小得多,并且您提供一个名为“在 HQ 中显示”的按钮?那应该可以解决预加载高清图像的问题。当用户单击“在 HQ 中显示”按钮时,将该图像加载到内存中,当它关闭时,它会被释放。

你没事吧?

如果我没记错的话,FileInfo 不会阻止任何文件。您不是打开它,而是阅读它的元数据。

另一方面,如果您的应用程序显示图像,您应该移动到内存可见图像并将它们从内存流加载到您的表单中。

这是合理的,因为您可以打开一个文件流,读取它的字节并将它们移动到一个内存流,留下对该文件的锁定。

注意:此解决方案适用于不太大的图像...如果您使用的是高清图像,请告诉我。

于 2011-01-17T14:30:00.913 回答
0
using(selectedImg = new Bitmap((Stream)selected))

会这样做吗?

于 2011-04-11T21:59:24.807 回答