• 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 + "
    ";
                        // 服务器收到客户端的请求信息后,给客户端返回响应信息: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 '
    ':
                    break loop;
                case '
    ':
                    int c2 = in.read();
                    if ((c2 != '
    ') && (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=
    ";
                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 : "") + "
    ";
                        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>
  • 相关阅读:
    远程访问Linux的常见方式
    GIT的安装与使用
    01_c语言学习之gcc
    车轮——项目 --- 云笔记
    python 基于ubuntu16.04 建立虚拟环境
    利用msfvenom生成木马
    msfvenom参数简介
    kali linux修改更新源及更新
    记通过mysql数据库成功入侵到服务器内部的渗透实战
    UML 几种关系:泛化、关联
  • 原文地址:https://www.cnblogs.com/lbangel/p/3494717.html
Copyright © 2020-2023  润新知