IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Android网络编程之文件上传/下载 -> 正文阅读

[网络协议]Android网络编程之文件上传/下载

这个任务是安卓课程的作业,任务分为两部分,一是搭建web服务器编写相应的处理逻辑,二是安卓客户端发送和接受相应的报文。

下载

整体思路是先读取要传输的文件,随后以缓冲流的形式写在相应的http报文实体体也就是正文中,接收方将报文以缓冲流读取出来,写在相应的文件位置。

先写web服务器,这里为了避免写一堆配置文档直接用spring boot框架。

这个Controller注解作用是标记这是一个控制器类,框架中的分发处理器会扫描带有该注解的类标记其为控制器,这里的控制器就和安卓的模型视图控制器模型类似。

相应的,RequestMapping注解用来映射请求地址,对该地址发出请求的报文会交给带有这个注解的方法处理。

这里用c盘下面的一个叫img.jpg的文件做例子,用文件字节流读取这个文件内容,一般情况下Java的io操作需要用缓冲流进行读写,否则会频繁对源文件进行io操作降低速度,因此再用缓冲流包裹这个字节流?。

?随后从响应报文中拿到输出流,再用缓冲流做包裹,因为之前使用的都是字节流,这里开一个字节数组作为缓冲,将输入流的数据写到输出流里面,还需要一个整型变量len,用来标记写了多少字节的数据。

最后关闭流,只需要关闭最外层的流就可以了。

还需要设置报文头,用来标记这是一个文件需要下载,而不是直接读取并且展示。

测试一下,在浏览器输入http://127.0.0.1:8080/down即可下载,spring boot默认使用的web容器是tomcat,其占用的端口号是8080。

接下来做安卓部分

安卓发起http网络请求的时候,官方提供了HttpURLConnection,不过它的io操作比较繁琐,这里用一个叫OKhttp的第三方库来进行网络请求,第三方库需要导包。

顺便把权限也申请了,得用四个权限,访问网络,读写文件和不经过通知直接读文件。读写外存属于危险权限需要运行时申请。

?这里读写文件属于危险权限,需要申请运行时权限才能进行,不过我降低了Android的版本,直接在这里申请就行了。

做一个download按钮,随后设置它的单击事件,这个setonclickLinstener方法本质就是传入了一个onClick接口进去,这个接口是一个函数式接口,因此这里直接用匿名函数。

接下来设置请求url,这里的地址需要注意一下,因为as的安卓模拟器本质上就是一个虚拟机,127.0.0.1是它自身的环回地址,而web服务器搭建在了这台电脑上,所以需要拿到这台电脑在局域网内的实际地址,ipconfig即可获得。

可以做一个EditView来让用户输入请求地址,不过这里避免麻烦就直接硬编码在程序里面地址了。

?接下来用okhttp构建请求,将url传进去然后创建,随后再用这个库提供的客户端类发送请求,

安卓的网络请求是要放在子线程里面做的,因为网络请求会阻塞所在的进程等待响应,如果用谷歌提供的请求方法,还需要在开启子线程或者使用异步任务类来处理,这里也是okhttp的优势之一,提供了封装好的异步请求方法,会将任务执行自动放在子线程中,不过需要传入回调函数,就是这个名字就叫回调的接口就行,第一个方法是请求失败的回调,第二个是成功的。

失败的写个日志就行,成功的需要进行io操作将服务器相应的文件缓冲流读取下来写到相应的位置。

?先拿到文件将要存储的位置,等下去文档管理器查看

?

public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {

                    String path= Environment.getExternalStorageDirectory().getAbsolutePath()+"/download";
                    File file=new File(path,"img.jpg");
                    file.createNewFile();
                    FileOutputStream fis=new FileOutputStream(file);
                    BufferedOutputStream bos=new BufferedOutputStream(fis);

                    InputStream is=response.body().byteStream();
                    BufferedInputStream bis=new BufferedInputStream(is);
                    byte[] buff=new byte[2048];
                    int len=0;
                    while((len=bis.read(buff))!=-1){
                        fis.write(buff,0,len);
                    }
                    bis.close();
                    bos.close();

                }

这里从响应报文中拿到输入缓冲流,用同样的方法写在文件里面就行了,如果需要检测下载进度的话,可以从响应的报文头中拿到文件大小,计数已经下载的字节数,更新相应的ui即可。

上传

上传属于镜像操作,我直接贴代码了

@Controller
public class in {
    @RequestMapping("/in")
    public void in(HttpServletRequest request,
                     HttpServletResponse response) throws IOException {
        System.out.println(request.getHeaderNames());
        File file=new File("in.jpg");
        file.createNewFile();
        FileOutputStream fos=new FileOutputStream(file);
        BufferedOutputStream bos=new BufferedOutputStream(fos);
        InputStream inputStream=request.getInputStream();
        byte[] buff=new byte[2048];
        int len=0;
        while((len=inputStream.read(buff))!=-1){
            bos.write(buff,0,len);
        }
        System.out.println(file.getAbsolutePath());
    }
}
public class MainActivity extends AppCompatActivity {
    public static final MediaType MEDIA_TYPE_MARKDOWN
            = MediaType.parse("text/x-markdown; charset=utf-8");
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        verifyStoragePermissions(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.upload).setOnClickListener(v->{
            OkHttpClient client = new OkHttpClient();
            File file=new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/download","img.jpg");
            RequestBody requestBody=new RequestBody() {

                @Nullable
                @Override
                public MediaType contentType() {
                    return MEDIA_TYPE_MARKDOWN;
                }
                @Override
                public void writeTo(@NonNull BufferedSink bufferedSink) throws IOException {
                    OutputStream os=bufferedSink.outputStream();
                    FileInputStream fis=new FileInputStream(file);
                    BufferedInputStream bis=new BufferedInputStream(fis);
                    byte[] buff=new byte[2048];
                    int len=0;
                    while((len=bis.read(buff))!=-1){
                        os.write(buff,0,len);
                    }
                }
            };
            Request request=new Request.Builder()
                    .url("http://192.168.1.102:8080/in")
                    .post(requestBody)
                    .build();
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {
                    Log.d("mes", "onFailure: error");
                    Log.d("mes", "onFailure: "+e.getMessage());
                }

                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                    Log.d("mes", "onResponse: send");
                }
            });
        });

    }
    //先定义
    private static final int REQUEST_EXTERNAL_STORAGE = 1;

    private static String[] PERMISSIONS_STORAGE = {
            "android.permission.READ_EXTERNAL_STORAGE",
            "android.permission.WRITE_EXTERNAL_STORAGE" };

    //然后通过一个函数来申请
    public static void verifyStoragePermissions(Activity activity) {
        try {
            //检测是否有写的权限
            int permission = ActivityCompat.checkSelfPermission(activity,
                    "android.permission.WRITE_EXTERNAL_STORAGE");
            if (permission != PackageManager.PERMISSION_GRANTED) {
                // 没有写的权限,去申请写的权限,会弹出对话框
                ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-11-16 19:11:36  更:2021-11-16 19:11:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:28:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码