ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2021-04-22 20:33:25  阅读:236  来源: 互联网

标签:调用 Java 编程 解压缩 C++ 生成 include Huffman 数据压缩


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

一、前言

实验内容

一个功能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进行通信;打包成库;生成可执行文件等.

标签:调用,Java,编程,解压缩,C++,生成,include,Huffman,数据压缩
来源: https://blog.csdn.net/weixin_43853027/article/details/116029795

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有