在任何时候,列表也可以清除项目并重新填充不同的项目.这会调用需要优雅处理文件流的每个项目的Dispose(它仍然可以处于异步读取的中间).
我将展示我正在使用的代码.我不确定在这样的情况下调用和锁定对象的正确用法,其中异步加载新文件的请求可能会在异步加载的同时加载异步文件.
public string FileName { get; set; } public Image Image { get; set; } public Control Parent { get; set; } private FileStream currentFileStream; private byte[] buffer; private object locker = new object(); private bool loading; private bool disposed; public void LoadImage(string fileName) { FileName = fileName; lock (locker) { currentFileStream = new FileStream(FileName,FileMode.Open,FileAccess.Read,FileShare.Read); buffer = new byte[currentFileStream.Length]; currentFileStream.BeginRead(buffer,buffer.Length,FileReadComplete,currentFileStream); loading = true; } } private void FileReadComplete(IAsyncResult ar) { FileStream fileStreamComplete = (FileStream)ar.AsyncState; lock (locker) { fileStreamComplete.EndRead(ar); // If the finished FileStream is the more recent one requested // And this item has not been disposed if (fileStreamComplete == currentFileStream && !disposed) { try { loading = false; Image = new Bitmap(currentFileStream); currentFileStream.Close(); currentFileStream.Dispose(); Parent.Invalidate(); } catch (Exception e) { } finally { currentFileStream = null; } } else { fileStreamComplete.Close(); fileStreamComplete.Dispose(); } } } protected override void Dispose(bool disposing) { lock (locker) { base.Dispose(disposing); if (!disposed) { if (disposing) { if (Image != null) Image.Dispose(); } disposed = true; } } }
编辑:
从Dispose()方法中删除了currentFileStream的处理.
编辑#2:
从LoadImage()函数中删除了currentFileStream的处理.它可能不应该存在,因为文件读取可能正在进行中并且在操作期间无法关闭.无论何时调用FileReadComplete回调,它都会被处理掉.
解决方法
>如果计划将其用于异步只读,请使用其他FileStream构造函数.它可能与您的问题无关,但只是一种更好的方法
currentFileStream = new FileStream(FileName,FileShare.Read,1024 * 8,true);
>您是否有任何理由不想提供Bitmap构造函数(或Image.FromFile)的路径并让它加载文件?请记住,在将大量文件加载到内存中时,按顺序加载它们可能会更快(如果文件驻留在顺序访问技术(如硬盘)上)
假设你仍然想要异步加载它,我只是将这个功能封装在一个“neatness”的类中
您似乎从同一个流中加载了您已经读入缓冲区的图像.我确信这是一个问题.以下是我对你的代码的改编.主要变化是
>我没有找到currentFileStream变量的用法
> dispose变量是易失性的,因为它可以从多个线程访问
>在FileStream.Close之后调用FileStream.Dispose是多余的,因此将其删除
我没有尝试过代码,所以你必须告诉我它是否有效
class ImageLoader : IDisposable { public string FileName { get; set; } public Image Image { get; set; } public Control Parent { get; set; } private FileStream currentFileStream; private byte[] buffer; private object locker = new object(); Control parent; private volatile bool dispose = false; public ImageLoader(Control parent,string fileName) { Parent = parent; FileName = fileName; Image = null; currentFileStream = new FileStream(FileName,true); buffer = new byte[currentFileStream.Length]; currentFileStream.BeginRead(buffer,new AsyncCallback(FileReadComplete),null); } private void FileReadComplete(IAsyncResult ar) { lock (locker) { try { currentFileStream.EndRead(ar); } catch (ObjectDisposedException) { } if (!dispose) { using (MemoryStream ms = new MemoryStream(buffer)) Image = new Bitmap(ms); Parent.Invalidate(); } try { currentFileStream.Close(); } catch(IOException) { } } } public void Dispose() { lock (locker) { if (dispose) return; dispose = true; try { currentFileStream.Close(); } catch(IOException) { } if (Image != null) Image.Dispose(); } } }
EDIT1:
根据您的评论,我在这里添加响应,因为系统不允许我在那里添加更多文本
>将这样的功能封装到一个类(一组函数)或一个函数中是很好的一致性,并且很多时候这样的好的实践都会有性能损失.你应该根据你的情况使用它.>我不认为这是一个流如何工作,但在小文件的情况下,我可以看到它是如何的情况.要解释这一点,如果指示文件缓冲区大小为8K,则大于8K的文件不能缓存在内存中.因此,如果没有真正的I / O,流无法读取整个文件(忘记Windows在屏幕后面做了什么).此外,Bitmap构造函数可能会执行同步I / O,并且在异步模式下打开它时可能会出现问题. MSDN明确指出,流应仅在整个流对象生命周期中以一种模式(同步或异步)使用.我坚信你应该关闭流并从你已经创建的缓冲区中读取.我认为它的方式是,它现在适用于你并不意味着它将在不同的情况下工作;你可能只是“幸运”.>我同意volatile关键字,我只是这样练习,因为有时在更改代码时(说我一起摆脱锁定)它可以避免我的错误
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。