Android学习笔记_43_网络通信之文件断点上传

1、建立服务端,用于接收上传的文件。这里使用Socket,文件可能会比较大。采用多线程编程,防止并发。

  

package com.socket.service;



import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.OutputStream;

import java.io.PushbackInputStream;

import java.io.RandomAccessFile;

import java.net.ServerSocket;

import java.net.Socket;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.HashMap;

import java.util.Map;

import java.util.Properties;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;



import com.socket.service.util.StreamTool;



public class FileServer {



    private ExecutorService executorService;// 线程池,实现网络多用户并发

    private int port;// 监听端口

    private boolean quit = false;// 退出

    private ServerSocket server;

    private Map<Long, FileLog> datas = new HashMap<Long, FileLog>();// 存放断点数据



    public FileServer(int port) {

        this.port = port;

        // 创建线程池,池中具有(cpu个数*50)条线程

        executorService = Executors.newFixedThreadPool(Runtime.getRuntime()

                .availableProcessors() * 50);

    }



    /**

     * 退出

     */

    public void quit() {

        this.quit = true;

        try {

            server.close();

        } catch (IOException e) {

        }

    }



    /**

     * 启动服务

     * 

     * @throws Exception

     */

    public void start() throws Exception {

        server = new ServerSocket(port);

        while (!quit) {

            try {

                Socket socket = server.accept();

                // 为支持多用户并发访问,采用线程池管理每一个用户的连接请求

                executorService.execute(new SocketTask(socket));

            } catch (Exception e) {

                // e.printStackTrace();

            }

        }

    }



    private final class SocketTask implements Runnable {

        private Socket socket = null;



        public SocketTask(Socket socket) {

            this.socket = socket;

        }



        public void run() {

            try {

                System.out.println("accepted connection "

                        + socket.getInetAddress() + ":" + socket.getPort());

                PushbackInputStream inStream = new PushbackInputStream(

                        socket.getInputStream());

                // 得到客户端发来的第一行协议数据:Content-Length=143253434;filename=xxx.3gp;sourceid=

                // 如果用户初次上传文件,sourceid的值为空。

                String head = StreamTool.readLine(inStream);

                System.out.println(head);

                if (head != null) {

                    // 下面从协议数据中提取各项参数值

                    String[] items = head.split(";");

                    String filelength = items[0].substring(items[0].indexOf("=") + 1);

                    String filename = items[1].substring(items[1].indexOf("=") + 1);

                    String sourceid = items[2].substring(items[2].indexOf("=") + 1);

                    long id = System.currentTimeMillis();// 生产资源id,如果需要唯一性,可以采用UUID

                    FileLog log = null;

                    if (sourceid != null && !"".equals(sourceid)) {

                        id = Long.valueOf(sourceid);

                        log = find(id);// 查找上传的文件是否存在上传记录

                    }

                    File file = null;

                    int position = 0;

                    if (log == null) {// 如果不存在上传记录,为文件添加跟踪记录

                        String path = new SimpleDateFormat("yyyy/MM/dd/HH/mm").format(new Date());

                        File dir = new File("file/" + path);

                        if (!dir.exists())

                            dir.mkdirs();

                        file = new File(dir, filename);

                        if (file.exists()) {// 如果上传的文件发生重名,然后进行改名

                            filename = filename.substring(0,filename.indexOf(".") - 1)

                                    + dir.listFiles().length

                                    + filename.substring(filename.indexOf("."));

                            file = new File(dir, filename);

                        }

                        save(id, file);

                    } else {// 如果存在上传记录,读取已经上传的数据长度

                        file = new File(log.getPath());// 从上传记录中得到文件的路径

                        if (file.exists()) {

                            File logFile = new File(file.getParentFile(),file.getName() + ".log");

                            if (logFile.exists()) {

                                Properties properties = new Properties();

                                properties.load(new FileInputStream(logFile));

                                position = Integer.valueOf(properties.getProperty("length"));// 读取已经上传的数据长度

                            }

                        }

                    }



                    OutputStream outStream = socket.getOutputStream();

                    String response = "sourceid=" + id + ";position="

                            + position + "\r\n";

                    // 服务器收到客户端的请求信息后,给客户端返回响应信息:sourceid=1274773833264;position=0

                    // sourceid由服务器端生成,唯一标识上传的文件,position指示客户端从文件的什么位置开始上传

                    outStream.write(response.getBytes());

                    RandomAccessFile fileOutStream = new RandomAccessFile(file,

                            "rwd");

                    if (position == 0)

                        fileOutStream.setLength(Integer.valueOf(filelength));// 设置文件长度

                    fileOutStream.seek(position);// 指定从文件的特定位置开始写入数据

                    byte[] buffer = new byte[1024];

                    int len = -1;

                    int length = position;

                    while ((len = inStream.read(buffer)) != -1) {// 从输入流中读取数据写入到文件中

                        fileOutStream.write(buffer, 0, len);

                        length += len;

                        Properties properties = new Properties();

                        properties.put("length", String.valueOf(length));

                        FileOutputStream logFile = new FileOutputStream(

                                new File(file.getParentFile(), file.getName()

                                        + ".log"));

                        properties.store(logFile, null);// 实时记录已经接收的文件长度

                        logFile.close();

                    }

                    if (length == fileOutStream.length())

                        delete(id);

                    fileOutStream.close();

                    inStream.close();

                    outStream.close();

                    file = null;

                }

            } catch (Exception e) {

                e.printStackTrace();

            } finally {

                try {

                    if (socket != null && !socket.isClosed())

                        socket.close();

                } catch (IOException e) {

                }

            }

        }

    }



    public FileLog find(Long sourceid) {

        return datas.get(sourceid);

    }



    // 保存上传记录

    public void save(Long id, File saveFile) {

        // 日后可以改成通过数据库存放

        datas.put(id, new FileLog(id, saveFile.getAbsolutePath()));

    }



    // 当文件上传完毕,删除记录

    public void delete(long sourceid) {

        if (datas.containsKey(sourceid))

            datas.remove(sourceid);

    }



    private class FileLog {

        private Long id;

        private String path;



        public Long getId() {

            return id;

        }



        public void setId(Long id) {

            this.id = id;

        }



        public String getPath() {

            return path;

        }



        public void setPath(String path) {

            this.path = path;

        }



        public FileLog(Long id, String path) {

            this.id = id;

            this.path = path;

        }

    }



}

2、通过swing编程启动服务:可以导出运行时jar文件。

package com.socket.service;



import java.awt.BorderLayout;

import java.awt.Frame;

import java.awt.Label;

import java.awt.event.WindowEvent;

import java.awt.event.WindowListener;





public class ServerWindow extends Frame {

    /**

     * 

     */

    private static final long serialVersionUID = -2723969590211090349L;

    private FileServer s = new FileServer(7788);

    private Label label;



    public ServerWindow(String title) {

        super(title);

        label = new Label();

        add(label, BorderLayout.PAGE_START);

        label.setText("服务器已经启动");

        this.addWindowListener(new WindowListener() {

            public void windowOpened(WindowEvent e) {

                new Thread(new Runnable() {



                    public void run() {

                        try {

                            s.start();

                        } catch (Exception e) {

                            // e.printStackTrace();

                        }

                    }

                }).start();

            }



            public void windowIconified(WindowEvent e) {

            }



            public void windowDeiconified(WindowEvent e) {

            }



            public void windowDeactivated(WindowEvent e) {

            }



            public void windowClosing(WindowEvent e) {

                s.quit();

                System.exit(0);

            }



            public void windowClosed(WindowEvent e) {

            }



            public void windowActivated(WindowEvent e) {

            }

        });

    }



    /**

     * @param args

     */

    public static void main(String[] args) {

        ServerWindow window = new ServerWindow("文件上传服务端");

        window.setSize(300, 300);

        window.setVisible(true);

    }

}
View Code

3、解析socket协议工具类:

package com.socket.service.util;



import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.PushbackInputStream;



public class StreamTool {



    public static void save(File file, byte[] data) throws Exception {

        FileOutputStream outStream = new FileOutputStream(file);

        outStream.write(data);

        outStream.close();

    }



    public static String readLine(PushbackInputStream in) throws IOException {

        char buf[] = new char[128];

        int room = buf.length;

        int offset = 0;

        int c;

        loop: while (true) {

            switch (c = in.read()) {

            case -1:

            case '\n':

                break loop;

            case '\r':

                int c2 = in.read();

                if ((c2 != '\n') && (c2 != -1))

                    in.unread(c2);

                break loop;

            default:

                if (--room < 0) {

                    char[] lineBuffer = buf;

                    buf = new char[offset + 128];

                    room = buf.length - offset - 1;

                    System.arraycopy(lineBuffer, 0, buf, 0, offset);



                }

                buf[offset++] = (char) c;

                break;

            }

        }

        if ((c == -1) && (offset == 0))

            return null;

        return String.copyValueOf(buf, 0, offset);

    }



    /**

     * 读取流

     * 

     * @param inStream

     * @return 字节数组

     * @throws Exception

     */

    public static byte[] readStream(InputStream inStream) throws Exception {

        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();

        byte[] buffer = new byte[1024];

        int len = -1;

        while ((len = inStream.read(buffer)) != -1) {

            outSteam.write(buffer, 0, len);

        }

        outSteam.close();

        inStream.close();

        return outSteam.toByteArray();

    }

}

4、java客户端测试:

package com.socket.service;



import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.InputStream;

import java.io.OutputStream;

import java.io.PushbackInputStream;

import java.io.RandomAccessFile;

import java.net.Socket;



import com.socket.service.util.StreamTool;



public class SocketClient {

    /**

     * @param args

     */

    public static void main(String[] args) {

        try {

            String filename = "1.zip";

            String dir=SocketClient.class.getClassLoader().getResource(filename).getPath();

            System.out.println(dir);

            Socket socket = new Socket("127.0.0.1", 7878);

            OutputStream outStream = socket.getOutputStream();

            File file = new File("src/"+filename);

            System.out.println(file.exists());

            String head = "Content-Length=" + file.length() + ";filename=" +filename + ";sourceid=\r\n";

            outStream.write(head.getBytes());



            PushbackInputStream inStream = new PushbackInputStream(socket.getInputStream());

            String response = StreamTool.readLine(inStream);

            System.out.println(response);

            String[] items = response.split(";");

            String position = items[1].substring(items[1].indexOf("=") + 1);

            RandomAccessFile fileOutStream = new RandomAccessFile(file, "r");

            fileOutStream.seek(Integer.valueOf(position));

            byte[] buffer = new byte[1024];

            int len = -1;

            while ((len = fileOutStream.read(buffer)) != -1) {

                outStream.write(buffer, 0, len);

            }

            System.out.println(" finish .. ");

            fileOutStream.close();

            outStream.close();

            inStream.close();

            socket.close();

        } catch (Exception e) {

            e.printStackTrace();

        }



    }



    /**

     * 读取流

     * 

     * @param inStream

     * @return 字节数组

     * @throws Exception

     */

    public static byte[] readStream(InputStream inStream) throws Exception {

        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();

        byte[] buffer = new byte[1024];

        int len = -1;

        while ((len = inStream.read(buffer)) != -1) {

            outSteam.write(buffer, 0, len);

        }

        outSteam.close();

        inStream.close();

        return outSteam.toByteArray();

    }

}

----------------------------------------------------------------------------------------------------------

          下面是android客户端测试

----------------------------------------------------------------------------------------------------------

1、activity后台代码:

package com.example.fileupclient;



import java.io.File;

import java.io.OutputStream;

import java.io.PushbackInputStream;

import java.io.RandomAccessFile;

import java.net.Socket;



import android.app.Activity;

import android.os.Bundle;

import android.os.Environment;

import android.os.Handler;

import android.os.Message;

import android.view.Menu;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.ProgressBar;

import android.widget.TextView;

import android.widget.Toast;



import com.example.service.UploadLogService;

import com.example.util.StreamTool;



public class MainActivity extends Activity {

    private EditText filenameText;



    private TextView resultView;



    private ProgressBar uploadbar;



    private UploadLogService service;



    private Handler handler = new Handler() {

        @Override

        public void handleMessage(Message msg) {

            uploadbar.setProgress(msg.getData().getInt("length"));

            float num = (float) uploadbar.getProgress()

                    / (float) uploadbar.getMax();

            int result = (int) (num * 100);

            resultView.setText(result + "%");

            if (uploadbar.getProgress() == uploadbar.getMax()) {

                Toast.makeText(MainActivity.this, R.string.success, 1).show();

            }

        }

    };



    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        service = new UploadLogService(this);

        filenameText = (EditText) findViewById(R.id.filename);

        resultView = (TextView) findViewById(R.id.result);

        uploadbar = (ProgressBar) findViewById(R.id.uploadbar);

        Button button = (Button) findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {

                String filename = filenameText.getText().toString();

                if (Environment.getExternalStorageState().equals(

                        Environment.MEDIA_MOUNTED)) {

                    File file = new File(Environment

                            .getExternalStorageDirectory(), filename);

                    if (file.exists()) {

                        uploadbar.setMax((int) file.length());

                        uploadFile(file);

                    } else {

                        Toast.makeText(MainActivity.this, R.string.notexsit,

                                Toast.LENGTH_LONG).show();

                    }

                } else {

                    Toast.makeText(MainActivity.this, R.string.sdcarderror,

                            Toast.LENGTH_LONG).show();

                }

            }

        });

    }



    private void uploadFile(final File file) {

        new Thread(new Runnable() {

            public void run() {

                try {

                    String sourceid = service.getBindId(file);

                    Socket socket = new Socket("192.168.8.101", 7788);

                    OutputStream outStream = socket.getOutputStream();

                    String head = "Content-Length=" + file.length()

                            + ";filename=" + file.getName() + ";sourceid="

                            + (sourceid != null ? sourceid : "") + "\r\n";

                    outStream.write(head.getBytes());

                    PushbackInputStream inStream = new PushbackInputStream(

                            socket.getInputStream());

                    String response = StreamTool.readLine(inStream);

                    String[] items = response.split(";");

                    String responseSourceid = items[0].substring(items[0]

                            .indexOf("=") + 1);

                    String position = items[1].substring(items[1].indexOf("=") + 1);

                    if (sourceid == null) {

                        // 如果是第一次上传文件,在数据库中不存在该文件所绑定的资源id

                        service.save(responseSourceid, file);

                    }

                    RandomAccessFile fileOutStream = new RandomAccessFile(file,

                            "r");

                    fileOutStream.seek(Integer.valueOf(position));

                    byte[] buffer = new byte[1024];

                    int len = -1;

                    int length = Integer.valueOf(position);

                    while ((len = fileOutStream.read(buffer)) != -1) {

                        outStream.write(buffer, 0, len);

                        length += len;// 累加已经上传的数据长度

                        Message msg = new Message();

                        msg.getData().putInt("length", length);

                        handler.sendMessage(msg);

                    }

                    if (length == file.length())

                        service.delete(file);

                    fileOutStream.close();

                    outStream.close();

                    inStream.close();

                    socket.close();

                } catch (Exception e) {

                    Toast.makeText(MainActivity.this, R.string.error, Toast.LENGTH_LONG).show();

                }

            }

        }).start();

    }



    @Override

    public boolean onCreateOptionsMenu(Menu menu) {

        getMenuInflater().inflate(R.menu.main, menu);

        return true;

    }

}

2、业务代码:

package com.example.service;



import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;



public class DBOpenHelper extends SQLiteOpenHelper {



    public DBOpenHelper(Context context) {

        super(context, "itcast.db", null, 1);

    }



    @Override

    public void onCreate(SQLiteDatabase db) {

        db.execSQL("CREATE TABLE IF NOT EXISTS uploadlog (_id integer primary key autoincrement, path varchar(20), sourceid varchar(20))");

    }



    @Override

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    



    }



}
View Code
package com.example.service;



import java.io.File;



import android.content.Context;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;



public class UploadLogService {

    private DBOpenHelper dbOpenHelper;



    public UploadLogService(Context context) {

        dbOpenHelper = new DBOpenHelper(context);

    }



    public String getBindId(File file) {

        SQLiteDatabase db = dbOpenHelper.getReadableDatabase();

        Cursor cursor = db.rawQuery(

                "select sourceid from uploadlog where path=?",

                new String[] { file.getAbsolutePath() });

        if (cursor.moveToFirst()) {

            return cursor.getString(0);

        }

        return null;

    }



    public void save(String sourceid, File file) {

        SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

        db.execSQL("insert into uploadlog(path,sourceid) values(?,?)",

                new Object[] { file.getAbsolutePath(), sourceid });

    }



    public void delete(File file) {

        SQLiteDatabase db = dbOpenHelper.getWritableDatabase();

        db.execSQL("delete from uploadlog where path=?",

                new Object[] { file.getAbsolutePath() });

    }

}
View Code

3、布局界面:

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView  

    android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

    android:text="@string/filename"

    />

    

    <EditText  

    android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

    android:text="5.jpg"

    android:id="@+id/filename"

    />

    

   <Button  

   android:layout_width="wrap_content" 

   android:layout_height="wrap_content" 

   android:text="@string/button"

   android:id="@+id/button"

   />

   

<ProgressBar 

   android:layout_width="fill_parent" 

   android:layout_height="20px"

   style="?android:attr/progressBarStyleHorizontal"

   android:id="@+id/uploadbar"

   /> 

<TextView  

   android:layout_width="fill_parent" 

   android:layout_height="wrap_content" 

   android:gravity="center"

   android:id="@+id/result"

   />    

</LinearLayout>

 

你可能感兴趣的:(Android学习)