zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    1052 Linked List Sorting (25 分)
    1051 Pop Sequence (25 分)
    1050 String Subtraction (20 分)
    1049 Counting Ones (30 分)
    1048 Find Coins (25 分)
    1047 Student List for Course (25 分)
    1046 Shortest Distance (20 分)
    1045 Favorite Color Stripe (30 分)
    1044 Shopping in Mars (25 分)
    1055 The World's Richest (25 分)
  • 原文地址:https://www.cnblogs.com/lbangel/p/3494717.html
Copyright © 2011-2022 走看看