微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

vb.net – 如何防止Image.FromFile()方法锁定文件

我正在使用以下代码将JPG放入DataGridView的 Image单元格中.
If strFileName.ToLower.EndsWith(".jpg") Then
     Dim inImg As Image = Image.FromFile(strFileName)
     DataGridView4.Rows.Add()
     DataGridView4.Rows(DataGridView4.Rows().Count - 1).Cells(0).Value = inImg
End If

问题是我需要从程序中保存这个文件,但我收到的消息是该文件正在被另一个程序使用.

所以我尝试在结束之前添加inImg.dispose()if,但是然后程序不再在DataGridView中显示图像.

如何在不锁定它们的情况下在DataGridView中添加图像?

谢谢

当您使用Image.FromFile(strFileName)方法创建Image时,该方法将锁定该文件,直到您释放Image.确切原因解释如下.这就是为什么用这种方法不能多次访问同一个图像文件的原因.

你可以改为:

>使用Image.FromStream(stream)方法.
>您使用从图像文件创建的新FileStream或MemoryStream.

以下是可能实现的自定义SafeImageFromFile方法,该方法不会锁定图像文件

Public Shared Function SafeImageFromFile(path As String) As Image
    Using fs As New FileStream(path,FileMode.Open,FileAccess.Read)
        Dim img = Image.FromStream(fs)
        Return img
    End using
End Function

要么

Public Shared Function SafeImageFromFile(path As String) As Image
    Dim bytes = File.ReadAllBytes(path)
    Using ms As New MemoryStream(bytes)
        Dim img = Image.FromStream(ms)
        Return img
    End Using
End Function

用法

If strFileName.ToLower.EndsWith(".jpg") Then
    Dim inImg As Image = SafeImageFromFile(strFileName)
    Dim index as integer = DataGridView4.Rows.Add()
    DataGridView4.Rows(index).Cells(0).Value = inImg
End If

重要的提示

在这里,我使用Using语句创建FileStream或MemoryStream,以确保释放流.它在我的系统上工作正常,它似乎也适合你,虽然MSDN说Image.FromStream(stream)方法

You must keep the stream open for the lifetime of the Image.

这句话的原因在这里解释:KB814675 Bitmap and Image constructor dependencies

GDI+,and therefore the System.Drawing namespace,may defer the
decoding of raw image bits until the bits are required by the image.

Additionally,even after the image has been decoded,GDI+ may
determine that it is more efficient to discard the memory for a large
Bitmap and to re-decode later.
Therefore,GDI+ must have access to the
source bits for the image for the life of the Bitmap or the Image
object.

To retain access to the source bits,GDI+ locks any source file,and
forces the application to maintain the life of any source stream,for
the life of the Bitmap or the Image object.

因此,知道上面的代码可以生成GDIexceptions,因为使用Using释放流.从文件或图像创建过程中保存图像时可能会发生这种情况.从这个帖子Loading an image from a stream without keeping the stream open和Hans Passant的评论他们修复了Vista版gdiplus.dll中索引像素格式的几个问题,它只会在XP上发生.

为避免这种情况,您需要保持流打开.方法是:

Public Shared Function SafeImageFromFile(path As String) As Image
    Dim fs As New FileStream(path,FileAccess.Read)
    Dim img = Image.FromStream(fs)
    Return img
End Function

要么

Public Shared Function SafeImageFromFile(path As String) As Image
    Dim bytes = File.ReadAllBytes(path)
    Dim ms = New MemoryStream(bytes)
    Dim img = Image.FromStream(ms)
    Return img
End Function

但是那些最后的方法有一些缺点,比如不释放流(内存问题),它们违反了规则CA2000 Dispose objects before losing scope.

知识库文章给出了一些解决方法

Create a Non-Indexed Image

This approach requires that the new image be in a non-indexed pixel
format (more than 8 bits-per-pixel),even if the original image was in
an indexed format. This workaround uses the Graphics.DrawImage()
method to copy the image to a new Bitmap object:

  1. Construct the original Bitmap from the stream,from the memory,or from the file.
  2. Create a new Bitmap of the same size,with a pixel format of more than 8 bits-per-pixel (BPP).
  3. Use the Graphics.FromImage() method to obtain a Graphics object for the second Bitmap.
  4. Use Graphics.DrawImage() to draw the first Bitmap onto the second Bitmap.
  5. Use Graphics.dispose() to dispose of the Graphics.
  6. Use Bitmap.dispose() to dispose of the first Bitmap.

Create an Indexed Image

This workaround creates a Bitmap object in an indexed format:

  1. Construct the original Bitmap from the stream,or from the file.
  2. Create a new Bitmap with the same size and pixel format as the first Bitmap.
  3. Use the Bitmap.LockBits() method to lock the whole image for both Bitmap objects in their native pixel format.
  4. Use either the Marshal.copy function or another memory copying function to copy the image bits from the first Bitmap to the second Bitmap.
  5. Use the Bitmap.UnlockBits() method to unlock both Bitmap objects.
    Use Bitmap.dispose() to dispose of the first Bitmap.

以下是基于知识库文章的非索引图像创建实现和此答案https://stackoverflow.com/a/7972963/2387010您最好的选择是创建像素完美的图像副本 – 尽管YMMV(某些类型的图像可能有多个帧,或者您可能还必须复制调色板数据.)但对于大多数图像,这适用:

Private Shared Function SafeImageFromFile(path As String) As Bitmap
    Dim img As Bitmap = nothing
    Using fs As New FileStream(path,FileAccess.Read)
        Using b As New Bitmap(fs)
            img = New Bitmap(b.Width,b.Height,b.PixelFormat)
            Using g As Graphics = Graphics.FromImage(img)
                g.DrawImage(b,Point.Empty)
                g.Flush()
            End Using
        End Using
    End Using
    Return img
End Function

有人表示重要的是FileStream以读模式打开(FileAccess.Read).

是的,但是如果你不使用Using语句并且不释放流,或者在多线程上下文中它会更加敏感:FileAccess.Write是不合适的,并且不需要FileAccess.ReadWrite,但打开流如果另一个程序(或多线程上下文中的程序)使用FileAccess.Read之外的其他模式打开文件,FileAccess.Read模式将不会阻止IO.Exception.

如果您希望能够显示图像并同时能够将数据保存到文件中,由于您没有使用这些方法锁定文件,您应该能够保存图像(删除/覆盖以前的图像) file)使用Image.Save方法.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐