Android上传文件到服务器中的简单实例(1)

本文详细描述了一个使用JNI编写的Java程序与C编写的服务器端进行文件传输的过程,包括Java客户端的ProgressDialog显示、文件名发送以及C服务器端的文件接收、解析和写入。讨论了基础数据类型转换问题和文件处理细节。
摘要由CSDN通过智能技术生成

progressdialog.show();

Log.d(“DUBUG”, “total is”+total);

new Thread(){

int count=0;

public void run() {

// TODO Auto-generated method stub

try{

while(count<100)

{

progressdialog.setProgress(count+=4);

Thread.sleep(100);

}

progressdialog.cancel();

}catch(InterruptedException e){

e.printStackTrace();

}

}

}.start();

}

}

});

}

}

这个很简单吧发送的东西交友jni编写的静待库去做了它返回独到的字节数并Toast出来,这个便于我们统计嘛还有一个progredialog。额·这个···美化一下哈实际上没什么用处滴~

好了客户端java部分就到此为止了,下面是重头戏之一,FileOperation.so啦!!

继续上代码,大家如果对JNI有不熟悉的话可以先去了解一下哈~

查看源码打印

#include<sys/socket.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<string.h>

#include<arpa/inet.h>

#include<sys/wait.h>

#include<netinet/in.h>

#include “zeng_Glogo_learn_FileOperation.h”

#define MAXBUF 1024

#define FILEPATH 255

#define FILENAME 255

int sockfd;

unsigned char buffer[MAXBUF];

char *end;

unsigned char end_buf[29];

struct sockaddr_in client_addr;

jint Java_zeng_Glogo_learn_FileOperation_fileOperatin

(JNIEnv *env, jobject thiz, jstring FilePath,jstring FileName)

{

const char *filepath_buf=(*env)->GetStringUTFChars(env,FilePath,0);

char filepath[FILEPATH];

strcpy(filepath,filepath_buf);

(*env)->ReleaseStringUTFChars(env,FilePath,filepath_buf);

const char *filename_buf=(*env)->GetStringUTFChars(env,FileName,0);

char filename[FILENAME];

memset(filename,0,FILENAME);

strncpy(filename,filename_buf,strlen(filename_buf));

(*env)->ReleaseStringUTFChars(env,FileName,filename_buf);

//开始读取文件,并发送给服务端

FILE *fp;

fp=fopen(filepath,“rb”);

if(!fp)

{

return -1;

}

int file_name=send(sockfd,filename,strlen(filename),0); //发送文件名

if(file_name<0)

{

return -2;

}

//int file_block_length=0;

int count=0; //将文件分块传输

int ReadNum=0;

int ReadSum=0;

unsigned char LenBuffer[1];

while(!feof(fp)) //读取文件的内容到buffer中

{

ReadNum=fread(buffer,1,MAXBUF,fp);

ReadSum+=ReadNum;

if(ReadNum>0)

{

if(send(sockfd,buffer,ReadNum,0)==-1)

{

fclose(fp);

return -3;

}

bzero(buffer,MAXBUF);

count++;

}

else

{

fclose(fp);

break;

}

}

//bzero(buffer,MAXBUF);

/*end=“EndLessLimiteFromGlogoPassion”;

strcmp(end_buf,end);

send(sockfd,end_buf,29,0);*/

//send(sockfd,end_buf,strlen(end_buf),0);

fclose(fp);

return ReadSum;

}

jstring Java_zeng_Glogo_learn_FileOperation_connect

(JNIEnv *env, jobject thiz, jstring IPAddress, jint PORT)

{

//转换String类型

const char * ipaddress_buf=(*env)->GetStringUTFChars(env,IPAddress,0);

char ipaddress[255];

strcpy(ipaddress,ipaddress_buf);

(*env)->ReleaseStringUTFChars(env,IPAddress,ipaddress_buf);

int port=PORT;

bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0

/* AF_INET域

struct sockaddr_in

{

short int sin_family; //AF_INET

unsigned short int sin_port; //Port number

struct in_addr{

unsigned long s_addr //Internet address

}

}*/

sockfd=socket(AF_INET,SOCK_STREAM,0);

if(sockfd<0)

{

return (*env)->NewStringUTF(env,“Socket Error 101”);

}

client_addr.sin_family=AF_INET; //internet协议族

client_addr.sin_port=htons(port); //端口号

/*也可以这么写

client_addr.sin_addr.s_addr=inet_addr(ipaddress); //转化IP地址 inet_addr和inet_aton的不同在于结果返回值的形式不同,

//inet_addr返回值为in_addr_t, inet_aton返回值为整形,但两者的转换的地址仍存放在straddr中

//in_addr_t inet_addr(const char* straddr) , int inet_aton(const char* straddr,struct in_addr *addrp)

//另外,sin_addr.s_addr=htonl(INADDR_ANY)表示*/

if(inet_aton(ipaddress,&client_addr.sin_addr)<0)

{

return (*env)->NewStringUTF(env,“inet_aton Error 101”);

}

if(connect(sockfd,(struct sockaddr*)&client_addr,sizeof(client_addr))<0)

{

return (*env)->NewStringUTF(env,“Connect Error 101”);

}

else

{

return (*env)->NewStringUTF(env,“Connec OK!”);

}

}

jstring Java_zeng_Glogo_learn_FileOperation_disconnect

(JNIEnv *env, jobject thiz)

{

close(sockfd);

return (*env)->NewStringUTF(env,“Socket Close!”);

}

大家应该看到了~这些都是Linux下C编程的一些简单的东西,这里说明一下,在jint Java_zeng_Glogo_learn_FileOperation_fileOperatin函数中的count变量是没什么用的,我懒得删掉而已哈~

在发送文件这边没什么的,就是根据传进来的文件路径FilePath打开文件读取内容,并发送文件名给服务端,然后就是在!fp的情况下一次一次的send而已。嗯~客户端的就到此为止啦!!

下面的是服务端的啦在这里我纠结了很久,后来终于发现问题,发送方发送的字节数是对的,但是接收方由于是java编写的,所以传过来的时候会涉及到基本数据类型的转换问题,这是一个老问题了但是嘛基础不够扎实的我还是忽略了在这里耽误了很多时间,好了上代码吧

查看源码打印

package learn;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.DataInputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.FileWriter;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.ServerSocket;

import java.net.Socket;

import java.nio.ByteBuffer;

public class JniServer_File implements Runnable{

int PORT=8888;

/**

  • @param args

*/

@Override

public void run() {

// TODO Auto-generated method stub

try{

System.out.println(" 服务器开启…");

System.out.println(“---- ---- ---- ----”);

ServerSocket serverSocket=new ServerSocket(PORT);

while(true){

Socket client=serverSocket.accept();

System.out.println(" 接收到客户端请求…");

System.out.println(“---- ---- ---- ----”);

System.out.println(" 打开输入流。。");

System.out.println(“---- ---- ---- ----”);

BufferedInputStream filename=new BufferedInputStream(client.getInputStream());

System.out.println(" 正在读取内容(文件名)…");

System.out.println(“---- ---- ---- ----”);

byte file_name[]=new byte[255];

filename.read(file_name);

String file_name_trans=new String(file_name);

System.out.println(" 读取文件名完毕,文件名是"+new String(file_name));

System.out.println(“---- ---- ---- ----”);

try{

if(file_name_trans!=“”){

System.out.println(" 开始创建文件… "+file_name_trans);

String file=“D:/Eclipse/test/HelloCDT.txt”; //文件的绝对路径

File newFile=new File(file); //创建文件对象

if(newFile.exists())

{

//检查文件在当前路径下是否存在

newFile.createNewFile();

}

System.out.println(“---- ---- ---- ----”);

System.out.println(“---- ---- ---- ----”);

System.out.println(" 打开文件输出流,准备将读取内容写入相应文件");

BufferedOutputStream file_context_in_buf=new BufferedOutputStream(new FileOutputStream(file,false));

System.out.println(“---- ---- ---- ----”);

System.out.println(" 正在将内容写入文件…");

int count=0; //测试用的标志

byte[] file_context=new byte[1024];

while(filename.read(file_context)>0){ //循环读取文件内容,并写入到相应的文件保存起来

count++;

System.out.println(" read times for "+count);

String end_buf_str=new String(file_context);

if(end_buf_str.contains(“END”)){

int len=end_buf_str.lastIndexOf(“END”);

String end_buf_str1=end_buf_str.substring(0, len+3);

byte end_buf_byte[]=end_buf_str1.getBytes();

file_context_in_buf.write(end_buf_byte);

System.out.println(" write times for "+count);

System.out.println(" This times is "+count);

System.out.println(“---- ---- ---- ----”);

break;

}

file_context_in_buf.write(file_context);

System.out.println(" write times for "+count);

System.out.println(" This times is "+count);

System.out.println(“---- ---- ---- ----”);

}

file_context_in_buf.flush();

System.out.println(" file_context_in_buf flush times for "+count);

System.out.println(“---- ---- ---- ----”);

System.out.println(" 写入完毕,请打开文件查看…"+count);

System.out.println(“---- ---- ---- ----”);

System.out.println(" 关闭文件各种流…");

System.out.println(“---- ---- ---- ----”);

file_context_in_buf.close(); //先关闭外层的缓冲连接流

filename.close();

file_name_trans=“”;

}

}

catch(IOException e){

e.printStackTrace();

System.out.println(e.getMessage()+" —1");

}

finally{

client.close(); //关闭socket

System.out.println(" 关闭连接");

}

}

}

catch(Exception e){

e.printStackTrace();

System.out.println(e.getMessage()+" —2");

}

}

public static void main(String[] args) {

// TODO Auto-generated method stub

Thread jniServer_File=new Thread(new JniServer_File());

jniServer_File.start

熟悉java的同学应该清楚上面的代码吧比较特殊的是在循环接收客户端send()过来的东西的时候,我这边做了一点小偷懒,就是发送是.txt文件最后都是以END结尾的,这个给了我一个方便,就是我可以根据这个来判断什么时候终止再往文件写入内容。还有一点是,传输是以字节为单位来传输的,所以要用Strean来接收和存入,用字符流Reader和Writer都是不靠谱的!这里面还涉及到String和byte类型的转化问题,我在这里也纠结过很久啦呵呵 ,大家先别喷,我坦诚是我的基础部够扎实啦~

好了基本就是这样子的! 这边的上图比较麻烦,所以没图没真相···额好吧········大家这样想的话也么办法啦·不过本人已经试验过啦一个15014KB的文件还有一个396800KB的文件传输都是没问题的,放在手机上测试也OK

上图不方便我这里贴一下man.xml的代码让大家都整个布局都有些了解吧~

查看源码打印

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:orientation=“vertical” >

<TextView

android:layout_width=“fill_parent”

android:layout_height=“wrap_content”

android:text=“@string/hello”

android:id=“@+id/tv” />

<TextView

android:layout_marginTop=“15dp”

android:layout_below=“@id/tv”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:id=“@+id/dir”

android:text=“@string/dir”/>

<EditText

android:layout_width=“260dp”

android:layout_height=“wrap_content”

android:hint=“@string/file_name_hint”

android:id=“@+id/file_name”

android:layout_below=“@id/tv”

android:layout_toRightOf=“@id/dir”/>

<TextView

android:layout_height=“wrap_content”

android:layout_width=“wrap_content”

android:text=“@string/dir1”

android:layout_below=“@id/dir”

android:id=“@+id/dir1”

android:layout_marginTop=“25dp”/>

<EditText

android:layout_width=“260dp”

android:layout_height=“wrap_content”

android:hint=“@string/file_seletced_hint”

android:id=“@+id/file_seletced”

android:layout_below=“@id/file_name”

android:layout_toRightOf=“@id/dir1”/>

<Spinner

android:layout_width=“fill_parent”

android:layout_height=“wrap_content”

android:id=“@+id/spinner”

android:layout_below=“@id/file_seletced”/>

<Button

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“@string/send”

android:id=“@+id/send”

android:layout_below=“@id/spinner”

android:layout_alignRight=“@id/spinner”/>

<EditText

android:layout_height=“wrap_content”

android:layout_width=“150dp”

android:layout_below=“@id/send”

android:layout_alignParentLeft=“true”

android:hint=“@string/ip”

android:id=“@+id/ip”/>

<EditText

android:layout_height=“wrap_content”

android:layout_width=“80dp”

android:layout_toRightOf=“@id/ip”

android:hint=“@string/port”

android:layout_below=“@id/send”

android:layout_marginLeft=“5dp”

android:id=“@+id/port”/>

<Button

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_toRightOf=“@id/port”

android:layout_below=“@id/send”

android:id=“@+id/sure”

android:layout_alignParentRight=“true”

android:text=“@string/sure”/>

最后

**要想成为高级安卓工程师,必须掌握许多基础的知识。**在工作中,这些原理可以极大的帮助我们理解技术,在面试中,更是可以帮助我们应对大厂面试官的刁难。


网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

“5dp”

android:id=“@+id/port”/>

<Button

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_toRightOf=“@id/port”

android:layout_below=“@id/send”

android:id=“@+id/sure”

android:layout_alignParentRight=“true”

android:text=“@string/sure”/>

最后

**要想成为高级安卓工程师,必须掌握许多基础的知识。**在工作中,这些原理可以极大的帮助我们理解技术,在面试中,更是可以帮助我们应对大厂面试官的刁难。


[外链图片转存中…(img-ByC2a9st-1714352964788)]

[外链图片转存中…(img-3etBiteZ-1714352964789)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值