伴随着 IP 位置库 的上线,笔者的“童年梦想”又成真了一个。为了分发这份来之不易的数据库,笔者找到了 ip2region 项目。该项目提供了一种体积小且查询速度极快的离线IP位置数据库文件格式,同时提供了多种语言支持的查询客户端。但 ip2region 项目的作者并未提供除 Java 以外的数据库文件生成代码,笔者打算为该项目移植 .NET 5.0 的数据库文件生成器,并在本文中记录下移植过程。

移植前准备

ip2region 的 Java 版数据库生成器 代码并不复杂,源代码文件只有 8 个。以笔者粗浅的 Java 经验来看,因为 C# 与 Java 大体相似,移植过程中无需对程序的结构和命名进行变更,也无需对处理逻辑进行调整。移植需要做的就是让程序可以编译通过,基本上就算成功。

开始移植

笔者新建了一个名为 IP2RegionDotNetDbMaker 的 .NET 5.0 控制台应用程序,删掉 Program.cs 文件并将所有的 Java 文件复制到项目中。

下一步操作很暴力,就是直接将源代码的后缀从 .java 改为 .cs 。为此,笔者在 LINQPad 中写了一段小代码,来完成这个操作:

var dir = @"D:\coderbusy.com\demo\IP2RegionDotNetDbMaker\IP2RegionDotNetDbMaker";var javaFiles = Directory.GetFiles(dir, "*.java");foreach (var javaFile in javaFiles){var _ = Path.GetDirectoryName(javaFile);var fileName = Path.GetFileNameWithoutExtension(javaFile);var csFile = Path.Combine(_, fileName + ".cs");File.Move(javaFile, csFile);}

在暴力改名之后的源代码文件里,不出意外的报了很多错误:

需要先把 package 和 import 这两种语句去掉,然后把缺失的命名空间给加上。

var dir = @"D:\coderbusy.com\demo\IP2RegionDotNetDbMaker\IP2RegionDotNetDbMaker";var files = Directory.GetFiles(dir, "*.cs");foreach (var file in files){var lines = File.ReadAllLines(file, Encoding.UTF8);var builder = new StringBuilder();builder.AppendLine($"using System;{Environment.NewLine}namespace IP2RegionDotNetDbMaker{Environment.NewLine}{{");foreach (var line in lines){if (line.StartsWith("package ")){continue;}if (line.StartsWith("import ")){continue;}builder.AppendLine(line);}builder.AppendLine("}");var content = builder.ToString();File.WriteAllText(file, content, Encoding.UTF8);}

异常声明在 C# 中不支持,可以通过正则将其替换掉:

在替换时,确定开启“使用正则表达式”,查找项为:throws ([\w ,]+)Exception 替换项保持为空。之后,替换掉所有的 @Override 和 final 关键字。

在 C# 中 out 是一个关键字不能被当作类型使用,Java 编程中常用的 System.out.println 方法需要被替换成 Console.WriteLine ,直接全局替换搞定。

重构 DbMakerConfigException 类型:

using System;namespace IP2RegionDotNetDbMaker
{/*** configuration exception* * @author chenxin<chenxin619315@gmail.com>*/public class DbMakerConfigException : Exception{public DbMakerConfigException(string info) : base(info){}}}

在 .NET 5.0 中 Mock 实现 Java 所需的 API

新建 Mock.cs 文件,用于存放 Java API 到 C# API 的Mock 代码。使用扩展方法对 String 类型进行扩展,并实现 Java API 所用的方法:

    public static class Extensions{public static Int32 length(this string str){if (String.IsNullOrWhiteSpace(str)){return 0;}return str.Length;}public static string trim(this string str){return str.Trim();}public static char charAt(this string str, Int32 i){return str[i];}public static int indexOf(this string str, string value){return str.IndexOf(value);}public static int indexOf(this string str, char value, Int32 start){return str.IndexOf(value, start);}public static string substring(this string str, Int32 startIndex){return str.Substring(startIndex);}public static string substring(this string str, Int32 startIndex, Int32 endIndex){return str.Substring(startIndex, endIndex - startIndex);}public static bool equals(this string str1, string str2){return String.Equals(str1, str2, StringComparison.InvariantCultureIgnoreCase);}public static string[] split(this string str, string separator){return str.Split(separator);}public static byte[] getBytes(this string str){return Encoding.UTF8.GetBytes(str);}public static byte[] getBytes(this string str, string encoding){return Encoding.GetEncoding(encoding).GetBytes(str);}public static bool endsWith(this string str, string value){return str.EndsWith(value);}}

Mock 实现 StringBuilder 类型:

    public class StringBuilder{private readonly System.Text.StringBuilder _builder = new System.Text.StringBuilder();internal StringBuilder append(object value){_builder.Append(value);return this;}internal string toString(){return _builder.ToString();}}

Mock 实现 File 类型:

    public class File{public File(string ipSrcFile){_fileInfo = new FileInfo(ipSrcFile);}private FileInfo _fileInfo;public FileInfo FileInfo => _fileInfo;internal bool exists(){return _fileInfo.Exists;}}

Mock 实现 LinkedList 类型:

    public class LinkedList<T> : List<T>{internal T getFirst(){return this[0];}internal void add(T item){this.Add(item);}internal T getLast(){return this[this.Count - 1];}internal IEnumerable<T> iterator(){return this;}}

Mock 实现 HashMap 类型:

    public class HashMap<K, V> : Dictionary<K, V>{internal void put(K k, V v){this[k] = v;}internal bool containsKey(K key){return this.ContainsKey(key);}internal V get(K k){if (containsKey(k)){return this[k];}return default;}}

Mock 实现 FileReader 类型:

    public class FileReader{private File globalRegionFile;private Queue<String> _lines = new Queue<string>();public FileReader(File file){this.globalRegionFile = file;using (var fs = file.FileInfo.OpenRead()){using (var sr = new StreamReader(fs)){while (!sr.EndOfStream){var line = sr.ReadLine();_lines.Enqueue(line);}}}}internal string readLine(){if (_lines.TryDequeue(out var line)){return line;}return null;}internal void close(){}}

Mock 实现 BufferedReader 类型:

    public class BufferedReader{private FileReader fileReader;public BufferedReader(FileReader fileReader){this.fileReader = fileReader;}internal string readLine(){return fileReader.readLine();}internal void close(){fileReader.close();}}

Mock 实现 RandomAccessFile 类型:

    public class RandomAccessFile{private string dbFile;private Stream stream;internal void seek(long v){stream.Seek(v, SeekOrigin.Begin);}internal void write(byte[] vs){stream.Write(vs);}internal void readFully(byte[] dbBinStr, int v, int length){stream.Read(dbBinStr, v, length);}private string v;public RandomAccessFile(string dbFile, string v){this.dbFile = dbFile;this.v = v;this.stream = new FileStream(dbFile, FileMode.OpenOrCreate, FileAccess.ReadWrite);}public long length(){return this.stream.Length;}internal void close(){if (stream == null){return;}this.stream.Flush();this.stream.Close();this.stream = null;}internal long getFilePointer(){return stream.Position;}internal void write(int v){var bytes = BitConverter.GetBytes(v);stream.Write(bytes);}}

语法与属性修正

经过以上的 Mock 操作,报错部分便仅仅涉及语法和部分属性。

C# 中并不存在“扩展属性”类似的东西,所以 Java 中以“小驼峰”命名的 length 字段调用,据需要改为“大驼峰”方式的 Length 。位运算符 >>> 也需要改为 >> ,同时,还有几个语法错误需要修正。比如:C# 中并不支持 Java 中的 for(Type e:collection) 语法,需要用 foreach 来替代。之后,项目就可以编译通过了。

结果验证

将 data 目录拷贝至 bin 目录,使用以下命令便可启动生成:

dbMaker -src ./data/ip.merge.txt -region ./data/global_region.csv

伴随着大量的控制台输出,笔者似乎找到了黑客帝国的感觉。经过一小会儿的等待,生成已经成功执行。

通过二进制对比,该结果文件仅在行尾的日期存储部分与源文件不同:

通过阅读代码,文件末尾部分的数据是生成的时间戳和一小段声明信息。文件尾的不一致并不会对使用造成影响。这表示,这次移植是成功的。

开源地址

目前,该代码已经上传至 Gitee ,地址是:

https://gitee.com/coderbusy/demo/tree/master/IP2RegionDotNetDbMaker

我是如何把 Java 项目移植到 .NET 5.0 的相关推荐

  1. 实战派 | Java项目中玩转Redis6.0客户端缓存

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 哈喽大家好啊,我是Hydra. 在前面的文章中,我们介绍了Redis6.0中的新特性客户端缓存client-side caching,通过tel ...

  2. Java工程进行性能测试时通常要考虑哪些要素,如何使接口响应时间在毫秒级范围,Java项目如何进行性能测试?0.2s的反应时间内返回响应,用户感知情况较好。附IO密集型和计算密集型性能测试摸底代码

    研究表明,人的反应时间通常在0.2s左右,运动员0.14s已经是顶级反应了,所以响应时间在0.2秒以内通常是无感的.那么在性能测试时,需要关注哪些指标呢? CPU:有的应用需要大量计算,他们会长时间. ...

  3. Java 项目实战 坦克大战 (0)--前言

    做了有一个星期了,java语言太强大了,也算是学得最认真的一门语言了,本次课设花的心思也就比较多了.关键总是追求完美总是想原创,最终做出来效果不错,但感觉代码逻辑很乱,今天开始就好好整理一番,以教程形 ...

  4. 最牛逼的 Java 项目实战,没有之一!

    想要成长为高级开发,掌握更多层面的技术,兼顾深度和广度是毋庸置疑的.你肯定认为,我要认真努力的学习技术,丰富自己的技术栈,然后就可以成为一个优秀的高级开发了.但当你真正去学习之后就会发现,技术栈异常庞 ...

  5. 程序员把开发搬到云服务器,如何将IDEA开发的java web项目移植到腾讯云服务器

    javaWeb项目移植到服务器 1.服务器添加国内新源 2.服务器安装java jdk 3.下载tomcat 8.5.31 (与自己电脑的tomcat版本对应) 4.安装mysql数据库(版本最好和之 ...

  6. 如何将IDEA开发的java web项目移植到腾讯云服务器

    javaWeb项目移植到服务器 1.服务器添加国内新源 2.服务器安装java jdk 3.下载tomcat 8.5.31 (与自己电脑的tomcat版本对应) 4.安装mysql数据库(版本最好和之 ...

  7. vs项目移植到linux运行,VS2008项目移植到Linux

    不少人都遇到过这种情况:在Windows下用Visual Studio工具开发的程序需要移植到Linux系统中,做成Linux版本的,但程序比较大,在Linux上又离不开Make,手动编写Makefi ...

  8. android java和c混合编程_C/C++在Java项目、Android和Objective-C三大平台下实现混合编程...

    Android和iOS开发都支持C++开发,可以一套代码多平台使用.同时C++难以反编译的特性也可以为Android开发带来代码的保密,另一native特性也可以提高代码的运行效率. 一.为什么使用C ...

  9. 将Windows MyEclipse的web项目移植到Debian下

    用windows先的MyEclipse很方便,但是要把MyEclipse的web项目移植到Debian下,稍微有一点麻烦.当然,如果是ubuntu的话,直接装MyEclipse就可以了.这里只将针对于 ...

最新文章

  1. vue ts 设置tslint提示_Typescript 在 Vue 中的实践(包含2.x、3.x)
  2. VS 2017开发ASP.NET Core Web应用过程中发现的一个重大Bug
  3. Angular-在服务和组件中使用管道
  4. html媒体查询怎么把颜色换成图片,为网页中图片src添加媒体查询功能。
  5. 前序-中序-后序-非递归-实现
  6. Qt工作笔记-使用Qt中QProcess与iostream中system调用外部进程
  7. ios 隔空投安装ipa_iOS 安装自己服务器上的IPA包
  8. 利用Civil 3D API更改曲面的样式
  9. 腾讯云cdn怎样接入域名
  10. Bat 下载文件并处理
  11. VSCode PIO创建工程失败分析和解决办法
  12. 服务器安全值得深思的几点问题?
  13. 【C#】EAN-13条形码生成与识别
  14. 鸿蒙系统pc版 硬件要求,原神全平台配置要求 原神配置需求一览
  15. csol控制台+去黑雾
  16. 网络分层架构 ARP baidu.com 访问过程 知识点总结
  17. Python基础:字符集和编码
  18. ISE verilog 综合错误提示:ERROR:Xst:880 - Johnson_source.v line 45: Cannot mix blocking and non blocking
  19. Download files
  20. 杰理AC692X---常用模式介绍

热门文章

  1. linux自学(四)之开始centos学习,网络配置
  2. js将时间戳格式化为HH:ii:ss的格式
  3. background意识(两)
  4. 数组的几种排序算法的实现(1)
  5. Teams bot的调用限制
  6. office数据集dslr_如何将照片从DSLR无线传输到智能手机
  7. viper4android 生效,另一种让V4a音效在Poweramp上生效的方法
  8. 腾讯云DevOps技术揭秘:新时代运维重器Tencent Hub最佳实践
  9. 自从装了windows神器,再也不用羡慕mac了
  10. 【Unity3D基础】让物体动起来②--UGUI鼠标点击逐帧移动