Mac 下使用 FinalShell 取代 XShell

Xshell 个人感觉是 Windows 下功能最好用的 ssh 客户端软件了,但是不能跨平台,所以在 Mac 下就要找一个替代品。

简单检索了一些网上的资料,最终被 FinalShell 吸引,感觉比 Xshell 还要好用一些(对于我这种小白来说)。

下载地址:http://www.hostbuf.com/

免费版完全够用了,如果想赞助一下使用高级版这里是传送门:35 软妹币赞助传送门

需要注意的是,赞助需要注册登录,同样软件高级版升级也是通过登录用户实现的。

预览:

E6BADE11-F0D2-46D7-95EB-A3D1D94631E0

使用 Sublime Text 替代 Windows 平台的 Notepad++

在 Windows 平台进行 LIS 接口开发时,经常需要使用 npp(Notepad++) 来进行通讯文本的查阅与解析。

好处主要一下几点:

  • 可以查看 ASCII 字符;
  • 可以使用正则对数据进行调整;
  • 可以查看到当前编辑位置以及选中文本长度;

因为 npp 是 Windows 系统的软件,无法跨平台使用,所以现在使用 macOS 就需要找到一个替代品。

开始是尝试过 ue 等一些网友推荐的软件,发现不行,绝望的以为找不到替代品。但是在 CoolQ 开发者聊天群聊天的时候,无意中听到 Coxxs 说 Sublime 其实也不错,于是下载下来试了一下,可以说是真香了。

以下整理以下安装时遇到的一些问题。

下载

https://pan.baidu.com/s/1_4twEeQGKXXddnsIrF1SrA 提取码:k744

关闭更新

菜单栏 -> Preferences -> Settings -> User Settings 配置添加以下内容:

1
"update_check": false

注意保持json内容的结果完整,可能需要补逗号。

使用GBK

中文乱码的问题需要安装包,包括 ConvertToUTF8 以及 Codecs33

安装的时候如果失败,需要配置一下下载连接方式,打开 菜单栏 -> Preferences -> Package Settings -> Package Control -> User Settings 将以下内容追加到配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"downloader_precedence":
{
"linux":
[
"curl",
"urllib",
"wget"
],
"osx":
[
"curl",
"wget"
],
"windows":
[
"wininet"
]
}

注意保持 json 内容的结果完整,可能需要补逗号。

以上配置完成以后,都需要重启 Sublime Text 才能生效,现在还有宏以及同时编辑多行的问题还需要研究一下,总的来说替代 npp 应该是没问题了,最关键是跨平台很方便。

罗技鼠标使用蓝牙连接的延迟问题

最近购置了一个迷你主机,体验了一下“黑苹果”,为了追求简约,看着桌面上的线材也比较窝心,所以重新购置了一套无线键鼠。

Screenshot_20191024081651718_com.jingdong.a.png

最开始打算使用蓝牙连接,避免占用 USB 接口,但是实际使用发现,可能由于无线网卡的问题,蓝牙模块非常卡顿,无论是接蓝牙耳机听歌,还是连接使用键鼠。键盘还可以接受,但是蓝牙鼠标卡顿非常明显。

解决方案

换无线模块大概是不可能了,mini 主机可以用的无线模块现在价格炒得很高。

但是两个都通过 USB 连接,占用两个接口又不好接受,这个时候我想起来之前鼠标无线接收器和鼠标丢失连接,可以使用过优联重新配对。那么优联可不可以将一个无线接收器配对两个设备呢?

查找了一下资料,得到的是肯定的答案,下载链接:Logitech Unifying™ 优联软件

系统信息:

屏幕快照 20191024 上午8.27.36.png

我的 MacOS 版本是 10.14.6,网上没有这个版本,但是我下载的 10.15 版本的软件可以完美安装使用。

屏幕快照 20191024 上午8.29.46.png

解决 Access 数据文件打开报错:无法打开应用程序较早版本创建的数据库

处理 LIS 接口,经常会遇到需要和 Access 数据库对接读写数据,可能需要打开对方数据库查看数据库表结构以及数据。

正常我们安装 Office 以后会附带有 Access,可以打开数据库,浏览数据以及执行 SQL。

但是我并不推荐使用 Office 里的 Access 软件,原因如下:

  1. 安装麻烦,新版本需要购买(我订阅了 Office 365 这倒没什么);
  2. 软件本身操作不友好,和其他 Office 软件类似的工具栏,在数据库操作中需要经常使用的一些功能下略显尴尬与低效,例如切换窗口或者创建查询;
  3. 虽然支持 mac,但是不能在 Linux 下使用;
  4. 对旧版本,例如 97 之前创建的数据库不支持会提示:无法打开应用程序较早版本创建的数据库;

    20190915111827.png

特别是针对第四点,网上去搜索 Access 数据库管理软件,能找到的资料其实很少。

开始,我会使用 Office 的 Access 软件,搭配一个简陋的从网上找到的工具来处理 Access 数据库文件,但是这就相对比较麻烦,特别是教同事怎么处理 Access 数据库文件的时候,他们经常会问“怎么创建一个查询窗”以及“这个数据库文件怎么打不开,是不是损坏了”?

这个问题曾经困扰我很长一段时间,不过因为有解决方案,就没有继续追究,直到我遇到了“DBeaver”。

开始接触这个软件,只是因为需要找一个可以连接各种数据库的工具,开始是用 Navicat,但是因为其需要收费,并且只支持五种数据库的连接:Oracle、MSSQL、SQLite、MySQL、PostgreSQL。

后来无意中打开了这个软件的官网:https://dbeaver.io/,惊讶于居然可以支持那么多种数据库,便下载下来试了一下,真的是只能说:真香。

  1. 安装软件不到 50MB(不过连接不同的数据库需要安装不同的“驱动”),并且国内下载速度也很快(我试了一下科学上网反而速度慢了很多);
  2. 社区版免费,企业完整版可以按月付费,每个月 19USD,虽然略贵,但是社区版已经支持“MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto”等等数据库类型,所以免费版已经很香了(注意看下图的滚动条);

    20190915121837.png

  3. 在各种数据库下均有一致的体验,和其他数据库管理软件体验也很类似,所以上手很简单;
  4. 支持查看数据库对象表、视图、存储过程等等;
  5. SQL 编辑有智能提示,除关键字外表和视图名称也有;
  6. SQL 编辑右键可以看到有 SQL 美化;
  7. 查询数据会自动分页,并且查询的数据可以实时的修改并提交;
  8. 如果是二进制数据例如文本和图片也可以很方便的查看;
  9. 跨平台,出 Windows 以外还支持 mac 以及 linux;
  10. 支持导入/导出表数据以及查询数据、支持查看数据表 DDL;

20190915121018.png

因为优点太多就不一一列举了,可以自己下载体验。

另外回到文章标题,Access97 以前的版本也是支持打开的,可以进行查询,但是因为 jdbc 的问题,旧版本的 Access 仅支持查询,不支持增删改,不过这也基本上够用了,后面的问题就用代码来解决吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
using System.Data.OleDb;

namespace JohnSun.Tests
{
class Program
{
static void Main(string[] args)
{
// 需要注意以下代码需要x86平台运行
using (OleDbConnection conn = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\hd2y\Downloads\Data .mdb;"))
{
conn.Open();
using (OleDbCommand comm = conn.CreateCommand())
{
comm.CommandText = "select count(1) from items";
int count = (int)comm.ExecuteScalar();
Console.WriteLine($"Items表共有{count}条数据!");
}

using (OleDbCommand comm = conn.CreateCommand())
{
comm.CommandText = "update items set MRU=@mru";
comm.Parameters.Add(new OleDbParameter("@mru", "test"));
int count = comm.ExecuteNonQuery();
Console.WriteLine($"共更新Items表{count}条记录!");
}
}
}
}
}

注意:偶然间发现有些 Access 数据库,DBeaver 打开也会报错,建议使用 Visual Studio 的数据库连接工具,可以通过 工具 - 连接到数据库 打开。

附录:

解决 Oracle 安装闪退问题

Oracle 19c 安装注意事项:

  • 解压路径不能带有空格与特殊字符,否则安装程序闪退;
  • 解压的内容在安装后不能删除,因为一些基础工具例如 dmp、sqlplus、tns 配置文件等安装后会在该解压目录下。

最近在研究 WTM 快速开发框架,但是目前还不支持 Oracle 数据库,所以想看下怎么兼容 Oracle 数据库。

因为不喜欢在自己的电脑上装数据库服务端,所以开始用的是公司的 Oracle 数据库进行测试,但是发现 Oracle 提供的 Oracle.ManagedDataAccess.Core总是报错,大概内容是语句不正确的结束。

注入日志发现生成的 SQL 中带有 fetch first 的内容,之前还在纠结Oracle 数据库不支持类似 MySQL 中 limit 的写法,毕竟 SQL Server 都开始支持了,现在反而被这个难住了。

查了下资料,发现 W3Cschool 上关于该关键字的语句标注了 以下查询语句仅能在Oracle 12c以上版本执行,所以公司的 11g 自然不能用了。

并且查了下资料发现网上 Oracle 发表的关于 ODP.NET Core 的文档写道:

1
Oracle released a beta version of ODP.NET Core in February 2018. Oracle plans to release a production version of ODP.NET Core during the third quarter of 2018 at the same time as Oracle Data Access Components (ODAC) 18c.

好吧,既然这样直接在自己电脑上安装一个最新版 19c 好了,卸载掉我的 12c 客户端以后开始第一次安装。

一切都很顺利,但是,安装好以后我发现在 C 盘找不到 tnsnames.ora 文件,开始没在意,一边删除着 E 盘的安装文件,一边打开 Oracle Net Configuration Assitant,此时“文件不存在”和E盘安装文件的“删除错误,文件被占用”提示同时弹出,我悲伤的发现不知道为什么 Oracle 被安装到了我的移动硬盘E盘上,而且这些文件已经被我删除了大半。

无奈只能从网上找手动卸载 Oracle 的方式卸载后准备重装,主要就是停止服务、删除注册表、清除安装文件、删除配置文件和环境变量信息。

一切就绪后我重新把文件解压到C盘,然后准备开始安装,安装前特意把移动硬盘拔了下来,避免再出现“事故”。但是点击 setup.exe 却闪退了,无法进入安装操作。

开始我以为是卸载不完全的问题,正常也都会这么想吧,毕竟潜意识里一直认为 Oracle 不好卸载,花了半个小时,重新理了一遍注册表以及清除了 Windows 的 Temp 文件夹,重启电脑后安装,仍然闪退。

正在一筹莫展的时候,看着我解压放置的文件夹名,突然来了灵感,我解压的文件目录名称为 Oracle Unzip,我试着把文件夹名字中的空格删除,打开安装文件,居然运行了。

此时内心只有 woc 了,不知道能说什么,重新安装的时间顺便吐槽记录一下,然后完事儿继续干活了。😓

20190831194414

C# 中的元组

什么是元组

元组是 C# 提供的简单定义的类型,早期版本为 System.Tuple,使用该类型可以简化类型的定义。

1
2
3
// 姓名 性别 出生日期
Tuple<string, bool, DateTime> person = new Tuple<string, bool, DateTime>("John", true, new DateTime(1990, 01, 01));
Console.WriteLine($"{person.Item1} is a good {(person.Item2 ? "boy" : "girl")} and {(person.Item2 ? "his" : "her")} birthday is on {person.Item3.ToString("MM.dd")}");

如上,可以组装多个类型成为一个新的类型,可以应用在多返回值或一些数组集合场景下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 多返回值:是否执行成功 错误信息
public Tuple<bool, string> Execute(string sql)
{
bool result = false;
string message = null;
try
{
result = SqlHelper.Excute(sql);
}
catch (Exception exc)
{
message = $"错误信息:{exc.Message}\n堆栈信息:{exc.StackTrace}";
}
return new Tuple<bool, string>(result, message);
}

// 特殊类型集合
public void Test()
{
List<Tuple<string, bool, DateTime>> people = new List<Tuple<string, bool, DateTime>>();
people.Add(new Tuple<string, bool, DateTime>("John", true, new DateTime(1990, 01, 01)));
people.Add(new Tuple<string, bool, DateTime>("Jane", false, new DateTime(1992, 02, 02)));
foreach (var item in people)
{
Console.WriteLine($"{item.Item1} is a good {(item.Item2 ? "boy" : "girl")} and {(item.Item2 ? "his" : "her")} birthday is on {item.Item3.ToString("MM.dd")}");
}
}

但是该类型使用时还是有一些缺陷,特别是通过 Item{n} 标记元素,没有具体的含义在使用中就比较容易出错。

另外,其泛型参数只提供了 7 个,如果超过 7 个,我们就要使用第 8 个泛型参数使用 System.Tuple 类型进行嵌套,例如:

1
2
// 定义多个参数
Tuple<int, int, int, int, int, int, int, Tuple<int>> nums = new Tuple<int, int, int, int, int, int, int, Tuple<int>>(1, 2, 3, 4, 5, 6, 7, new Tuple<int>(8));

所以微软在后来提供了 System.ValueTuple 类型,取代了 System.Tuple,我们可以通过 NuGet 引用 System.ValueTuple 使用。

20190813175313

如上图所示,其标记的支持 .NET Framework 的最低版本为 .NET Framework 4.5,但实际上我们给 .NET Framework 4.0 的项目引用依然是可以正常使用的。另外如果想在 .NET Framework 3.5 的项目中使用,可以引用上图中的 ValueTupleBridge

ValueTuple 的语法

首先我们使用 NuGet 添加对 System.ValueTuple 的引用,我们可以将以上 Tuple 部分定义的内容进行简单的重写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 多返回值:是否执行成功 错误信息
public (bool result, string message) Execute(string sql)
{
bool result = false;
string message = null;
try
{
result = SqlHelper.Excute(sql);
}
catch (Exception exc)
{
message = $"错误信息:{exc.Message}\n堆栈信息:{exc.StackTrace}";
}
return (result, message);
}

// 特殊类型集合
public void Test()
{
List<(string name, bool sex, DateTime birthday)> people = new List<(string name, bool sex, DateTime birthday)>();
people.Add(("John", true, new DateTime(1990, 01, 01)));
people.Add(("Jane", false, new DateTime(1992, 02, 02)));
foreach (var item in people)
{
Console.WriteLine($"{item.name} is a good {(item.sex ? "boy" : "girl")} and {(item.sex ? "his" : "her")} birthday is on {item.birthday.ToString("MM.dd")}");
}
}
1
2
// 定义多个参数
(int num1, int num2, int num3, int num4, int num5, int num6, int num7, int num8) nums = (1, 2, 3, 4, 5, 6, 7, 8);

此外我们还可以用多种方式来声明 System.ValueTuple

  1. 将元组赋给单独声明的变量
    1
    2
    (string name, bool sex, DateTime birthday) = ("John", true, new DateTime(1992, 02, 02));
    Console.WriteLine($"{name} is a good {(sex ? "boy" : "girl")} and {(sex ? "his" : "her")} birthday is on {birthday.ToString("MM.dd")}");
  2. 将元组赋给预声明的变量
    1
    2
    3
    4
    5
    string name;
    bool sex;
    DateTime birthday;
    (name, sex, birthday) = ("John", true, new DateTime(1992, 02, 02));
    Console.WriteLine($"{name} is a good {(sex ? "boy" : "girl")} and {(sex ? "his" : "her")} birthday is on {birthday.ToString("MM.dd")}");
  3. 将元组赋给单独声明和隐式类型的变量
    1
    2
    (var name, var sex, var birthday) = ("John", true, new DateTime(1992, 02, 02));
    Console.WriteLine($"{name} is a good {(sex ? "boy" : "girl")} and {(sex ? "his" : "her")} birthday is on {birthday.ToString("MM.dd")}");
  4. 将元组赋给单独声明和隐式类型的变量,但只用一个var
    1
    2
    var (name, sex, birthday) = ("John", true, new DateTime(1992, 02, 02));
    Console.WriteLine($"{name} is a good {(sex ? "boy" : "girl")} and {(sex ? "his" : "her")} birthday is on {birthday.ToString("MM.dd")}");
  5. 声明具名元组,将元组值赋给它,按名称访问元组项
    1
    2
    (string name, bool sex, DateTime birthday) person = ("John", true, new DateTime(1992, 02, 02));
    Console.WriteLine($"{person.name} is a good {(person.sex ? "boy" : "girl")} and {(person.sex ? "his" : "her")} birthday is on {person.birthday.ToString("MM.dd")}");
  6. 声明包含具名元组项的元组,将其赋给隐式类型的变量,按名称访问元组项
    1
    2
    var person = (name: "John", sex: true, birthday: new DateTime(1992, 02, 02));
    Console.WriteLine($"{person.name} is a good {(person.sex ? "boy" : "girl")} and {(person.sex ? "his" : "her")} birthday is on {person.birthday.ToString("MM.dd")}");
  7. 将元组项未具名的元组赋给隐式类型的变量,通过项编号属性访问单独的元素
    1
    2
    var person = ("John", true, new DateTime(1992, 02, 02));
    Console.WriteLine($"{person.Item1} is a good {(person.Item2 ? "boy" : "girl")} and {(person.Item2 ? "his" : "her")} birthday is on {person.Item3.ToString("MM.dd")}");
  8. 将元组项具名的元组赋给隐式类型的变量,但还是通过项编号
    1
    2
    var person = (name: "John", sex: true, birthday: new DateTime(1992, 02, 02));
    Console.WriteLine($"{person.Item1} is a good {(person.Item2 ? "boy" : "girl")} and {(person.Item2 ? "his" : "her")} birthday is on {person.Item3.ToString("MM.dd")}");
  9. 赋值时使用下划线丢弃元组的一部分(弃元)
    1
    (string name, bool sex, DateTime birthday, _) = ("John", true, new DateTime(1992, 02, 02), "China");
  10. 通过变量和属性名推断元组项名称(C# 7.1 新增)
    1
    2
    3
    4
    5
    string name = "John";
    bool sex = true;
    DateTime birthday = new DateTime(1990, 01, 01);
    var person = (name, sex, birthday);
    Console.WriteLine($"{person.name} is a good {(person.sex ? "boy" : "girl")} and {(person.sex ? "his" : "her")} birthday is on {person.birthday.ToString("MM.dd")}");

    注意:

    1. 元组是在对象中封装数据的轻量级方案,元组数据项的类型没有限制,但是他们的类型是由编译器决定,不能在运行时改变。
    2. 如果需要对封装的数据关联行为(事件、方法),应该创建一个类而不是使用元组。
    3. 元组 System.ValueTuple 类似结构体,如果将一个元组赋值给另外一个元组,其是值传递而非引用传递。

解决 Telegram 无法联网的问题

前言

最近重新安装了 Telegram,但是发现无法登录,代理工具已经正常开启,Google 也可以访问,但是 Telegram 的网络检测总是不通过,简单研究了一下终于发现了怎么解决网络连接的问题。

解决方案

首先我们需要打开代理设置的界面,可以点击左下角旋转的网络连接的图标:

20190812115937

选择添加代理(Add Proxy):

20190812120000

弹出的界面,设置我们代理工具使用的协议和端口,设置后保存:

20190812120036

保存以后如上图左下角,可以看到连接已经正常。

附:汉化可以搜搜 @zh_CN,然后选择搜索结果的第一个安装语言包,如下图:
20190812192040

注意:MacOS 设置后可能需要重启软件才能生效,这是一个历史遗留问题,在 GitHub 上有讨论。

Win10 中 TreeView 控件显示问题

前言

最近重装了系统,Win10 中 TreeView 控件自然又是不能显示的。

20190812153344

之前在 CSDN 中整理过解决方案,但是早已经放弃了在 CSDN 写文章,所以在个人博客再重新整理一下这个问题的处理方案。

解决方案

下载与安装

百度网盘:http://pan.baidu.com/s/1cANFPG 密码:zblv

解压文件到:C:\inetpub\wwwroot

20190812154140

注意:压缩文件时没有注意,有两个层级,文件夹名称都是 webctrl_client,要进第二层再解压缩。

效果

解压到对应目录后直接刷新,树形控件即可正常显示,但是需要注意的是,该控件仅提供显示,并不是 VS 控件。

20190812154217

Win10 安装 Oracle

下载安装

首先下载地址:https://www.oracle.com/technetwork/cn/database/enterprise-edition/downloads/index.html

我试了一下是可以用迅雷下载,速度还可以。

安装没有什么需要特别注意的,基本上一直下一步安装就可以了。

安装完服务可能会弹出一些数据库初始化的信息框,根据提示操作运行即可。

TNS 配置

首先我们可以测试一下是否可以正常使用,安装过程中有一步是设置密码,可以用这个密码登录 SQL Plus

oracle1

虽然可以正常访问,但是还是建议重新配置一下服务器上的监听程序。

打开随 Oracle 一起安装的 Net Configuration Assitant

先配置监听程序:监听程序配置 -> 重新配置 -> Listener -> 使用标准端口号 1521

配置以后继续配置 Net 服务名:本地 Net 服务名配置 -> 服务名随意取一个 -> 主机名填客户端 IP -> 使用标准端口号 1521 -> 完成

tns重新配置以后我们要找一下 tnsnames 的文件,在安装目录下,可以参考我安装的路径:C:\app\czh\product\12.2.0\dbhome_1\network\admin

Host 配置为 localhost 的修改为服务器的 IP 地址。

远程连接

首先应该安装 Oracle 的客户端,之前下载的页面对应版本查看全部有具体的下载:https://www.oracle.com/technetwork/cn/database/enterprise-edition/downloads/oracle12c-windows-3633015-zhs.html

注意:网上搜索客户端会出现“即时客户端”或精简版客户端,如果需要进行开发,不建议安装。

安装以后找到 tnsnames 文件,将服务端配置的信息直接拷贝到客户端文件中,例如:C:\app\client\Administrator\product\12.1.0\client_1\network\admin\tnsnames.ora

可以使用 tnsping 功能检查是否可以正常连接:

oracle2

当然如果有问题,有可能是防火墙的问题,入站规则设置一下一般就可以。

Oracle 数据库的管理“墙裂”建议使用 PL/SQL Developer,而且建议安装 12.0 以后的版本。

如果只是简单查一下数据,当然 Navicat 与 DBeaver 也是不错的选择:

oracle3

注意:安装完成以后有一次测试连接出现了 ora-12514,检查 tnsping 命令正常,并且客户端 SERVICE_NAME 和 HOST 配置也没有问题纠结了好久,最后使用重启大法,重启了服务器自己好了,很是郁闷。