我正在开发一个解决方案,它需要支持查询许多jpeg文件元数据才能获得Comment
- 和DateTaken
- 属性。但是我总是在大约20个文件后得到一个OutOfMemoryException。因此,在将Comment
- 和DateTaken
- 值分配给两个字符串后,我需要知道如何释放内存。目前我正在使用JpegBitmapDecoder
并通过解码器的实例化将BitmapCacheOption
设置为OnLoad
。我想,这就是我得到异常的原因,但我不知道如何让它变得更好,因为我第一次使用Images / Bitmaps工作。
在一个单独的表单中,我有一个BackgroundWorker,在其中调用mainform的方法。在该方法中,调用两个方法,以从文件中获取Comment和DateTaken。为了在这两个方法中获取文件的元数据,调用另一个方法,在该方法中,我在行中获得异常,我实例化了JpegBitmapDecoder
。
以下是方法:
在formPleaseWait
:
private void bgwLoadPhotos_DoWork(object sender, DoWorkEventArgs e)
//BackgroundWorker in formPleaseWait
{
int filesCount;
FileInfo[] files;
FolderBrowserDialog browseFolder = (FolderBrowserDialog)e.Argument;
files = selectedFolder.GetFiles("*.jpg");
filesCount = files.Count();
foreach (FileInfo file in selectedFolder.GetFiles("*.jpg"))
{
try
{
Photo photo = formMain.CreatePhotoObject(file);
//the method in the mainform is called
loadedPhotos.Add(photo);
loadProgress++;
if (loadProgress == filesCount)
{
loadProgress = 100;
}
}
catch (OutOfMemoryException)
{
MessageBox.Show(
MessageBoxButtons.OK, MessageBoxIcon.Information);
loadProgress = 100;
break;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
在formMain
:
public Photo CreatePhotoObject(FileInfo file)
{
int year = 0;
string comment = GetPhotoComment(file);
string dateString = GetPhotoDate(file);
//the two methods to get comment and date are called
string filename = file.Name;
string path = selectedFolder + @"\" + filename;
string photoname = Path.GetFileNameWithoutExtension(file.FullName);
DateTime date = new DateTime();
if(dateString != null)
{
date = DateTime.Parse(dateString).Date;
dateString = date.ToShortDateString();
year = date.Year;
}
return new Photo(year, comment, filename, photoname, dateString);
}
private string GetPhotoComment(FileInfo file)
{
BitmapMetadata metadata = GetMetadata(file);
return metadata.Comment;
}
private string GetPhotoDate(FileInfo file)
{
BitmapMetadata metadata = GetMetadata(file);
return metadata.DateTaken;
}
private BitmapMetadata GetMetadata(FileInfo file)
{
BitmapFrame frame;
BitmapMetadata metadata;
JpegBitmapDecoder decoder;
string filepath = file.FullName;
using (Stream fileStreamIn = File.Open(filepath, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
decoder = new JpegBitmapDecoder(fileStreamIn,
BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.OnLoad);
//Here I get the exception
}
frame = decoder.Frames[0];
return metadata = (BitmapMetadata)frame.Metadata;
}
答案 0 :(得分:1)
我找到了解决方案。
我创建了一个包含所需方法的类:
public class PhotoFactory
{
[...]
public Photo CreatePhotoObject(FileInfo file)
{
string comment;
string dateString;
DateTime date;
int year = 0;
string filename = file.FullName;
string path = selectedFolder + @"\" + filename;
string photoname = file.Name;
GetCommentDate(file.FullName, out comment, out dateString);
if (dateString != null)
{
date = DateTime.Parse(dateString).Date;
dateString = date.ToShortDateString();
year = date.Year;
}
return new Photo(year, comment, filename, photoname, dateString);
}
private void GetCommentDate(string filepath, out string comment, out
string dateString)
{
using (FileStream fileIn = new FileStream(filepath, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
BitmapSource source = BitmapFrame.Create(fileIn);
BitmapMetadata metadata = (BitmapMetadata)source.Metadata;
comment = metadata.Comment;
dateString = metadata.DateTaken;
}
}
}
当我加载100个文件时,我没有得到OutOfMemoryException。
如果有人有改进建议或其他注释,我将很高兴听到他们。
答案 1 :(得分:0)
首先,不要两次加载元数据。您的GetPhotoComment
和GetPhotoDate
方法应该采用BitmapMetadata
而不是FileInfo
。
然后,您应该尝试使用BitmapCacheOption.None
。有关不同的可用值,请参阅the documentation。
最后,您向我们展示的formMain
中的所有方法都应该放在他们自己的类中。它们没有理由在表单类中,它们与用户界面无关。我会通过以下方式解决这个问题:
PhotoFactory
作为参数的构造函数创建一个类selectedFolder
。formMain
中创建该类的实例,并将其传递给formPleaseWait
formMain
。