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.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:
- Construct the original Bitmap from the stream,from the memory,or from the file.
- Create a new Bitmap of the same size,with a pixel format of more than 8 bits-per-pixel (BPP).
- Use the Graphics.FromImage() method to obtain a Graphics object for the second Bitmap.
- Use Graphics.DrawImage() to draw the first Bitmap onto the second Bitmap.
- Use Graphics.Dispose() to dispose of the Graphics.
- Use Bitmap.Dispose() to dispose of the first Bitmap.
Create an Indexed Image
This workaround creates a Bitmap object in an indexed format:
- Construct the original Bitmap from the stream,or from the file.
- Create a new Bitmap with the same size and pixel format as the first Bitmap.
- Use the Bitmap.LockBits() method to lock the whole image for both Bitmap objects in their native pixel format.
- Use either the Marshal.Copy function or another memory copying function to copy the image bits from the first Bitmap to the second Bitmap.
- 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方法.