【问题标题】:C# - Unable to close file, resulting in 'file being used in another process' Exception [closed]C# - 无法关闭文件,导致“文件正在另一个进程中使用”异常 [关闭]
【发布时间】:2015-12-30 18:38:16
【问题描述】:

我有一个程序在给定路径搜索文件夹,并提取文件夹内任何文件或其中任何子文件夹的路径。 从这里,它使用单独的文件路径来创建一个名为ImageData 的自定义类的对象。处理此问题的方法如下所示:

public void saveLatestImages(string chosenPath)
{
    //if there is a Pictures folder
    if (Directory.Exists(chosenPath))
    {
        //get number of files in folder
        int fileCount = Directory.GetFiles(chosenPath).Count();

        //more than one file in folder
        if (fileCount > 0)
        {
            //create data structures to store file info
            //filePaths holds path of each file represented as a string
            string[] filePaths = Directory.GetFiles(chosenPath);

            //for each file in Pictures...
            for (int index = 0; index < fileCount; ++index)
            {
                //get name of image at current index
                imageName = filePaths[index];
                //separate the part relating to the patient name (everything before (DD/MM/YYYY))
                string subSpecifier = imageName.Split('\\').Last();
                subSpecifier = subSpecifier.Split('_')[0];
                //add to root directory to form subfolder name
                subDirectory = Path.Combine(rootDirectory, subSpecifier);

                //subdirectory name formulated, check for pre-existing
                //subfolder does not exist
                if (!Directory.Exists(subDirectory))
                {
                    //create it
                    Directory.CreateDirectory(subDirectory);
                }
                //otherwise, file will be added to existing directory

                //take everything from end and folder\file division to get unique filename
                string fileName = imageName.Split('\\').Last();
                //add this to the existing subDirectory
                fileName = Path.Combine(subDirectory, fileName);

                //copy the image into the subfolder using this unique filename
                File.Copy(imageName, fileName, true); //true gives instruction to overwrite any existing file with the same path

                //construct new instance with created filename
                imageData.Add(new ImageData(fileName));

            }
        }
    }
}

到目前为止,一切都很好。 当创建的ImageData 对象显示在PictureBox 上(使用位图属性)时,问题就出现了。当此图像在图片框上时,可通过按钮获得许多选项。 例如,有一个按钮可以从图片框中删除ImageData 对象并删除文件。 这是使用以下方法完成的:

private void btnDeleteImage_Click(object sender, EventArgs e)
{
    ///////////////////////////////////////////////////////////////////////////////////
    //imageData is List<ImageData> that contains all ImageData objects currently in use
    //imageSlider is the PictureBox where the images are displayed/////////////////////
    ///////////////////////////////////////////////////////////////////////////////////

    //identify image currently on picturebox
    Image displayImage = imageData[displayImageIndex()].getThumbnailImage();
    //get the file path of this image
    string displayImagePath = imageData[displayImageIndex()].getImagePath();

    //move to next or previous image in list
    //then remove image that was just viewed

    //current image not last in list
    if (!(imageSlider.Image.Equals(imageData.Last().getThumbnailImage())))
    {
        displayImage = imageData[displayImageIndex() + 1].getThumbnailImage();
        //display the next image in the list
        imageSlider.Image = displayImage;

        //delete the image just moved on from from list
        imageData.RemoveAt(displayImageIndex() - 1);
        //delete the file path at this index in the paths list
        File.Delete(displayImagePath);
    }
    //current image is last in list
    else
    {
        displayImage = imageData[displayImageIndex() - 1].getThumbnailImage();
        //display previous image in list
        imageSlider.Image = displayImage;

        //delete the image just moved on from from list
        imageData.RemoveAt(displayImageIndex() + 1);
        //delete the file path at this index in the paths list
        File.Delete(displayImagePath); <--- ////ERROR OCCURS////
    }

    //check for prior and successive elements in list
    checkFirstLast(displayImage);
    updateImageInfo();
}

File.Delete() 命令中,出现异常通知我“无法访问文件,因为它正被另一个进程使用”。

基本上,文件在被带入程序时被打开,并且永远不会关闭。这意味着当我尝试访问要删除的文件(或对其执行其他操作)时,无法按照程序当前的状态执行此操作。 我知道如果我使用的是FileStream 对象,那么一旦对象完成,我就可以调用.Close() 方法。但是看到所有文件访问都是使用字符串变量完成的,然后这些变量用于创建图像,我似乎没有可用的等效方法。

有没有人知道任何其他方式来实现这种行为?如果这不可能,是否可以使用FileStream 之类的方式管理图像文件?

任何关于从这里去哪里的建议都会很棒。

谢谢, 标记

【问题讨论】:

  • 大概你是在 ImageData 类中创建 Bitmap 对象。 Bitmap 对象使创建它们的流保持打开状态。如果您将所有文件数据读入MemoryStream(完成读取后关闭FileStream)并从该流中创建Bitmap,您应该没问题。
  • 你的代码看起来很复杂,里面有很多重复。但产生问题的代码似乎在“ImageData”类中,没有显示。看起来它仍然在文件上,而不是仅加载它。能否展示一下引导图片的代码?
  • 谢谢你,听起来像是我正在寻找的东西!只是一个简单的问题,因为我只使用文件路径而没有文件中的实际数据,因此 MemoryStream 是否合适?如果是这样,我如何将图像数据读入 MemoryStream 并读出?谢谢@adv12
  • 此链接 stackoverflow.com/questions/11397565/… 将提供 3 种可能的方式来做到这一点...
  • @marcuthh 我已经用您要求的代码添加了一个实际答案。

标签: c# file


【解决方案1】:

正如我的评论中所述,您可能正在使用 ImageData 类中创建 Bitmap 对象,使用 the constructor that takes a string(文件名):

Bitmap b = new Bitmap(filename);

使用此构造函数创建的Bitmap 将从给定路径的文件中创建一个FileStream,并将保持FileStream 打开直到Bitmap 被处置,如文档中所述:

在释放位图之前,文件保持锁定状态。

要解决此问题,您可以改为从您自己从文件中填充的 MemoryStream 构建 Bitmap

byte[] data = File.ReadAllBytes(filename);
MemoryStream stream = new MemoryStream(data);
Bitmap b = new Bitmap(stream);

这样,Bitmap 保持打开的流是您创建的MemoryStream,而不是保持文件锁定的FileStream

【讨论】:

  • 嗨,我刚刚在创建位图的ImageData 方法中添加了这些行。它编译得很好,但是当我再次尝试访问该文件时,我仍然遇到相同的异常。使用您给我的代码,是否有任何我可能缺少的“close()”方法?
  • 忽略之前的评论,我现在可以使用了。感谢您的帮助!
【解决方案2】:

通常的标准是 -

  • 创建临时文件夹。像一个临时文件夹
  • 在那里复制您的文件
  • 显示该临时文件中的图像
  • 为每个操作制作一个副本(1.jpg,2.jpg)
  • 最后完成后,将最新的最终文件复制回原始文件夹
  • 删除暂存文件夹

优势 -

  • 原始数据永不丢失
  • 意外损坏非常少
  • 易于进行撤消操作
  • 如果您不能立即删除暂存文件夹,您可以为此进行后台作业

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 2013-02-25
    • 2014-08-28
    • 2013-09-14
    相关资源
    最近更新 更多