1

这是我对图像进行序列化、反序列化和保存到文件系统的代码。我看过很多序列化/反序列化的例子,我只是想得到一些反馈,因为我确信我的代码可以改进。任何反馈将不胜感激。我知道这是一个常见问题,所以希望这个问题将来能成为其他人的一个很好的资源。

这是使用建议的修改后的代码:

    private void Form1_Load(object sender, EventArgs e)
    {
        RunTest();
    }

    private void RunTest()
    {
        byte[] jpgba = ConvertFileToByteArray("D:\\Images\\Image01.jpg");
        using (Image jpgimg = ConvertByteArrayToImage(jpgba))
        {
            SaveImageToFileSystem(jpgimg, "D:\\Images\\Image01_Copy.jpg");
        }

        byte[] pngba = ConvertFileToByteArray("D:\\Images\\Image02.png");
        using (Image pngimg = ConvertByteArrayToImage(pngba))
        {
            SaveImageToFileSystem(pngimg, "D:\\Images\\Image02_Copy.png");
        }

        byte[] gifba = ConvertFileToByteArray("D:\\Images\\Image03.gif");
        using (Image gifimg = ConvertByteArrayToImage(gifba))
        {
            SaveImageToFileSystem(gifimg, "D:\\Images\\Image03_Copy.gif");
        }

        MessageBox.Show("Test Complete");
        this.Close();
    }

    private static byte[] ConvertFileToByteArray(String FilePath)
    {
        return File.ReadAllBytes(FilePath);
    }

    private static Image ConvertByteArrayToImage(byte[] ImageByteArray)
    {
        using (MemoryStream ms = new MemoryStream(ImageByteArray))
        {
            return Image.FromStream(ms);
        }
    }

    private static void SaveImageToFileSystem(Image ImageObject, string FilePath)
    {
        // ImageObject.Save(FilePath, ImageObject.RawFormat);
        // This method only works with .png files.

        // This method works with .jpg, .png and .gif
        // Need to copy image before saving.
        using (Image img = new Bitmap(ImageObject.Width, ImageObject.Height))
        {
            using (Graphics tg = Graphics.FromImage(img))
            {
                tg.DrawImage(ImageObject, 0, 0);
            }
            img.Save(FilePath, img.RawFormat);
        }
        return;
    }
4

3 回答 3

3

我从快速浏览中看到的:

流应该包装在using(...)模式中,如果在处理过程中发生异常,则不会调用 Dispose() 。

using (FileStream fs = new FileStream(FilePath, FileMode.Open))
{
    // Another small optimization, removed unnecessary variable 
    byte[] iba = new byte[(int)fs.Length];
    fs.Read(iba, 0, iba.Length);
}

您应该只捕获您期望的异常。例如,在 SerializeImage 中,这将是IOException。捕获所有异常是非常糟糕的做法。

}
catch (IOException ex)
{

Image.FromStream 方法依赖于流,因此如果关闭底层流并返回 Image,您可能会收到不可预知的行为(嗯,在大多数情况下这会起作用,但有时会发生错误)。因此,您需要创建图像副本并将其返回。

using (MemoryStream ms = new MemoryStream(ImageByteArray))
{
    using (Image img = Image.FromStream(ms))
    {
        return new Bitmap(img);
    }
}

您没有在 SaveImage 方法中处理 tg 图形对象和 img 对象(而是处理了 ImageObject,请参见下一段)。总的来说,我认为这种逻辑没有必要,如果您想保存图像保留质量,只需调用 ImageObject.Save(..., ImageFormat.Png) 即可。

在同一方法 (SaveImage) 中,您将设置 ImageObject 参数。在大多数情况下,这也是不好的做法,请考虑使用using(...)模式在工作方法之外处理此图像。

于 2009-07-21T00:18:00.877 回答
1

这里还有一点:

private void RunTest()
{
    // byte array that can be stored in DB
    byte[] iba;

    // image object to display in picturebox or used to save to file system.

    iba = ReadImage("D:\\Images\\Image01.jpg");
    using (Image img = DeserializeImage(iba))
    {
        SaveImage(img, "D:\\Images\\Image01_Copy.jpg");
    }

    iba = ReadImage("D:\\Images\\Image02.png");
    using (Image img1 = DeserializeImage(iba))
    {
        SaveImage(img1, "D:\\Images\\Image02_Copy.png");
    }

    iba = ReadImage("D:\\Images\\Image03.gif");
    using (var img2 = DeserializeImage(iba))
    {
        SaveImage(img2, "D:\\Images\\Image03_Copy.gif");
    }

    MessageBox.Show("Test Complete");
}

private static byte[] ReadImage(String filePath)
{
    // This seems to be the easiest way to serialize an image file
    // however it would be good to take a image object as an argument
    // in this method.
    using (var fs = new FileStream(filePath, FileMode.Open))
    {
        Int32 fslength = Convert.ToInt32(fs.Length);
        var iba = new byte[fslength];
        fs.Read(iba, 0, fslength);
        return iba;
    }
}

private static Image DeserializeImage(byte[] imageByteArray)
{
    using (var ms = new MemoryStream(imageByteArray))
    {
        return Image.FromStream(ms);
    }
}

private static void SaveImage(Image imageObject, string filePath)
{
    // I could only get this method to work for .png files.
    // imageObject.Save(filePath, imageObject.RawFormat);

    // This method works with .jpg, .png and .gif
    // Need to copy image before saving.
    using (Image img = new Bitmap(imageObject.Width, imageObject.Height))
    {
        using (Graphics tg = Graphics.FromImage(img))
        {
            tg.DrawImage(imageObject, 0, 0);
        }

        img.Save(filePath, img.RawFormat);
    }

    return;
}

请注意,您所谓的序列化只是读取字节。序列化更多的是您在保存时所做的事情。

我摆脱了所有的 try/catch 块。他们为您做的最好的事情就是告诉您问题是否发生在读取、保存或反序列化中。您可以通过仅显示 ex.Message 来破坏堆栈跟踪来确定这一点。

您还返回 null 一个严重的异常,传播失败。

除此之外,我同意仲裁者所说的一切。

于 2009-07-21T00:36:13.860 回答
0

正如 John Saunder 所说,序列化和反序列化不仅仅是从文件中读取原始数据。参见 Wiki 关于序列化

对于 .net 中的图像,除了提供的框架方法之外,您不需要使用任何其他方法(大多数情况下)

所以在.net中加载图像(反序列化)是。

using System.Drawing.Image;

Image test;

test = Image.FromFile(@"C:\myfile.jpg")
test = Image.FromStream(myStream); // or you can load from an existing stream

同样,保存图像(序列化)是:

test.Save(@"C:\anotherFile.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);

这些是在 .net 中加载和保存图像的基础知识。如果您有更具体的情况,请提出另一个问题。

于 2009-07-21T00:50:56.017 回答