跨语言调用和编程 实现数据压缩和解压缩

2021/4/22 20:55:42

本文主要是介绍跨语言调用和编程 实现数据压缩和解压缩,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

中间件实验三:跨语言调用和编程

一、前言

实验内容

一个功能A,用的是L1语言进行编程实现的;请把该功能,在L2语言的环境下进行调用/合并,并能正确的返回结果。

请先自己编写或找到实现A功能的代码,或仅有可执行文件,并进行跨语言开发。

多语言开发一般基于第三方的库或解决方案。

A:数据压缩和解压缩功能, L1: C++ , L2:Python 和 Java

使用语言

Python、Java

开发环境

Python 3.8

IDEA 2020.1.4

Visual Studio 2019

其中,Python调用C++通过SWIG实现,而Java调用C++通过JNI实现。

二、准备工作

1、安装SWIG(Simplified Wrapper and Interface Generator)

SWIG:SWIG的简介、安装、使用方法之详细攻略

1、 下载Swig for Windows:http://www.swig.org/download.html

2、 解压 .zip 文件到目录

3、 添加swig所在目录到环境变量path

4、 简单测试安装是否成功:

打开Dos,在命令行执行: swig --help, 显示 Target Language Options即表明安装成功。

2、使用C++实现数据压缩和解压缩功能

基于哈夫曼编码实现文件的压缩与解压缩

源文件保存为HuffmanEncoderCompress.hHuffmanEncoderCompress.cpp

在这里插入图片描述

三、实验步骤

1、Python调用C++

1.1、SWIG实现python对C++封装

编写swig定义文件

在这里插入图片描述

.i文件主要包含了三个部分:

  1. %module后面的名字是被封装的模块名称,Python通过这个名称加载程序。
  2. %{...%}之间所添加的内容,一般包含此文件需要的一些函数声明和头文件。
  3. **最后一部分,声明了要封装的函数和变量。**如果把要封装的函数声明部分写在了头文件里,最后一部分直接用%include包含头文件名也行。

此处HuffmanEncoderCompress.h调用了std::string库,所以需要%include "std::string.i"

The SWIG library std_string.i has language specific code for mapping the c++ string to the target languages string class. Adding %include "std_string.i" before the code that generates your class should fix the error.

Note that %include is different from #include in a swig interface file.

通过命令行运行

swig python -c++ huffman.i

这样会创建两个不同的文件,huffman_wrap.cxxHuffman.py

1.2、使用python.distutils生成模块动态库

编写配置文件setup.py

# File: setup.py

from distutils.core import setup, Extension

# 生成一个扩展模块
hfm_module = Extension('_Huffman',  # 模块名称,必须要有下划线
                       sources=['E:\\Project\Huffman\Huffman_wrap.cxx',  # 封装后的接口cxx文件
                                'E:\\Project\Huffman\HuffmanEncoderCompress.cpp'  # 以下为原始代码所依赖的文件
                                ],
                       )

setup(name='Huffman',  # 打包后的名称
      version='0.1',
      author='SWIG Docs',
      description='Simple swig pht from docs',
      ext_modules=[hfm_module],  # 与上面的扩展模块名称一致
      py_modules=['Huffman'],  # 需要打包的模块列表
      )

通过命令行运行

python setup.py build_ext --inplace

这样会在本目录下生成_Huffman.pyd模块。

出现的问题

1.python\include\pyconfig.h(59): fatal error C1083: Cannot open include file: 'io.h': No such file or directory

解决方法:

添加环境变量INCLUDE,路径指向VC的Include文件夹,如

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\include

2.e:\python\include\pyconfig.h(206): fatal error C1083: Cannot open include file: 'basetsd.h': No such file or directory

解决方法:

In case anyone is currently (2017) facing same error with visual C++ 2015 tools, launch setup again and also select windows 8.1 / 10 SDK depending upon your OS. This will fix basestd.h error.

If it is still not working, try launching build tools from: C:\Program Files (x86)\Microsoft Visual C++ Build Tools.

通过C:\Program Files (x86)\Microsoft Visual C++ Build Tools\Visual C++ 2015 x86 x64 Cross Build Tools Command Prompt 命令行运行

以管理员身份运行

在这里插入图片描述

这样会在该目录下生成_Huffman.pyd模块。

在这里插入图片描述

1.3 测试Python调用

注:如果导入模块失败,需要将模块所在路径添加到sys.path

import sys
sys.path.append("PATH")

压缩文件

import Huffman
Huffman.Huffman("file\\test.pdf")

在这里插入图片描述

成功生成压缩文件

在这里插入图片描述

解压缩文件

import Huffman
Huffman.Huffman("file\\test.pdf.hfm")

在这里插入图片描述

成功生成解压缩文件

在这里插入图片描述

2、Java调用C++

2.1 Java生成C++头文件

新建一个Java项目,项目结构如下:

在这里插入图片描述

编写测试代码

package com.huffman.test;

public class JNIDemo {

    public native void Huffman();

    public static void main(String[] args){
        System.loadLibrary("Huffman_DLL");
        JNIDemo jnidemo = new JNIDemo();
        jnidemo.Huffman();
    }
}

生成C++头文件

java程序包的目录src执行 javac -h命令

E:\Project\Java\Huffman\src>javac -h ./ com\huffman\test\JNIDemo.java

会生成一个.h的头文件:

在这里插入图片描述

2.2 创建C++项目

新建一个C++项目,选择动态链接库(.dll)

在这里插入图片描述

配置新项目名称为"Huffman_JNI"

2.3 拷贝头文件

将jdk安装目录下的:include下的jni.h、 include/win32下的jni_md.h,java生成的头文件com_huffman_test_JNIDemo.h拷贝到C++项目空间中

在这里插入图片描述

并在C++项目中添加这三个头文件:

在这里插入图片描述

修改com_huffman_test_JNIDemo.h,把#include <jni.h>改成#include "jni.h"

2.4 编写C++代码

新建类,命名为:

在这里插入图片描述

在这个类中实现数据的压缩与解压缩

项目结构:

在这里插入图片描述

Java接口函数:

在这里插入图片描述

2.5 生成DLL文件

配置项目属性为Release X64:

在这里插入图片描述

在工程名上右键生成:

在这里插入图片描述

工程目录下就会生成.dll文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o4snXs0B-1619093268834)(pic\17.png)]

2.6 将DLL文件应用到Java项目中

将Huffman_JNI.dll拷贝到如下目录:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FcOAJq3A-1619093268835)(pic\18.png)]

将DLL添加到项目的Library中

File --> Project Structure --> Huffman --> Dependencies --> 点**+** --> JARs or Directories --> 选择 Huffman_JNI.dll

在这里插入图片描述

2.7 运行Java测试

点击运行“Run JNIDemo”,程序成功调用之前用C++写的代码:

压缩文件:

在这里插入图片描述

解压缩文件:

在这里插入图片描述

四、实验出现的问题

Java调用C++生成的dll时会出现中文乱码问题

java内部是使用16bit的unicode编码(UTF-16)来表示字符串的,无论中文英文都是2字节; jni内部是使用UTF-8编码来表示字符串的,UTF-8是变长编码的unicode,一般ascii字符是1字节,中文是3字节; c/c++使用的是原始数据,ascii就是一个字节了,中文一般是GB2312编码,用两个字节来表示一个汉字。

C++打印出的信息如果有中文就会导致乱码,如果调用时传输的参数有中文将会导致调用出错.

解决方案:实现utf与gb2312的转换

char* jstringToWindows( JNIEnv *env, jstring jstr )
{ //UTF8/16转换成gb2312
  int length = (env)->GetStringLength(jstr );
  const jchar* jcstr = (env)->GetStringChars(jstr, 0 );
  char* rtn = (char*)malloc( length*2+1 );
  int size = 0;
  size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL );
  if( size <= 0 )
    return NULL;
  (env)->ReleaseStringChars(jstr, jcstr );
  rtn[size] = 0;
  return rtn;
}

jstring WindowsTojstring( JNIEnv* env, const char* str )
{//gb2312转换成utf8/16
    jstring rtn = 0;
    int slen = strlen(str);
    unsigned short * buffer = 0;
    if( slen == 0 )
        rtn = (env)->NewStringUTF(str );
    else
    {
        int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
        buffer = (unsigned short *)malloc( length*2 + 1 );
        if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
            rtn = (env)->NewString(  (jchar*)buffer, length );
    }
    if( buffer )
        free( buffer );
    return rtn;
}

五、实验思考

请讨论跨语言开发的利弊;

利:

可以直接利用现有的库,避免了重复造轮子.

开发跨平台程序是对自己技术的一种挑战,也能在代码重构过程中得到一些新的经验。

能够与不同平台开发者交流以获得更多的技能点提升。

弊:

可能会导致预料之外的错误.

除了直接的跨语言调用,还有哪些方式可以多语言的协同开发?如果无法实现直接的跨语言调用,该如何实现多语言的协作?

还可以通过Web进行通信;打包成库;生成可执行文件等.



这篇关于跨语言调用和编程 实现数据压缩和解压缩的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程