Android中SD卡内容读取和简易FTP文件上传(番外)

摘要:
本周公司有很多事情。本周将要分享的关于MediaPlayer多媒体应用程序技术的原始安排需要演唱。为了不穿女装,这项关于Android中SD卡处理和FTP上传功能的技术分享内容是一个外国故事。有些人可能会问,在Android中读SD卡内容有什么好写的。互联网上有很多关于这个领域的内容。环境getExternalStorageDirectory()可以动态获取每个Android设备中外部SD存储卡的位置。Android FTP文件上传:有时,我们在手机上获取一些数据,然后想使用Android App一键将其上传到指定网络的FTP服务器,以便其他人下载最新数据。

  大家好,又是一周一次的拔旗时间。本周公司事情较多,原本安排的关于MediaPlayer多媒体应用的技术在本周内分享的事宜要歌啦~ 为了不女装,这次的技术分享内容关于Android中SD卡处理和FTP上传功能,算是一个番外篇(其实我才不告诉你们我是代码没有写完)。So,下面正式开始吧。

Android中SD卡内容读取

         有人可能会问,这有什么好写的,网上有许多这方面的内容。Noop, 只有自己亲自去Coding才会发现一些很神奇的坑点,比如SD卡内的文件内容读取这一个很小的功能点。

         首先,实现这个功能,在mainifest里面加入这句权限:

1 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>

   然后在代码中加入以下这句话:

   Path = Environment.getExternalStorageDirectory().getAbsolutePath()

         用递归算法依次遍历每一个File,OK,思路没错,网上或者书上绝大部分都是建议你这么做的。Environment.getExternalStorageDirectory()可以动态的获取每个Android设备中外置SD存储卡的位置。当我编写完程序进行测试的时候发现,File is null!!!! 当时蒙蔽了,路径不是都能拿到么,怎么new File(path)就会报错呢???

        进行下一步的调查可以FA现,我得到的path是 /storage/emulated/0/, Nexus和Galaxy系列的手机都会进入到这个目录,这个查了下会根据不同的安卓厂商发生改变,目的是隐藏SD卡的路径进行保护。这样就麻烦了,adb shell的访问是进入不了这个目录的。那我怎么能获取到整个路径下的文件呢?

   于是我打开万能的stackoverflow搜索了一下,除了要加上权限之外,还需要判断SD卡是否处于mounted的状态,好,那我加上如下代码:

1  private boolean isSdCardExist() {
2       logcat("state: " + Environment.getExternalStorageState());
3       return Environment.getExternalStorageState().equals(
4               Environment.MEDIA_MOUNTED);
5  }

         但结果令人失望,debug过程中可以发现,代码逻辑依然可以进去走原先的逻辑,也就是说,当前的状态处于加载状态的。

         经过多次尝试,我观察了下Environment这个类,发现一个神奇的方法,名字叫:getRootDirectory(),用来获取SD卡的根目录。发现可以了!!

         整理下之前的思路,介绍部分代码: 获取SD卡路径(这里用File来做)

    public File getSDCardPath(){
        // 不要用Environment.getExternalStorageDirectory().getAbsoluteFile()这个方法
        if (isSdCardExist()) {
            logcat("path is " + Environment.getExternalStorageDirectory().getAbsolutePath());
//            return Environment.getExternalStorageDirectory();
            return Environment.getRootDirectory();
        } else {
            return null;
        }
    }

   进行递归操作,遍历每个文件夹:

    private void getFileName(File[] files) {
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    getFileName(file.listFiles());
                } else {
                    String fileName = file.getName();
                    if (isImageFile(fileName)) {
                        addToImageFileLists(file.getAbsolutePath());
                    } else {
                        continue;
                    }
                }
            }
        } else  {
            logcat("Files is null");
        }
    }

   当然我做的程序内容是读取SD卡上的图片和音乐文件,以上提供一个无法读取SD卡内容的一个解决思路,希望可以帮助到大家。这个奇葩Bug在4.4中就被发现了,Nexus和Galaxy机型就会碰到。

AndroidFTP文件上传:

     有时候,我们在手机上获得到一些数据(通常是一些图片),然后想用安卓App,一键上传到指定网络的ftp服务器,让其他人下载到最新数据。那么以下的程序正是基于此需求进行开发。

         准备工作1:

         到Apache的官网下载commons-net-3.5.jar(我用的时候的最新版本),将此包导入到工程中(详细方法可以参考PS第一条)。

         准备工作2:

         下载一款适合你的FTP服务器工具软件,这里我推荐FTPServer,方便快捷非安利。打开FTPServer后,输入账号名和密码,指定好访问目录,然后把“下载文件”和“上传文件”两个权限开启(否则会有Permission Denied, 别问我为什么知道),点击“启动服务”。

         以上,便做好了前置工作, 开始下一步。

         设计一个配置实体类Config,包含hostname, port, username, passwd 四个参数。在CommonUtil中写入如下核心代码:

 1     public String ftpUpload(UploadConfig config, ArrayList<String> fileLists) {
 2 
 3         FTPClient ftpClient = new FTPClient();
 4         FileInputStream fis;
 5         String returnMessage = "Recived message from ftp";
 6 
 7         try {
 8             logcat("Upload Config" + config.toString());
 9             ftpClient.connect(config.getHostname(), config.getPort());
10             boolean isLogin = ftpClient.login(config.getUsername(), config.getPassword());
11             int replyCode = ftpClient.getReplyCode();
12             logcat("replyCode = " + replyCode);
13             if (isLogin && FTPReply.isPositiveCompletion(replyCode)) {
14                 ftpClient.changeWorkingDirectory("/share");
15                 ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
16                 ftpClient.setBufferSize(1024);
17                 ftpClient.setControlEncoding("UTF-8");
18                 ftpClient.enterLocalPassiveMode();
19 
20                 for (String filepath : fileLists) {
21                     File f = new File(filepath);
22                     fis = new FileInputStream(f);
23                     ftpClient.storeFile(getFileName(filepath), fis);
24                 }
25                 returnMessage = "Update Complite";
26             }
27             else {
28                 returnMessage = "Update Faile";
29             }
30         } catch (NumberFormatException e) {
31             // TODO Auto-generated catch block
32             e.printStackTrace();
33         } catch (SocketException e) {
34             // TODO Auto-generated catch block
35             e.printStackTrace();
36         } catch (IOException e) {
37             // TODO Auto-generated catch block
38             e.printStackTrace();
39         } finally {
40             try {
41                 ftpClient.disconnect();
42             } catch (IOException e) {
43                 // TODO Auto-generated catch block
44                 e.printStackTrace();
45             }
46         }
47         return returnMessage;
48     }

        传入的两个参数,一个是配置信息文件,一个是上传文件绝对路径列表。FTP的连接会有一个ftpClient.getReplyCode()这个方法,可以得知是否与FTPServer进行了通信,当这个replyCode为230表示上传成功。changeWorkingDirectory() 这个方法可以指定FTP共享文件的路径,剩下的就是一些上传方式设定,比如设定为文件二进制流方式,流大小限定1M等。

        在AndroidMenifest中加入:

1     <uses-permission android:name="android.permission.INTERNET"/>
2     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    OK完成了,运行程序,我们发现会有java.net.SocketException: socket failed: EACCES (Permission denied) 报错, 查了下原因,在4.0之后像联网这样的耗时操作需要在另外一个线程中做,不能放在主进程中,因此,添加如下两行代码:

1         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
2         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath().build());

    以上,便实现了FTP上传的主要功能。

PS:

  1 进入AndroidStudio时代,就要用AndroidStudio的方式来进行编译,跟以往Eclipse的操作有一些不同。补充一些小技巧,首先是关于导包,将jar文件放入如下图所示的lib文件夹中,然后在build.gradle中的dependencies里面加入compile files('libs/commons-net-3.5.jar'),这样在编译的时候将jar包一起打包编译就可以了。

  Android中SD卡内容读取和简易FTP文件上传(番外)第1张

免责声明:文章转载自《Android中SD卡内容读取和简易FTP文件上传(番外)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇java(JSP)中几种获取项目路径方式Arcgis Server for JavaScript API之自定义InfoWindow下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android Visibility控件显示和隐藏

Android控件显示和隐藏 visibility   可见(visible) XML文件:android:visibility="visible" Java代码:view.setVisibility(View.VISIBLE); 不可见(invisible) XML文件:android:visibility="invisible" Java代码:vie...

Android实现简单的检测手机自由落体关闭屏幕

实现功能如下:在背景运行app,检测到自由落体状态时,熄灭屏幕,可重复测试。 1. 检测自由落体动作  需要使用到加速度感应器 TYPE_ACCELEROMETER SensorManager mSensorManager; private float mLastX; private float mLastY; private float mLastZ;...

【移动安全高级篇】————4、Android手机一键Root原理分析

一直以来,刷机与Root是Android手机爱好者最热衷的事情。即使国行手机的用户也不惜冒着失去保修的风险对Root手机乐此不疲。就在前天晚上,一年一度的Google I/O大会拉开了帷幕,最新的Android4.1系统成为了大会的热点,经过短短的几个小时后,网上就有人泄露了Jelly Bean的下载地址,再然后就有了Android 4.1带Root的完整...

觅踪2

        昨天的页面设计受到了停滞,今天换了一种形式,之前是直接用按键绘制,现在改为代码操纵,自己的进程缓慢了许多,明天将继续加油 界面代码如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.co...

Node.js及npm详细安装教程

一、使用之前,我们先来掌握3个东西是用来干什么的。 npm: Nodejs下的包管理器。 webpack: 它主要的用途是通过CommonJS的语法把所有浏览器端需要发布的静态资源做相应的准备,比如资源的合并和打包。 vue-cli: 用户生成Vue工程模板。(帮你快速开始一个vue的项目,也就是给你一套vue的结构,包含基础的依赖库,只需要 npm in...

模拟器上安装 Frida (Frida +FRIDA-DEXDump联动)

1.模拟器安装drozer和相关adb 。看上文。 https://www.cnblogs.com/pangya/p/10062860.html 把adb添加到环境变量。 2.模拟器上安卓Firda-server 1.确定模拟器版本,使用adb adb shell getprop ro.product.cpu.abi --查看版本 2.下载frid...