C#基于ScottPlot进行可视化

前言

上一篇文章跟大家分享了用NumSharp实现简单的线性回归,但是没有进行可视化,可能对拟合的过程没有直观的感受,因此今天跟大家介绍一下使用C#基于Scottplot进行可视化,当然Python的代码,我也会同步进行可视化。

Python代码进行可视化

Python代码用matplotlib做了可视化,我就不具体介绍了。

修改之后的python代码如下:

#The optimal values of m and b can be actually calculated with way less effort than doing a linear regression. 
#this is just to demonstrate gradient descent

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation


# y = mx + b
# m is slope, b is y-intercept
def compute_error_for_line_given_points(b, m, points):
    totalError = 0
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        totalError += (y - (m * x + b)) ** 2
    return totalError / float(len(points))

def step_gradient(b_current, m_current, points, learningRate):
    b_gradient = 0
    m_gradient = 0
    N = float(len(points))
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        b_gradient += -(2/N) * (y - ((m_current * x) + b_current))
        m_gradient += -(2/N) * x * (y - ((m_current * x) + b_current))
    new_b = b_current - (learningRate * b_gradient)
    new_m = m_current - (learningRate * m_gradient)
    return [new_b, new_m]

def gradient_descent_runner(points, starting_b, starting_m, learning_rate, num_iterations):
    b = starting_b
    m = starting_m
    args_data = []
    for i in range(num_iterations):
        b, m = step_gradient(b, m, np.array(points), learning_rate)
        args_data.append((b,m))
    return args_data

if __name__ == '__main__':
     points = np.genfromtxt("data.csv", delimiter=",")
     learning_rate = 0.0001
     initial_b = 0 # initial y-intercept guess
     initial_m = 0 # initial slope guess
     num_iterations = 10
     print ("Starting gradient descent at b = {0}, m = {1}, error = {2}".format(initial_b, initial_m, compute_error_for_line_given_points(initial_b, initial_m, points)))
     print ("Running...")
     args_data = gradient_descent_runner(points, initial_b, initial_m, learning_rate, num_iterations)
     
     b = args_data[-1][0]
     m = args_data[-1][1]

     print ("After {0} iterations b = {1}, m = {2}, error = {3}".format(num_iterations, b, m, compute_error_for_line_given_points(b, m, points)))
    
     data = np.array(points).reshape(100,2)
     x1 = data[:,0]
     y1 = data[:,1]
     
     x2 = np.linspace(20, 80, 100)
     y2 = initial_m * x2 + initial_b

     data2 = np.array(args_data)
     b_every = data2[:,0]
     m_every = data2[:,1]

     # 创建图形和轴
     fig, ax = plt.subplots()
     line1, = ax.plot(x1, y1, 'ro')
     line2, = ax.plot(x2,y2)

     # 添加标签和标题
     plt.xlabel('x')
     plt.ylabel('y')
     plt.title('Graph of y = mx + b')

     # 添加网格
     plt.grid(True)

    # 定义更新函数
     def update(frame):
        line2.set_ydata(m_every[frame] * x2 + b_every[frame])
        ax.set_title(f'{frame} Graph of y = {m_every[frame]:.2f}x + {b_every[frame]:.2f}')
    
# 创建动画
animation = FuncAnimation(fig, update, frames=len(data2), interval=500)

# 显示动画
plt.show()

实现的效果如下所示:

python代码的可视化

image-20240113200232614

C#代码进行可视化

这是本文重点介绍的内容,本文的C#代码通过Scottplot进行可视化。

Scottplot简介

ScottPlot 是一个免费的开源绘图库,用于 .NET,可以轻松以交互方式显示大型数据集。

控制台程序可视化

首先我先介绍一下在控制台程序中进行可视化。

首先添加Scottplot包:

image-20240113201207374

将上篇文章中的C#代码修改如下:

using NumSharp;

namespace LinearRegressionDemo
{
    internal class Program
    {    
        static void Main(string[] args)
        {   
            //创建double类型的列表
            List<double> Array = new List<double>();
            List<double> ArgsList = new List<double>();

            // 指定CSV文件的路径
            string filePath = "你的data.csv路径";

            // 调用ReadCsv方法读取CSV文件数据
            Array = ReadCsv(filePath);

            var array = np.array(Array).reshape(100,2);

            double learning_rate = 0.0001;
            double initial_b = 0;
            double initial_m = 0;
            double num_iterations = 10;

            Console.WriteLine($"Starting gradient descent at b = {initial_b}, m = {initial_m}, error = {compute_error_for_line_given_points(initial_b, initial_m, array)}");
            Console.WriteLine("Running...");
            ArgsList = gradient_descent_runner(array, initial_b, initial_m, learning_rate, num_iterations);
            double b = ArgsList[ArgsList.Count - 2];
            double m = ArgsList[ArgsList.Count - 1];
            Console.WriteLine($"After {num_iterations} iterations b = {b}, m = {m}, error = {compute_error_for_line_given_points(b, m, array)}");
            Console.ReadLine();

            var x1 = array[$":", 0];
            var y1 = array[$":", 1];
            var y2 = m * x1 + b;

            ScottPlot.Plot myPlot = new(400, 300);
            myPlot.AddScatterPoints(x1.ToArray<double>(), y1.ToArray<double>(), markerSize: 5);
            myPlot.AddScatter(x1.ToArray<double>(), y2.ToArray<double>(), markerSize: 0);
            myPlot.Title($"y = {m:0.00}x + {b:0.00}");

            myPlot.SaveFig("图片.png");
       
        }

        static List<double> ReadCsv(string filePath)
        {
            List<double> array = new List<double>();
            try
            {
                // 使用File.ReadAllLines读取CSV文件的所有行
                string[] lines = File.ReadAllLines(filePath);             

                // 遍历每一行数据
                foreach (string line in lines)
                {
                    // 使用逗号分隔符拆分每一行的数据
                    string[] values = line.Split(',');

                    // 打印每一行的数据
                    foreach (string value in values)
                    {
                        array.Add(Convert.ToDouble(value));
                    }                  
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("发生错误: " + ex.Message);
            }
            return array;
        }

        public static double compute_error_for_line_given_points(double b,double m,NDArray array)
        {
            double totalError = 0;
            for(int i = 0;i < array.shape[0];i++)
            {
                double x = array[i, 0];
                double y = array[i, 1];
                totalError += Math.Pow((y - (m*x+b)),2);
            }
            return totalError / array.shape[0];
        }

        public static double[] step_gradient(double b_current,double m_current,NDArray array,double learningRate)
        {
            double[] args = new double[2];
            double b_gradient = 0;
            double m_gradient = 0;
            double N = array.shape[0];

            for (int i = 0; i < array.shape[0]; i++)
            {
                double x = array[i, 0];
                double y = array[i, 1];
                b_gradient += -(2 / N) * (y - ((m_current * x) + b_current));
                m_gradient += -(2 / N) * x * (y - ((m_current * x) + b_current));
            }

            double new_b = b_current - (learningRate * b_gradient);
            double new_m = m_current - (learningRate * m_gradient);
            args[0] = new_b;
            args[1] = new_m;

            return args;
        }

        public static List<double> gradient_descent_runner(NDArray array, double starting_b, double starting_m, double learningRate,double num_iterations)
        {
            double[] args = new double[2];
            List<double> argsList = new List<double>();
            args[0] = starting_b;
            args[1] = starting_m;

            for(int i = 0 ; i < num_iterations; i++) 
            {
                args = step_gradient(args[0], args[1], array, learningRate);
                argsList.AddRange(args);
            }

            return argsList;
        }


    }
}

然后得到的图片如下所示:

image-20240113202345301

在以上代码中需要注意的地方:

  var x1 = array[$":", 0];
  var y1 = array[$":", 1];

是在使用NumSharp中的切片,x1表示所有行的第一列,y1表示所有行的第二列。

当然我们不满足于只是保存图片,在控制台应用程序中,再添加一个 ScottPlot.WinForms包:

image-20240113202751162

右键控制台项目选择属性,将目标OS改为Windows:

image-20240113212334704

将上述代码中的

  myPlot.SaveFig("图片.png");

修改为:

 var viewer = new ScottPlot.FormsPlotViewer(myPlot);
 viewer.ShowDialog();

再次运行结果如下:

image-20240113203022718

winform进行可视化

我也想像Python代码中那样画动图,因此做了个winform程序进行演示。

首先创建一个winform,添加ScottPlot.WinForms包,然后从工具箱中添加FormsPlot这个控件:

image-20240113205227384

有两种方法实现,第一种方法用了定时器:

using NumSharp;
namespace WinFormDemo
{
    public partial class Form1 : Form
    {
        System.Windows.Forms.Timer updateTimer = new System.Windows.Forms.Timer();
        int num_iterations;
        int count = 0;
        NDArray? x1, y1, b_each, m_each;
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            StartLinearRegression();
        }

        public void StartLinearRegression()
        {
            //创建double类型的列表
            List<double> Array = new List<double>();
            List<double> ArgsList = new List<double>();

            // 指定CSV文件的路径
            string filePath = "你的data.csv路径";

            // 调用ReadCsv方法读取CSV文件数据
            Array = ReadCsv(filePath);

            var array = np.array(Array).reshape(100, 2);

            double learning_rate = 0.0001;
            double initial_b = 0;
            double initial_m = 0;
            num_iterations = 10;

            ArgsList = gradient_descent_runner(array, initial_b, initial_m, learning_rate, num_iterations);

            x1 = array[$":", 0];
            y1 = array[$":", 1];

            var argsArr = np.array(ArgsList).reshape(num_iterations, 2);
            b_each = argsArr[$":", 0];
            m_each = argsArr[$":", 1];

            double b = b_each[-1];
            double m = m_each[-1];
            var y2 = m * x1 + b;

            formsPlot1.Plot.AddScatterPoints(x1.ToArray<double>(), y1.ToArray<double>(), markerSize: 5);
            //formsPlot1.Plot.AddScatter(x1.ToArray<double>(), y2.ToArray<double>(), markerSize: 0);
            formsPlot1.Render();


        }

        static List<double> ReadCsv(string filePath)
        {
            List<double> array = new List<double>();
            try
            {
                // 使用File.ReadAllLines读取CSV文件的所有行
                string[] lines = File.ReadAllLines(filePath);

                // 遍历每一行数据
                foreach (string line in lines)
                {
                    // 使用逗号分隔符拆分每一行的数据
                    string[] values = line.Split(',');

                    // 打印每一行的数据
                    foreach (string value in values)
                    {
                        array.Add(Convert.ToDouble(value));
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("发生错误: " + ex.Message);
            }
            return array;
        }

        public static double compute_error_for_line_given_points(double b, double m, NDArray array)
        {
            double totalError = 0;
            for (int i = 0; i < array.shape[0]; i++)
            {
                double x = array[i, 0];
                double y = array[i, 1];
                totalError += Math.Pow((y - (m * x + b)), 2);
            }
            return totalError / array.shape[0];
        }

        public static double[] step_gradient(double b_current, double m_current, NDArray array, double learningRate)
        {
            double[] args = new double[2];
            double b_gradient = 0;
            double m_gradient = 0;
            double N = array.shape[0];

            for (int i = 0; i < array.shape[0]; i++)
            {
                double x = array[i, 0];
                double y = array[i, 1];
                b_gradient += -(2 / N) * (y - ((m_current * x) + b_current));
                m_gradient += -(2 / N) * x * (y - ((m_current * x) + b_current));
            }

            double new_b = b_current - (learningRate * b_gradient);
            double new_m = m_current - (learningRate * m_gradient);
            args[0] = new_b;
            args[1] = new_m;

            return args;
        }

        public static List<double> gradient_descent_runner(NDArray array, double starting_b, double starting_m, double learningRate, double num_iterations)
        {
            double[] args = new double[2];
            List<double> argsList = new List<double>();
            args[0] = starting_b;
            args[1] = starting_m;

            for (int i = 0; i < num_iterations; i++)
            {
                args = step_gradient(args[0], args[1], array, learningRate);
                argsList.AddRange(args);
            }

            return argsList;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            // 初始化定时器
            updateTimer.Interval = 1000; // 设置定时器触发间隔(毫秒)
            updateTimer.Tick += UpdateTimer_Tick;
            updateTimer.Start();
        }

        private void UpdateTimer_Tick(object? sender, EventArgs e)
        {
            if (count >= num_iterations)
            {
                updateTimer.Stop();
            }
            else
            {
                UpdatePlot(count);
            }

            count++;
        }

        public void UpdatePlot(int count)
        {

            double b = b_each?[count];
            double m = m_each?[count];

            var y2 = m * x1 + b;

            formsPlot1.Plot.Clear();
            formsPlot1.Plot.AddScatterPoints(x1?.ToArray<double>(), y1?.ToArray<double>(), markerSize: 5);
            formsPlot1.Plot.AddScatter(x1?.ToArray<double>(), y2.ToArray<double>(), markerSize: 0);
            formsPlot1.Plot.Title($"第{count + 1}次迭代:y = {m:0.00}x + {b:0.00}");
            formsPlot1.Render();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            updateTimer.Stop();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}

简单介绍一下思路,首先创建List<double> argsList用来保存每次迭代生成的参数b、m,然后用

           var argsArr = np.array(ArgsList).reshape(num_iterations, 2);  

argsList通过np.array()方法转化为NDArray,然后再调用reshape方法,转化成行数等于迭代次数,列数为2,即每一行对应一组参数值b、m。

            b_each = argsArr[$":", 0];
            m_each = argsArr[$":", 1];

argsArr[$":", 0]表示每一行中第一列的值,也就是每一个b,argsArr[$":", 1]表示每一行中第二列的值。

            double b = b_each[-1];
            double m = m_each[-1];

b_each[-1]用了NumSharp的功能表示b_each最后一个元素。

实现效果如下所示:

winform绘图效果1

另一种方法可以通过异步实现:

using NumSharp;

namespace WinFormDemo
{
    public partial class Form2 : Form
    {      
        int num_iterations;
        NDArray? x1, y1, b_each, m_each;
        public Form2()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            StartLinearRegression();
        }

        public void StartLinearRegression()
        {
            //创建double类型的列表
            List<double> Array = new List<double>();
            List<double> ArgsList = new List<double>();

            // 指定CSV文件的路径
            string filePath = "你的data.csv路径";

            // 调用ReadCsv方法读取CSV文件数据
            Array = ReadCsv(filePath);

            var array = np.array(Array).reshape(100, 2);

            double learning_rate = 0.0001;
            double initial_b = 0;
            double initial_m = 0;
            num_iterations = 10;

            ArgsList = gradient_descent_runner(array, initial_b, initial_m, learning_rate, num_iterations);

            x1 = array[$":", 0];
            y1 = array[$":", 1];

            var argsArr = np.array(ArgsList).reshape(num_iterations, 2);
            b_each = argsArr[$":", 0];
            m_each = argsArr[$":", 1];

            double b = b_each[-1];
            double m = m_each[-1];
            var y2 = m * x1 + b;

            formsPlot1.Plot.AddScatterPoints(x1.ToArray<double>(), y1.ToArray<double>(), markerSize: 5);      
            formsPlot1.Render();
        }

        static List<double> ReadCsv(string filePath)
        {
            List<double> array = new List<double>();
            try
            {
                // 使用File.ReadAllLines读取CSV文件的所有行
                string[] lines = File.ReadAllLines(filePath);

                // 遍历每一行数据
                foreach (string line in lines)
                {
                    // 使用逗号分隔符拆分每一行的数据
                    string[] values = line.Split(',');

                    // 打印每一行的数据
                    foreach (string value in values)
                    {
                        array.Add(Convert.ToDouble(value));
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("发生错误: " + ex.Message);
            }
            return array;
        }

        public static double compute_error_for_line_given_points(double b, double m, NDArray array)
        {
            double totalError = 0;
            for (int i = 0; i < array.shape[0]; i++)
            {
                double x = array[i, 0];
                double y = array[i, 1];
                totalError += Math.Pow((y - (m * x + b)), 2);
            }
            return totalError / array.shape[0];
        }

        public static double[] step_gradient(double b_current, double m_current, NDArray array, double learningRate)
        {
            double[] args = new double[2];
            double b_gradient = 0;
            double m_gradient = 0;
            double N = array.shape[0];

            for (int i = 0; i < array.shape[0]; i++)
            {
                double x = array[i, 0];
                double y = array[i, 1];
                b_gradient += -(2 / N) * (y - ((m_current * x) + b_current));
                m_gradient += -(2 / N) * x * (y - ((m_current * x) + b_current));
            }

            double new_b = b_current - (learningRate * b_gradient);
            double new_m = m_current - (learningRate * m_gradient);
            args[0] = new_b;
            args[1] = new_m;

            return args;
        }

        public static List<double> gradient_descent_runner(NDArray array, double starting_b, double starting_m, double learningRate, double num_iterations)
        {
            double[] args = new double[2];
            List<double> argsList = new List<double>();
            args[0] = starting_b;
            args[1] = starting_m;

            for (int i = 0; i < num_iterations; i++)
            {
                args = step_gradient(args[0], args[1], array, learningRate);
                argsList.AddRange(args);
            }

            return argsList;
        }

        private void Form2_Load(object sender, EventArgs e)
        {

        }

        public async Task UpdateGraph()
        {
            for (int i = 0; i < num_iterations; i++)
            {
                double b = b_each?[i];
                double m = m_each?[i];
                var y2 = m * x1 + b;

                formsPlot1.Plot.Clear();
                formsPlot1.Plot.AddScatterPoints(x1?.ToArray<double>(), y1?.ToArray<double>(), markerSize: 5);
                formsPlot1.Plot.AddScatter(x1?.ToArray<double>(), y2.ToArray<double>(), markerSize: 0);
                formsPlot1.Plot.Title($"第{i + 1}次迭代:y = {m:0.00}x + {b:0.00}");
                formsPlot1.Render();
           
                await Task.Delay(1000);
            }


        }

        private async void button2_Click(object sender, EventArgs e)
        {
            await UpdateGraph();
        }
    }
}

点击更新按钮开始执行异步任务:

 private async void button2_Click(object sender, EventArgs e)
        {
            await UpdateGraph();
        }
 public async Task UpdateGraph()
        {
            for (int i = 0; i < num_iterations; i++)
            {
                double b = b_each?[i];
                double m = m_each?[i];
                var y2 = m * x1 + b;

                formsPlot1.Plot.Clear();
                formsPlot1.Plot.AddScatterPoints(x1?.ToArray<double>(), y1?.ToArray<double>(), markerSize: 5);
                formsPlot1.Plot.AddScatter(x1?.ToArray<double>(), y2.ToArray<double>(), markerSize: 0);
                formsPlot1.Plot.Title($"第{i + 1}次迭代:y = {m:0.00}x + {b:0.00}");
                formsPlot1.Render();
           
                await Task.Delay(1000);
            }

实现效果如下:

winform绘图效果2

image-20240113210320131

总结

本文以一个控制台应用与一个winform程序为例向大家介绍了C#如何基于ScottPlot进行数据可视化,并介绍了实现动态绘图的两种方式,一种是使用定时器,另一种是使用异步操作,希望对你有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/317725.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

虚幻引擎nDisplay教程:如何同步nDisplay节点与Switchboard + Helix Core

对于使用大型LED屏幕进行拍摄的虚拟制作团队来说&#xff0c;虚幻&#xff08;Unreal&#xff09;的nDisplay是一个重要的工具。但是&#xff0c;在nDisplay中将正确版本的文件发送到每个节点会非常耗时。立即阅读本文&#xff0c;您将了解到如何使用Perforce Helix Core版本控…

【b站咸虾米】新课uniapp零基础入门到项目打包(微信小程序/H5/vue/安卓apk)全掌握

课程地址&#xff1a;【新课uniapp零基础入门到项目打包&#xff08;微信小程序/H5/vue/安卓apk&#xff09;全掌握】 https://www.bilibili.com/video/BV1mT411K7nW/?p12&share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 三、vue语法 继续回到官…

Python之jieba分词相关介绍

1.jieba分词的安装 直接在cmd窗口当中pip install即可 2.jieba分词的介绍 jieba分词是目前比较好的中文分词组件之一&#xff0c;jieba分词支持三种模式的分词(精确模式、全模式、搜索引擎模式)&#xff0c;并且支持自定义词典(这一点在特定的领域很重要&#xff0c;有时候…

VMware workstation搭建与安装AlmaLinux-9.2虚拟机

VMware workstation搭建与安装AlmaLinux-9.2虚拟机 适用于需要在VMware workstation平台安装AlmaLinux-9.2&#xff08;最小化安装、无图形化界面&#xff09;虚拟机。 1. 安装准备 1.1 安装平台 Windows 11 1.2. 软件信息 软件名称软件版本安装路径VMware-workstation 1…

【前端素材】bootstrap5实现美食餐饮网站RegFood

一、需求分析 美食餐饮网站是指专门提供关于美食和餐饮的信息、服务和资源的在线平台。这类网站通常提供以下功能&#xff1a; 餐厅搜索和预订&#xff1a;用户可以在网站上搜索附近的餐厅&#xff0c;并预订桌位。网站会提供餐厅的详细信息&#xff0c;包括菜单、地址、电话号…

Jmeter 性能-监控服务器

Jmeter监控Linux需要三个文件 JMeterPlugins-Extras.jar (包&#xff1a;JMeterPlugins-Extras-1.4.0.zip) JMeterPlugins-Standard.jar (包&#xff1a;JMeterPlugins-Standard-1.4.0.zip) ServerAgent-2.2.3.zip 1、Jemter 安装插件 在插件管理中心的搜索Servers Perform…

JDK介绍

JDK(Java Development Kit)是Sun Microsystems针对Java开发员的产品。自从Java推出以来&#xff0c;JDK已经成为使用最广泛的Java SDK&#xff08;Software development kit&#xff09;&#xff0c;JDK是一个写Java的applet和应用程序的程序开发环境。它由一个处于操作系统层之…

vue3-计算属性

计算属性 模板中的表达式虽然方便&#xff0c;但也只能用来做简单的操作。如果在模板中写太多逻辑&#xff0c;会让模板变得臃肿&#xff0c;难以维护。 根据作者今年是否看过书展示不同信息 <script lang"ts" setup> import { ref, reactive } from "…

C++11 14 17内存管理

智能指针 unique_ptr 初始化 访问和移动赋值 重置和移动内存资源 自定义删除器 shared_ptr 原理 自定义删除器 分配器allocator和new重载 new表达式原理 operator new delete placement new new (buf) 是一种 "placement new" 的使用方式&#xff0c;它允许在已…

thinkphp学习06-连接数据库与模型初探

新建数据库 CREATE DATABASE tp6stu01 CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;创建表和数据 DROP TABLE IF EXISTS tp_user; CREATE TABLE tp_user (id mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 自动编号,username varchar(20) CHARACTER SET utf8 COLL…

绘制几何图形(Shape)

目录 1、创建绘制组件 2、形状视口viewport 3、自定义样式 4、场景示例 绘制组件用于在页面绘制图形&#xff0c;Shape组件是绘制组件的父组件&#xff0c;父组件中会描述所有绘制组件均支持的通用属性。具体用法请参考Shape。 1、创建绘制组件 绘制组件可以由以下两种形式…

Spring MVC的RequestMapping注解、controller方法返回值

1.使用说明 作用&#xff1a;用于建立请求URL和处理请求方法之间的对应关系。 出现位置&#xff1a; 类上&#xff1a; 请求 URL的第一级访问目录。此处不写的话&#xff0c;就相当于应用的根目录。写的话需要以/开头。它出现的目的是为了使我们的 URL 可以按照模块化管理&…

Netty开篇——NIO章上(三)

Java NIO基本介绍 java non-blocking I/O 称为NIO(也叫New IO)。JDK4开始提供,同步非阻塞相关内容在 java.nio 包及子包下&#xff0c;对java.io 包中的很多类进行改写。三大核心: Channel(通道)&#xff0c;Buffer(缓冲区),Selector(选择器)NIO是面向缓冲区或者面向块编程的。…

企业网站建设中常用的英文翻译

下面好代码网在长期的网站建设业务中总结的&#xff0c;一些在企业网站建设中词语的常用翻译&#xff0c;可以让你的企业网站更具有专业性。如果你做中英文双语版本网站或者外贸网站的请收藏备用。 网站导航 site map 公司简介 PROFILE or COMPANY Profile or Company 综述 Gen…

Java文件自动生成文档

说明 此文章根据Gemini Pro 生成资料整理。 生成文档 javadoc -d mydoc -author -version HelloWorld.java javadoc -d mydoc -author -version HelloWorld.java 命令用于生成 Java 源文件的javadoc文档&#xff0c;并将javadoc文档输出到 mydoc 目录中。 javadoc&#xf…

【SQL注入】SQLMAP v1.7.11.1 汉化版

下载链接 【SQL注入】SQLMAP v1.7.11.1 汉化版 简介 SQLMAP是一款开源的自动化SQL注入工具&#xff0c;用于扫描和利用Web应用程序中的SQL注入漏洞。它在安全测试领域被广泛应用&#xff0c;可用于检测和利用SQL注入漏洞&#xff0c;以验证应用程序的安全性。 SQL注入是一种…

【服务器数据恢复】Hyper-V虚拟化数据恢复案例

服务器数据恢复环境&#xff1a; Windows Server操作系统服务器&#xff0c;部署Hyper-V虚拟化环境&#xff0c;虚拟机的硬盘文件和配置文件存放在某品牌MD3200存储中&#xff0c;MD3200存储中有一组由4块硬盘组成的raid5阵列&#xff0c;存放虚拟机的数据文件&#xff1b;另外…

C++11 左右值引用、移动语义

右值引用和移动语义 什么是左值&#xff1f;什么是左值引用&#xff1f; 左值是一个表示数据的表达式(如变量名或解引用的指针)&#xff0c;我们可以获取它的地址可以对它赋值&#xff0c;左值可以出现赋值符号的左边&#xff0c;右值不能出现在赋值符号左边。定义时const修饰…

Oracle数据库 CentOS7上修改hostname后无法启动解决办法

目录 一、问题背景 二、解决问题 三、重启数据库 四、重启监听 一、问题背景 CentOS系统需要修改hostname&#xff0c;修改后oracle数据库无法启动和正常运行。 系统&#xff1a;CentOS7.3 数据库版本&#xff1a;Oracle 11g Express Edtion 二、解决问题 通过which orac…

迈入AI智能时代!ChatGPT国内版免费AI助手工具 peropure·AI正式上线 一个想法写一首歌?这事AI还真能干!

号外&#xff01;前几天推荐的Peropure.Ai迎来升级&#xff0c;现已支持联网模式&#xff0c;回答更新更准&#xff0c;欢迎注册体验&#xff1a; https://sourl.cn/5T74Hu 相信很多人都有过这样的想法&#xff0c;有没有一首歌能表达自己此时此刻的心情&#xff1a; 当你在深…