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


    在 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数据库的时候,发现图片显示不正常,需要对图片进行十六进制转换才能正常显示。

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

    2、解决问题

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

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

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

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

    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 数据库,并且正常获取并显示图片。

     

  • 相关阅读:
    【PCB绘制】Altium Designer 20 使用教程
    (C++版)ROS2 bind函数解读
    GitHub学习(三)
    java基于springboot+vue的酒店预订网站——计算机毕业设计
    个人博客系列-后端项目-用户验证(5)
    Node.js
    Flutter 3.3 之 SelectionArea 好不好用?用 “Bug” 带你全面了解它
    面向对象分析与设计(图书管理系统)--实验4活动图
    java 线程安全问题 三种线程同步方案 线程通信(了解)
    剑指 Offer 10- I. 斐波那契数列
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/18088886