0

在 PostgreSQL 中,解决图片二进制数据,由于bytea_output参数问题导致显示不正常的问...

 1 month ago
source link: https://www.cnblogs.com/wuhuacong/p/18088886
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在 PostgreSQL 中,bytea_output 参数控制在查询结果中 bytea 类型的显示格式。默认情况下,bytea_output 的值为 hex,这意味着在查询结果中,bytea 类型的数据以十六进制格式显示。但是,如果你的应用程序期望以二进制格式获取图像数据,则将 bytea_output 设置为 escape 可能更适合。无论 bytea_output 参数设置为 hex 还是 escape,你都可以通过 C# 访问 PostgreSQL 数据库,并且正常获取并显示图片。本篇随笔介绍这个问题的处理过程。

1、碰到的数据库图片在界面显示问题

在我们的Winform框架中,由于底层是支持多种数据库的设计,因此可以兼容MS SQLServer、Oracle、Mysql、PostgreSQL、SQLite等数据库的,但是一般我们用的是SQLServer、MySql居多,有客户切换到PostgreSQL数据库的时候,发现图片显示不正常,需要对图片进行十六进制转换才能正常显示。

8867-20240322095814685-535926413.png
8867-20240322100046741-996463701.png

 默认的方式,这里方框在SQLServer等数据库上是正常显示图标的,打开编辑也是可以展示菜单的图表的,不过由于切换到PostgreSQL后,这里图标消失,检查数据库操作,默认的处理都是一致的,因此考虑是否为数据库参数配置问题。

2、解决问题

打开ChatGPT,或者百度、Google一下,细心都可以发现,在 PostgreSQL 中默认情况下,bytea_output 的值为 hex,这意味着在查询结果中,bytea 类型的数据以十六进制格式显示。如果你的应用程序期望以二进制格式获取图像数据,则将 bytea_output 设置为 escape 可能更适合。

我们找到PostgreSQL的安装目录,找到 C:\Program Files\PostgreSQL\13\data\postgresql.conf里面的数据库配置文件,找到bytea_output 的值查看。

8867-20240322100538609-1192375487.png

果然发现其默认值为hex,我们按要求修改为 escape,并去掉注释符号#,如下所示。

8867-20240322100735180-398356701.png

 重启PostgreSQL,并测试系统数据库,显示和保存处理正常。

8867-20240322101456435-1096368530.png

3、两种方式处理的差异

 如果 bytea_output 参数设置为 hex,你可以通过将读取到的十六进制字符串转换为字节数组,然后使用这些字节数组来创建图像对象。以下是一个示例代码,演示了如何在 C# 中获取并显示图片,即使 bytea_output 参数设置为 hex

class Program
{
    static void Main()
    {
        string connString = "Host=myServerAddress;Port=myPort;Username=myUsername;Password=myPassword;Database=myDatabase";

        using (var conn = new NpgsqlConnection(connString))
        {
            conn.Open();

            // 执行 SQL 查询以获取图像数据
            string sql = "SELECT image_column FROM your_table WHERE id = @id";
            int id = 1; // 替换为你要查询的图像的 ID
            using (var cmd = new NpgsqlCommand(sql, conn))
            {
                cmd.Parameters.AddWithValue("@id", id);

                // 读取图像数据
                using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
                {
                    if (reader.Read())
                    {
                        // 获取十六进制字符串
                        string hexString = reader.GetString(0);

                        // 将十六进制字符串转换为字节数组
                        byte[] imageData = StringToByteArray(hexString);

                        // 创建图像对象
                        using (MemoryStream ms = new MemoryStream(imageData))
                        {
                            Image image = Image.FromStream(ms);

                            // 显示图像
                            ShowImage(image);
                        }
                    }
                }
            }
        }
    }

    static void ShowImage(Image image)
    {
        // 创建一个新的窗体
        using (var form = new System.Windows.Forms.Form())
        {
            // 创建 PictureBox 控件
            var pictureBox = new System.Windows.Forms.PictureBox();
            pictureBox.Dock = System.Windows.Forms.DockStyle.Fill;
            pictureBox.Image = image;

            // 将 PictureBox 添加到窗体中
            form.Controls.Add(pictureBox);

            // 设置窗体大小并显示
            form.Size = new System.Drawing.Size(image.Width, image.Height);
            form.ShowDialog();
        }
    }

    static byte[] StringToByteArray(string hex)
    {
        int NumberChars = hex.Length / 2;
        byte[] bytes = new byte[NumberChars];
        using (var sr = new StringReader(hex))
        {
            for (int i = 0; i < NumberChars; i++)
                bytes[i] = Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
        }
        return bytes;
    }
}

如果 bytea_output 参数设置为 escape,则可以直接使用 Npgsql 从数据库中读取图像数据,并将其转换为字节数组,而不需要进行额外的处理。以下是示例代码:

using Npgsql;
using System;
using System.Data;
using System.Drawing;
using System.IO;

class Program
{
    static void Main()
    {
        string connString = "Host=myServerAddress;Port=myPort;Username=myUsername;Password=myPassword;Database=myDatabase";

        using (var conn = new NpgsqlConnection(connString))
        {
            conn.Open();

            // 执行 SQL 查询以获取图像数据
            string sql = "SELECT image_column FROM your_table WHERE id = @id";
            int id = 1; // 替换为你要查询的图像的 ID
            using (var cmd = new NpgsqlCommand(sql, conn))
            {
                cmd.Parameters.AddWithValue("@id", id);

                // 读取图像数据
                using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
                {
                    if (reader.Read())
                    {
                        // 获取图像数据字节数组
                        byte[] imageData = (byte[])reader["image_column"];

                        // 创建图像对象
                        using (MemoryStream ms = new MemoryStream(imageData))
                        {
                            Image image = Image.FromStream(ms);

                            // 显示图像
                            ShowImage(image);
                        }
                    }
                }
            }
        }
    }

    static void ShowImage(Image image)
    {
        // 创建一个新的窗体
        using (var form = new System.Windows.Forms.Form())
        {
            // 创建 PictureBox 控件
            var pictureBox = new System.Windows.Forms.PictureBox();
            pictureBox.Dock = System.Windows.Forms.DockStyle.Fill;
            pictureBox.Image = image;

            // 将 PictureBox 添加到窗体中
            form.Controls.Add(pictureBox);

            // 设置窗体大小并显示
            form.Size = new System.Drawing.Size(image.Width, image.Height);
            form.ShowDialog();
        }
    }
}

无论 bytea_output 参数设置为 hex 还是 escape,你都可以通过 C# 访问 PostgreSQL 数据库,并且正常获取并显示图片。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK