c# wpf 加密文本
可以加密人们的内容,文本加密。
界面
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="encryption_note.MainWindow"
Height="700" Width="405.8" Icon="/resources/bitbug_favicon.ico" WindowStartupLocation="CenterScreen" Title="密码本" Unloaded="exit_button">
<Grid x:Name="formMain" KeyDown="fastkey">
<Grid.RowDefinitions>
<RowDefinition Height="20*"/>
<RowDefinition Height="650*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Menu>
<MenuItem Header="文件(_F)">
<MenuItem Header="新建(_N)" Click="new_file_button" >
</MenuItem>
<MenuItem Header="打开(_O)" Click="open_button" >
</MenuItem>
<MenuItem Header="保存(_S)" Click="save_button" IsEnabled="{Binding Path=main_enable,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}">
</MenuItem>
<MenuItem Header="另存为(_A)" Click="save_as_button" IsEnabled="{Binding Path=main_enable,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}">
</MenuItem>
<MenuItem Header="退出(_X)" Click="exit_button" >
</MenuItem>
</MenuItem>
<MenuItem Header="编辑(_E)">
<MenuItem Header="全选(_A)" Click="select_button" IsEnabled="{Binding Path=main_enable,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}">
</MenuItem>
<MenuItem Header="复制(_C)" Click="copy_button" IsEnabled="{Binding Path=main_enable,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}">
</MenuItem>
<MenuItem Header="粘贴(_V)" Click="paste_button" IsEnabled="{Binding Path=main_enable,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}">
</MenuItem>
</MenuItem>
<MenuItem Header="帮助(_H)">
<MenuItem Header="关于(_A)" >
</MenuItem>
</MenuItem>
</Menu>
</Grid>
<Grid Grid.Row="1">
<Grid x:Name="registerGrid" Visibility="{Binding Path=register_visibility,Mode=OneWay}" Background="#FF130464" d:IsHidden="True">
<StackPanel Orientation="Vertical">
<Label x:Name="reminder" HorizontalAlignment="Left" Height="35" Margin="10,270,0,0" Content="{Binding Path=reminder_content,Mode=OneWay}" VerticalAlignment="Top" Width="379" Background="{x:Null}" FontSize="20" BorderBrush="{x:Null}" Foreground="#FFF6F9F7"/>
<PasswordBox x:Name="codeIn" Visibility="{Binding Path=codein_visibility,Mode=OneWay}" HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center" FontSize="26.667" Width="383.335" ToolTip="密码大于10字符"/>
<Button x:Name="registerButton" Content="确定" HorizontalAlignment="Right" Height="33.875" Margin="10,10,10,10" VerticalAlignment="Center" Width="69.633" IsDefault="True" Click="registerButtonClick" />
</StackPanel>
<ProgressBar x:Name="progressBar" Visibility="{Binding Path=progress_bar_visibility,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" IsIndeterminate="True" Height="50" d:IsHidden="True" />
<!--输入密码password_box-->
</Grid>
<Grid x:Name="mainGrid" Visibility="{Binding Path=main_visibility,Mode=OneWay}">
<!--显示密码text-->
<TextBox x:Name="source" Margin="0,0,0,0" TextWrapping="Wrap" Text="{Binding Path=text_string, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" TextOptions.TextFormattingMode="Display" ScrollViewer.CanContentScroll="True" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" LostFocus="source_lostfocus"/>
</Grid>
</Grid>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace encryption_note
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
ViewModel view_model = ViewModel.g_view_model();
public MainWindow()
{
InitializeComponent();
this.DataContext = ViewModel.g_view_model();
codeIn.Focus();
}
private void registerButtonClick(object sender , RoutedEventArgs e)
{
progressBar.Visibility = Visibility.Visible;
view_model.register_button_click(codeIn.Password);
codeIn.Password = "";
progressBar.Visibility = Visibility.Hidden;
}
/// <summary>
/// 没焦点,保存
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void source_lostfocus(object sender, RoutedEventArgs e)
{
view_model.new_key();
}
private void save_button(object sender, RoutedEventArgs e)
{
view_model.new_key();
}
private void open_button(object sender, RoutedEventArgs e)
{
view_model.open_file();
codeIn.Focus();
}
private void new_file_button(object sender, RoutedEventArgs e)
{
view_model.new_file();
}
private void save_as_button(object sender, RoutedEventArgs e)
{
view_model.save_file();
}
private void exit_button(object sender, RoutedEventArgs e)
{
view_model.new_key();
Application.Current.Shutdown();
}
private void select_button(object sender, RoutedEventArgs e)
{
source.Focus();
source.SelectAll();
}
private void copy_button(object sender, RoutedEventArgs e)
{
Clipboard.SetText(source.SelectedText);
}
private void paste_button(object sender, RoutedEventArgs e)
{
string temp;
temp = source.Text.Substring(source.SelectionStart);
source.Text = source.Text.Substring(0, source.SelectionStart) + Clipboard.GetText() + temp;
}
private void fastkey(object sender , KeyEventArgs e)
{
if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
switch (e.Key)
{
case Key.N:
new_file_button(sender , new RoutedEventArgs());
break;
case Key.S:
save_button(sender , new RoutedEventArgs());
break;
case Key.O:
open_button(sender , new RoutedEventArgs());
break;
default:
break;
}
}
if(e.Key==Key.Escape)
{
exit_button(sender , new RoutedEventArgs());
}
}
}
}
把界面的数据绑定
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace encryption_note
{
public class ViewModel : INotifyPropertyChanged
{
mul_key_encryption mul_key = new mul_key_encryption();
private ViewModel()
{
first = true;
if (File.Exists(mul_key.file_address))
{
first = false;
reminder_content = "请输入密码";
}
else
{
first = true;
reminder_content = "第一次使用,请输入密码";
}
register_visibility = Visibility.Visible;
main_visibility = Visibility.Hidden;
//progress_bar_visibility = Visibility.Hidden;
register = true;
}
public event PropertyChangedEventHandler PropertyChanged;
public Visibility register_visibility
{
set
{
if (value == Visibility.Visible)
{
_register_visibility = true;
}
else if (value == Visibility.Hidden)
{
_register_visibility = false;
}
OnPropertyChanged("register_visibility");
}
get
{
if (_register_visibility == true)
{
return Visibility.Visible;
}
else
{
return Visibility.Hidden;
}
}
}
public Visibility main_visibility
{
set
{
if (value == Visibility.Visible)
{
_main_visibility = true;
}
else if (value == Visibility.Hidden)
{
_main_visibility = false;
}
OnPropertyChanged("main_visibility");
OnPropertyChanged("main_enable");
}
get
{
if (_main_visibility == true)
{
return Visibility.Visible;
}
else
{
return Visibility.Hidden;
}
}
}
public bool main_enable
{
set
{
_main_visibility = value;
}
get
{
return _main_visibility;
}
}
public Visibility progress_bar_visibility
{
set
{
if (value == Visibility.Visible)
{
register = false;
}
else
{
register = true;
}
OnPropertyChanged("password_box_visibility");
}
get
{
if (register == true)
{
return Visibility.Hidden;
}
else
{
return Visibility.Visible;
}
}
}
public Visibility codein_visibility
{
set
{
if (value == Visibility.Visible)
{
register = true;
}
else
{
register = true;
}
OnPropertyChanged("codein_visibility");
}
get
{
if (register == true)
{
return Visibility.Visible;
}
else
{
return Visibility.Hidden;
}
}
}
public string text_string
{
set
{
_text_string.Clear();
_text_string.Append(value);
OnPropertyChanged("text_string");
}
get
{
return _text_string.ToString();
}
}
public string reminder_content
{
set
{
_reminder_content.Clear();
_reminder_content.Append(value);
OnPropertyChanged("reminder_content");
}
get
{
return _reminder_content.ToString();
}
}
/// <summary>
/// true 输入,不进度条,false不输入,进度条
/// </summary>
public bool register
{
set
{
_register = value;
OnPropertyChanged("password_box_visibility");
OnPropertyChanged("codein_visibility");
}
get
{
return _register;
}
}
/// <summary>
/// 第一次使用
/// </summary>
public bool first
{
set
{
_first = value;
}
get
{
return _first;
}
}
/// <summary>
/// 进入密码
/// </summary>
public string key
{
set
{
_key = value;
}
get
{
return _key;
}
}
public static ViewModel g_view_model()
{
if (_view_model == null)
{
_view_model = new ViewModel();
}
return _view_model;
}
public void new_file()
{
//mul_key.new_use(key);
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "data";
dlg.DefaultExt = ".data";
dlg.Filter = "data(.data)|*.data";
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
mul_key.file_address = dlg.FileName;
//mul_key.override_entryption(text_string);
first = true;
register_visibility = Visibility.Visible;
main_visibility = Visibility.Hidden;
register = true;
text_string = "";
}
}
public void open_file()
{
new_key();
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.FileName = "data";
dlg.DefaultExt = ".data";
dlg.Filter = "data(.data)|*.data";
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
mul_key.file_address = dlg.FileName;
first = false;
register_visibility = Visibility.Visible;
main_visibility = Visibility.Hidden;
register = true;
text_string = "";
}
}
/// <summary>
/// 另存为
/// </summary>
/// <param name="file_address">文件地址</param>
public void save_file()
{
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "data";
dlg.DefaultExt = ".data";
dlg.Filter = "data(.data)|*.data";
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
mul_key.file_address = dlg.FileName;
mul_key.override_entryption(text_string);
}
}
/// <summary>
/// 显示密码
/// </summary>
public void calculate_key_txt()
{
StringBuilder str = new StringBuilder();
mul_key.jmz_decryption();
foreach (var temp in mul_key.file_key)
{
str.Append(temp);
}
text_string = str.ToString();
Debug.Write(str.ToString());
}
/// <summary>
/// 保存密码
/// </summary>
public void new_key()
{
//mul_key.new_entryption(text_string);
Debug.Write("保存\n");
if (main_visibility == Visibility.Visible)
{
mul_key.override_entryption(text_string);
}
}
public void register_button_click(string key)
{
Debug.Write("register\n");
register = false;
Debug.Write("key" + key + "\n");
//progress_bar_visibility = Visibility.Visible;
if (key.Length > 10 && key.Length < 500)
{
if (first == true)
{
//new_file(key);
mul_key.new_use(key);
register_visibility = Visibility.Hidden;
main_visibility = Visibility.Visible;
}
else
{
if (mul_key.confirm_password(key))
{
calculate_key_txt();
register_visibility = Visibility.Hidden;
main_visibility = Visibility.Visible;
}
else
{
reminder_content = "密码错误,请重新输入";
}
//Debug.Write("key" + key + "\n");
}
}
else
{
reminder_content = "密码长度必须大于10字符";
}
register = true;
}
private static ViewModel _view_model = new ViewModel();
private StringBuilder _text_string = new StringBuilder();
private StringBuilder _reminder_content = new StringBuilder();
private bool _first;
private bool _register;
private bool _register_visibility;
private bool _main_visibility;
private string _key;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this , new PropertyChangedEventArgs(name));
}
}
}
}
使用字符串加密类,有公共
属性 key:密码
file_address:文件地址
方法 n_md5(string key) :将key进行n md5,我是用字符串的第一个字符unicode作为n
encryption(string str):加密字符串
decryption(string str):揭秘字符串
using System;
using System.Diagnostics;
using System.Text;
namespace encryption_note
{
public class string_decryption
{
///需要 using System.IO;
private string_decryption()
{
file_address = @".\data.data";
_temp_string_lenth = 1024;
}
public string_decryption(string file_加密的文件 , int key_length_more512)
{
key_length_more512 = 1024;
_temp_string_lenth = key_length_more512;
file_address = file_加密的文件;
}
public string_decryption(string key)
{
int 密钥_大于512;
密钥_大于512 = 1024;
_temp_string_lenth = 密钥_大于512;
this.key = key;
}
public static string_decryption g_获得类()
{
return _string_decryption;
}
public static string_decryption g_获得类(string file_加密的文件)
{
_string_decryption = new string_decryption(file_加密的文件 , 1024);
return _string_decryption;
}
~string_decryption()
{
}
public string key
{
get
{
if (_key.Length <= 0)
{
return "林德熙";
}
return _key;
}
set
{
_key = value;
}
}
/// <summary>
/// 加密文件绝对位置
/// </summary>
public string file_address
{
set
{
_file_address = value;
}
get
{
return _file_address;
}
}
private int ran
{
set
{
_random = new Random(value);
}
get
{
return _random.Next(2) == 0 ? _random.Next(19968 , 40864) : _random.Next(33 , 126);
}
}
public string encryption(string str)
{
char[] temp_str = new char[_temp_string_lenth];
int i , has , key_place;//has字符位置,key_place密码位置
//str = encryptDes(str);
str += "结束";
str.PadRight(_temp_string_lenth);
for (i = 0; i < _temp_string_lenth; i++)
{
temp_str[i] = Convert.ToChar(0);
}
key_place = 0;
for (i = 0; i < str.Length; i++)
{
has = Convert.ToInt32(key[key_place]);
has = has % _temp_string_lenth;
while (temp_str[has] != Convert.ToChar(0))//如果位置有别的字符就下一个,到没有字符位置
{
has++;
if (has >= _temp_string_lenth)
{
has = 0;
}
//has=has>=_temp_string_lenth?0:has++;
}
//temp_str[l] = (char)(str[i]);//+key[key_l]);
temp_str[has] = (char)((str[i]) + key[key_place]);
key_place++;
if (key_place == key.Length)
{
key_place = 0;
}
//key_place=key_place>=key.length?0:key_place++;
}
//把空填充
for (i = 0; i < _temp_string_lenth; i++)
{
if (temp_str[i] == Convert.ToChar(0))
{
temp_str[i] = Convert.ToChar(ran); //% 1000+1);
}
}
string s = new string(temp_str);
return s;
//return null;
}
public string decryption(string str)
{
StringBuilder temp = new StringBuilder();
char[] jie = str.ToCharArray();
int has , key_place;//has字符位置,key_place密码位置
bool accomplish;
accomplish = false;//初始
has = 0;
key_place = 0;
if (jie.Length < _temp_string_lenth - 1)
{
Debug.Write("错" + jie.Length.ToString());
return null;
}
while (accomplish == false)//我while(true)
{
has = Convert.ToInt32(key[key_place]);
has = has % _temp_string_lenth;//密码给字符所在位置
while (jie[has] == Convert.ToChar(0))
{
has++;
if (has >= _temp_string_lenth)
{
accomplish = true;
break;
}
}
if (accomplish)
{
break;
}
temp.Append((char)((jie[has]) - key[key_place]));
jie[has] = Convert.ToChar(0);//把原来位置0
key_place++;
if (key_place == key.Length)
{
key_place = 0;
}
}
string temp_str = temp.ToString();
int temp_l = temp_str.LastIndexOf("结束");
if (temp_l > 0)
{
return temp_str.Substring(0 , temp_l);
}
else
{
return null;
}
}
/// <summary>
/// 加密key[0].toint次md5
/// </summary>
/// <param name="key">密码</param>
/// <returns>加密后密码</returns>
public string n_md5(string key)
{
string temp;
int i;
int str_0_length;
if (string.IsNullOrEmpty(key))
{
temp = "";
return temp.PadRight(32 , '0');
}
str_0_length = Convert.ToInt32(key[0]);
temp = get_MD5(key);
for (i = 1; i < str_0_length; i++)
{
temp = get_MD5(temp);
}
return temp;
}
private int _temp_string_lenth;
private static string_decryption _string_decryption = new string_decryption();
private Random _random = new Random();
//加密文件的路径
private string _file_address;
private string _key;
/// <summary>
/// md5加密
/// </summary>
/// <param name="str">要加密字符串</param>
/// <returns>加密后密码</returns>
private string get_MD5(string str)
{
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] temp;
StringBuilder strb = new StringBuilder();
temp = md5.ComputeHash(Encoding.Unicode.GetBytes(str));
md5.Clear();
for (int i = 0; i < temp.Length; i++)
{
strb.Append(temp[i].ToString("X").PadLeft(2 , '0'));
}
return strb.ToString().ToLower();
}
}
}
这是使用只是一个字符串的加密,而在字符串很长就不能。
我把一个很长的字符串分割为多个字符串。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace encryption_note
{
public class mul_key_encryption
{
public mul_key_encryption()
{
new_class();
}
public mul_key_encryption(string key)
{
new_class(key);
}
~mul_key_encryption()
{
file_key.Clear();
decryption.Clear();
}
/// <summary>
/// 默认没有jia.key 密码
/// </summary>
public List<string> file_key
{
set
{
_key = value;
}
get
{
return _key;
}
}
public List<string> decryption
{
set
{
_decryption = value;
}
get
{
return _decryption;
}
}
public bool confirm_password(string key)
{
int len;
string temp;
len = 2048;
FileStream fs = new FileStream(file_address , FileMode.Open);
byte[] buffer = new byte[len];
fs.Read(buffer , 0 , len);//不密码
fs.Close();
temp = Encoding.Unicode.GetString(buffer);
jia.key = key;
return string.Equals(jia.n_md5(key) , jia.decryption(temp));
}
/// <summary>
/// 获得密码
/// </summary>
/// <returns>保存下密码</returns>
public string jmz_decryption()
{
string str;
str = "";
file_key.Clear();
d_scan();
foreach (string temp in decryption)
{
file_key.Add(jia.decryption(temp));
}
foreach (string temp in file_key)
{
str += temp + "\r\n\r\n";
}
return str;
}
/// <summary>
/// 要新增密码
/// </summary>
/// <param name="key">密码</param>
public void new_entryption(string key)
{
int sub = key.IndexOf("\r\n\r\n");
string temp;
while (sub != -1)
{
//如果开头\r\n\r\n那么直接去空
temp = key.Substring(0 , sub);
if (temp.Length > 0)
{
file_key.Add(temp);
}
key = key.Substring(sub + 4);
sub = key.IndexOf("\r\n\r\n");
}
file_key.Add(key);
//加密();
hold_decryption_key();
}
/// <summary>
/// 覆盖密码,把原有密码删掉
/// </summary>
/// <param name="key">密码</param>
public void override_entryption(string key)
{
file_key.Clear();//污染
while(key.Length>100)
{
file_key.Add(key.Substring(0, 100));
key = key.Substring(100);
}
file_key.Add(key);
hold_decryption_key();
}
public void new_use(string key)
{
jia.key = key;
file_key.Clear();
decryption.Clear();
hold_decryption_key();
//x_write();2015年5月12日19:55:57
}
/// <summary>
/// 删除密码
/// </summary>
/// <param name="key">要删除密码</param>
/// <returns>如果删除return true;如果没有return false</returns>
public bool delete_key(string key)
{
return file_key.Remove(key);
}
/// <summary>
///
/// </summary>
/// <param name="key">密码号</param>
/// <returns></returns>
public bool delete_key(int key)
{
if (key < file_key.Count)
{
file_key.RemoveAt(key);
return true;
}
return false;
}
private string_decryption jia
{
set
{
value = null;
}
get
{
return string_decryption.g_获得类();
}
}
private List<string> _key = new List<string>();
public string file_address
{
set
{
jia.file_address = value;
}
get
{
return jia.file_address;
}
}
private List<string> _decryption = new List<string>();
private bool new_class()
{
new_class("qq123456");
return true;
}
private bool new_class(string key)
{
file_address = @".\data.data";
jia.file_address = file_address;
jia.key = key;
return true;
}
/// <summary>
/// 写加密文件
/// </summary>
///<param name="str">函数要写入文件内容</param>
/// <returns>如果写成功返回true</returns>
private bool x_write()
{
FileStream xiaFile = new FileStream(file_address , FileMode.Create);
byte[] buf;
foreach (string temp in decryption)
{
buf = Encoding.Unicode.GetBytes(temp);
xiaFile.Write(buf , 0 , buf.Length);
}
decryption.Clear();
xiaFile.Flush();
xiaFile.Close();
return true;
}
/// <summary>
/// 读文件
/// </summary>
/// <param name="str">读文件内容保存到str</param>
/// <returns>读文件成功返回true</returns>
private bool d_scan()
{
string temp;
int len;//文件长
len = 2048;
decryption.Clear();//不污染
//文件流
try
{
FileStream fs = new FileStream(file_address , FileMode.Open);
//缓冲
byte[] buffer = new byte[len];
fs.Read(buffer , 0 , len);//不密码
while (fs.Read(buffer , 0 , len) != 0)
{
temp = Encoding.Unicode.GetString(buffer);
//没有解密
decryption.Add(temp);
}
//让文件可以被其他打开
fs.Close();
return true;
}
catch
{
//如果文件被占用,没有找到文件
return false;
}
}
/// <summary>
/// 添加、删除,可以保存密码
/// </summary>
private void hold_decryption_key()
{
//会污染
decryption.Clear();
//启动密码
decryption.Add(jia.encryption(jia.n_md5(jia.key)));
foreach (string temp in file_key)
{
if (temp != null && temp.Length > 0)
{
decryption.Add(jia.encryption(temp));
}
//如果密码空,不保存
}
x_write();
}
}
}
打开文件
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.FileName = "data";
dlg.DefaultExt = ".data";
dlg.Filter = "data(.data)|*.data";
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
//返回地址
}
保存文件
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "data";
dlg.DefaultExt = ".data";
dlg.Filter = "data(.data)|*.data";
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
}
INotifyPropertyChanged
OnPropertyChanged(“属性”);
void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this , new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
原本我的加密 http://blog.csdn.net/lindexi_gd/article/details/45419195
博客园博客只做备份,博客发布就不再更新,如果想看最新博客,请访问 https://blog.lindexi.com/
如图片看不见,请在浏览器开启不安全http内容兼容
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名[林德熙](https://www.cnblogs.com/lindexi)(包含链接:https://www.cnblogs.com/lindexi ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我[联系](mailto:lindexi_gd@163.com)。