以C++實現讀寫文件,Java調用為例。包括中文路徑的傳遞和數組的傳入傳出。
1.環境准備
保證Java代碼能夠正確編譯運行(安裝JDK,正確配置環境變量)
保證C++代碼能夠正確編譯(安裝VS或者Eclipse等)
文件目錄結構
E:\JNI\com\yiluboke\zxy\WriteReadJ.java
E:\JNI\WriteReadC++
2.編寫java代碼(WriteReadJ.java)
package com.yiluboke.zxy;
class WriteReadJ {
// 函數功能:將內存數據寫入文件
// 傳入參數:bData 內存數據
// iLen 內存數據的長度
// strFilePath 文件路徑
// 返回參數:
public native int writeFile(byte bData[], String strFilePath);
// 函數功能:文件是否正確讀取
// 傳入參數:strFilePath 文件路徑
// 返回參數:0 正確
public native int readFilePre(String strFilePath);
// 函數功能:讀取文件
// 傳入參數:strFilePath 文件路徑
// 返回參數:返回文件的內容
public native byte[] readFile(String strFilePath);
static {
// 調用動態鏈接庫
System.loadLibrary("jniwritereadfile");
}
public static void main(String[] args){
WriteReadJ demo = new WriteReadJ();
byte[] bytes = new byte[3];
bytes[0] = '7';
bytes[1] = '8';
bytes[2] = 'h';
int nResult = 0;
String strFilePathName = "E:\\JNI\\新建文本文檔.txt";
try {
strFilePathName = new String(strFilePathName.getBytes(),"gb2312");
} catch (Exception ex) {
System.out.println(ex);
return;
}
nResult = demo.writeFile(bytes, strFilePathName);
if (nResult == 0) {
System.out.println("寫入成功");
} else {
System.out.println("寫入失敗錯誤碼:" + nResult);
}
nResult = demo.readFilePre(strFilePathName);
if (nResult == 0) {
System.out.println("讀取成功");
byte[] fileReadData = demo.readFile(strFilePathName);
System.out.println("獲取數據如下: ");
for (int index = 0; index < fileReadData.length; index++) {
System.out.println(fileReadData[index]);
}
} else {
System.out.println("讀取失敗錯誤碼:" + nResult);
}
}
}
3.編譯Java代碼,生成class文件
在E:\JNI目錄下
javac E:\JNI\com\yiluboke\zxy\WriteReadJ.java,在該java文件所在目錄下生成WriteReadJ.class文件。
4.生成.h文件
在E:\JNI目錄下
javah -jni com.yiluboke.zxy.WriteReadJ,在當前目錄下生成com_yiluboke_zxy_WriteReadJ.h文件
5.編寫C++代碼,並編譯成dll文件
writeReadDo.h
#ifndef __WRITEREADDO__H
#define __WRITEREADDO__H
typedef unsigned char BYTE;
const int MAXLEN = 1024;
extern BYTE gbData[MAXLEN];
extern int gbLen;
//函數功能:將內存數據寫入文件
//傳入參數:bData 內存數據
// iLen 內存數據的長度
// strFilePath 文件路徑
//返回參數: 0 成功 非0參見錯誤碼
int writeFile(BYTE bData[],int iLen,const char* strFilePath);
//函數功能:讀取寫入的數據
//傳入參數:strFilePath 文件路徑
//返回參數:0 成功 非0參見錯誤碼
int readFile(const char* strFilePath);
#endif
writeReadDo.cpp
#include "writeReadDo.h"
#include "fstream"
using namespace std;
int writeFile(BYTE bData[],int iLen,const char* strFilePath)
{
fstream fOut(strFilePath, ios::out | ios::binary);
if(!fOut)
return -1;
fOut.write((const char*)&bData[0],iLen);
fOut.close();
return 0;
}
BYTE gbData[MAXLEN] = {};
int gbLen = 0;
int readFile(const char* strFilePath)
{
ifstream fIn(strFilePath,ios::in | ios::binary);
if(!fIn)
return -1;
fIn.seekg(0,ios_base::end);
int bCount = fIn.tellg();
fIn.seekg(0 , ios::beg);
if (bCount < MAXLEN)
{
gbLen = bCount;
fIn.read((char*)&gbData[0], bCount);
}
else
{
gbLen = MAXLEN;
fIn.read((char*)&gbData[0], MAXLEN);
}
fIn.close();
return 0;
}
com_yiluboke_zxy_WriteReadJ.cpp
#include "com_yiluboke_zxy_WriteReadJ.h"
#include "writeReadDo.h"
#include
static const char* encodeMode = "GB2312";
char* Jstring2CStr(JNIEnv* env, jstring jstr, int* charLen)
{
char* chRet = NULL;
jclass classStr = env->FindClass("java/lang/String");
jstring jstrEncode = env->NewStringUTF(encodeMode);
jmethodID methodId = env->GetMethodID(classStr, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray bArray = (jbyteArray)env->CallObjectMethod(jstr, methodId, jstrEncode);
jsize bArrayLen = env->GetArrayLength(bArray);
*charLen = bArrayLen + 1;
jbyte* pByte = env->GetByteArrayElements(bArray,JNI_FALSE);
if(bArrayLen > 0)
{
chRet =new char[bArrayLen + 1];
memcpy(chRet,pByte,bArrayLen);
chRet[bArrayLen]=0;
}
env->ReleaseByteArrayElements(bArray,pByte,0);
return chRet;
}
JNIEXPORT jint JNICALL Java_com_yiluboke_zxy_WriteReadJ_writeFile
(JNIEnv *env, jobject, jbyteArray bData, jstring jstrFilePath)
{
int chlen = 0;
const char* chFilePath = Jstring2CStr( env, jstrFilePath, &chlen) ;//jstringToWindows( env, jstrFilePath ); //(*env).GetStringUTFChars(jstrFilePath, 0); //修改文件名亂碼
jbyte *jData = (jbyte*)env->GetByteArrayElements(bData, 0);
jsize jSize = env->GetArrayLength(bData);
BYTE* bytearr = (BYTE*)jData;
int len = (int)jSize;
int nResult = writeFile(bytearr,len, chFilePath);
//(*env).ReleaseStringUTFChars(jstrFilePath, chFilePath);
if(chFilePath)
{
delete [] chFilePath;
chFilePath = NULL;
}
return nResult;
}
JNIEXPORT jint JNICALL Java_com_yiluboke_zxy_WriteReadJ_readFilePre
(JNIEnv *env, jobject, jstring jstrFilePath)
{
int chlen = 0;
const char* chFilePath =Jstring2CStr( env, jstrFilePath, &chlen) ;// (*env).GetStringUTFChars(jstrFilePath, 0);//jstringToWindows(env,jstrFilePath);
int nResult = readFile(chFilePath);
//(*env).ReleaseStringUTFChars(jstrFilePath, chFilePath);
if(chFilePath)
{
delete [] chFilePath;
chFilePath = NULL;
}
return nResult;
}
JNIEXPORT jbyteArray JNICALL Java_com_yiluboke_zxy_WriteReadJ_readFile
(JNIEnv *env, jobject, jstring)
{
jbyte *by = (jbyte*)gbData;
int len = gbLen;
jbyteArray jarray = (*env).NewByteArray(len);
(*env).SetByteArrayRegion(jarray, 0, len, by);
return jarray;
}
6.運行java文件
在E:\JNI目錄下
java com.yiluboke.zxy.WriteReadJ
7.完整Demo下載
百度網盤地址:http://pan.baidu.com/s/1bot3wyr
本文采 用的JDK是 64位版本1.8.0_60。
E:\JNI>java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
編譯錯誤:
如果遇到編譯錯誤jni.h錯誤,替換工程中jni.h及jni.md.h為電腦中JDK安裝路徑中的jni.h及jni_md.h即可。
運行錯誤:
Exception in thread "main" java.lang.UnsatisfiedLinkError: E:\JNI\jniwritereadfile.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform
dll編譯成:64位dll