安卓核心技术中级——文件管理与XMLJSON解析

本文详细介绍Android中数据存储方式,包括内部与外部存储的使用,以及XML与JSON数据的解析方法。涵盖权限申请、存储目录选择、文件操作、XML解析机制及JSON解析技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用内部存储器

你可以直接保存文件在设备的内部存储。默认情况下,文件保存在你的应用程序的内部存储,其他应用程序或用户不能访问。当用户卸载你的应用程序中,这些文件被删除。

(一)在内部存储创建并写入读取私有文件
  1. 调用openFileOutput(name,mode())方法,返回一个FileOutputStream,name参数用于指定文件名称,不能包含路径分隔符“/”,如果文件不存在,会自动创建它,创建的文件保存在/data/data/< package name>/files/目录中,model参数指定是使用方式,分别有:

MODE_PRIVATE:私有(创建此文件的应用能够使用,其他应用不能访问),写入会覆盖原来的内容。
MODE_APPEND:私有,在原有内容上增加数据
MODE_WORLD_READABLE,MODE_WORLD_WRITEABLE:可以被其他应用读取或写入(API17版本中已废弃)不建议使用

  1. 调用write方法吧数据写入文件
  2. 调用close方法关闭流

写入私有文件

/**
     * 写入私有文件
     * @param v
     */
    public void writePrivateFileClick(View v){
        try {
            OutputStream out = openFileOutput("ttt.txt", Context.MODE_PRIVATE);
            String info = "劝君更尽一杯酒";
            byte[] bytes = info.getBytes();
            out.write(bytes,0,bytes.length);
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

在这里插入图片描述
读取私有文件

public void readPrivateFileClick(View v){
        try {
            InputStream in = openFileInput("ttt.txt");
            byte[] bytes = new byte[1024];
            StringBuffer sb = new StringBuffer();
            int len = -1;
            while ((len=in.read(bytes))!=-1){
                sb.append(new String(bytes,0,len));
            }
            in.close();
            Toast.makeText(this,sb,Toast.LENGTH_LONG).show();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

在这里插入图片描述

(二)保存内部缓存文件

如果你想缓存一些数据,而不是永久保存,可以使用getCacheDir()打开文件所在的目录,代表内部应用程序应保存临时缓存文件。
当设备的内部存储空间低,Android可以删除这些缓存文件以回收空间。然而,你不应该以来系统来为你清除这些文件。你应该自己维护缓存文件,并保持在一个合理的消耗空间的限制,如1MB。当用户卸载你的应用程序,这些文件被删除。
通过getCacheDir()获取的目录为:/data/data/< package name>/cache

方法作用作用的目录
getFileDir():获取私有文件目录/data/data/< package name>/files
getDir(name,model):创建(或打开已存在的)目录/data/data/< package name>/app_< 文件名>
deleteFile(name):删除私有目录的文件/data/data/< package name>/files
fileList():获取/data/data/< package name>/files目录的文件名数组
public void writePrivateCacheDataClick(View v){
//        String  temp = getCacheDir() + "/temp.tmp";
        try {
            //创建一个缓存的文件
            File temp = File.createTempFile("temp",null,getCacheDir());
            FileOutputStream out = new FileOutputStream(temp);
            PrintStream ps = new PrintStream(out);
            ps.print("朝辞白帝彩云间");
            ps.close();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

使用外部存储器

所有兼容Android的设备都支持一个可共享的“外部存储”,可用来保存文件。这可以使一个可以的的存储设备(比如SD卡)或者一个内部的(不可以的的)存储。保存在外部存储的文件是可读的。并且当用于传输数据的USB大容量存储选项启用时,用户能够在计算机上修改它们。

(一)获取外部存储权限

为了在外部存储读写文件,必须获得
< uses-permission android:name=“android.permission.READ_EXTERNAL_STORAGE”/>
< uses-permission android:name=“android.permission.WRITE_EXTERNAL_STORAGE”/>
的系统权限。
要读也要写权限,可添加
< uses-permission android:name=“android.permission.WRITE_EXTERNAL_STORAGE”/>

(二)检查媒体的可用性

在使用外部存储来保存数据时,我们应该使用getExtetrnalStorageState()来检查当前设备是否存在外部存储设备(SDCard),否则将会发生意外

public void isSDCardClick(View v){
        //判断是否有SDCard
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            Toast.makeText(this,"有SDCard",Toast.LENGTH_SHORT).show();
            if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY)){
                Toast.makeText(this,"SDCard只读",Toast.LENGTH_SHORT).show();
            }
        }else{
            Toast.makeText(this,"没有SDCard",Toast.LENGTH_SHORT).show();
        }
    }

在这里插入图片描述

(三)访问SDCard路径

以前的Android(4.1以前的版本)中,SDcard路径通过“/sdcard”或者“/mnt/sdcard”来表示,
而在Jelly Bean系统中修改为了“/storage/sdcard0”,以后肯还会有多个SDCard的情况。
目前为了保持和之前代码的兼容,sdcard路径做了link映射。
为了使代码更加见状并能兼容以后的Android版本和新设备,请通过Environment.getExternalStorageDirectory().getPath()来获取sdcard路径
可以使用Environment.getExternalStoragePublicDirectory(String type)函数,返回特定类型的目录:

类型
DIRECTORY_ALARMS警报的临时
DIRECTORY_DCIM相机拍摄的图片和视频位置
DIRECTORY_DOWNLOADS下载文件保存的位置
DIRECTORY_MOVIES电影保存的位置
DIRECTORY_MUSIC音乐保存的位置
DIRECTORY_NOTIFICATIONS通知音保存的位置
DIRECTORY_PICTURES下载的图片保存的位置
DIRECTORY_PODCASTS永远忽保存podcast(博客)的音频文件
DIRECTORY_RINGTONES保存铃声的位置
(四)Saving files that are app-private(保存文件私有化)4.4版本后可用

为了文件的保密性,你必须保证自己的文件不让其他app读取,你可以使用getExternalFilesDir(type),type为null为默认。
再次注意,getExternalFilesDir()这个方法,不一定总能访问sd卡中的信息。
如果设备资深已经有了一部分内部存储当做外部存储,那这个方法就不能访问到sd。

当用户卸载应用程序时,Android系统删除以下:
(1)你保存在内部存储的所有文件
(2)所有使用本应用外部存储的私有文件

public void writeSDcardPrivateFileClick(View v){
        File file = getExternalFilesDir(null);
        if(file!=null){
            FileOutputStream out = null;
            try {
                out = new FileOutputStream(file+"/yyy.txt");
                PrintStream ps = new PrintStream(out);
                ps.print("渭城朝雨浥轻尘");
                ps.close();
                out.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
(五)外部存储保存私有缓存文件

通过Context.getExternalFilesDir()可以获取到 SDCard/Android/data/你的应用的包名/files/目录 ,一般存放长时间保存的数据,
通过Context.getExternalCacheDir()可以获取到 SDCard/Android/data/你的应用的包名/cache/ 目录,一般存放临时缓存数据

如果使用上面的方法,在应用被用户卸载后, SDCard/Android/data/你的应用的包名/ 这个目录下单所有文件都会被删除,不会留下垃圾文件,而且上面二个目录分别对应 设置->应用->应用详情里面的“清除数据”与“清除缓存”选项

//写入SDCARD 私有缓存文件
    public void writeSDcardPrivateCacheFileClick(View v){
        try {
            File temp = File.createTempFile("xxx",null,getExternalCacheDir());
            if(temp!=null){
                FileOutputStream out = new FileOutputStream(temp);
                PrintStream ps = new PrintStream(out);
                ps.print("渭城朝雨浥轻尘");
                ps.close();
                out.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

XML解析

(一)XML解析的两种机制

xml是一种常用的存储数据方式,在Android平台中内部很多地方使用了xml存储,比如轻量级的SharedPreference类的存储就是使用了xml文件。
xml解析主要有三张方式,SAX(Simple API for XML),DOM(Document Object Model)和Android附带的PULL解析器解析XML文件。
常规PC开发我们使用DOM,淡一些性能敏感的数据库或手机上还是采用SAX方式,SAX读取是单向的,优点是不占内存空间,解析属性方便,但缺点就是对于套嵌多个分支来说处理不是很方便,而DOM方式会把整个XML文件加载到内存中去,优点是可以任意读取节点,但缺点是会消耗内存,而PULL常常用在移动设备对于节点处理比较好,类似SAX方式,同样很节省内存。

(二)PULL解析

Pull解析器的运行方式与SAX相似。它提供了类似的事件,如开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.next()方法可以获取下一个Text类型元素的值。

<!--创建xml文件-->
<codingke>
<person personid="1">
	<name>ttt</name>
	<age>18</age>
	<sex></sex>
	<tel>138456784569</tel>
</person>
<person personid="2">
	<name>yyy</name>
	<age>15</age>
	<sex></sex>
	<tel>13632145875</tel>
</person>
</codingke>

<!--同时要创建一个Person类-->
public void pullParserClick(View v){
        ArrayList<Person> list = parser();
        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }
    }

    private ArrayList<Person> parser(){

        ArrayList<Person> list = new ArrayList<>();
        Person p = null;

        //创建PULL解析器
        XmlPullParser pull = Xml.newPullParser();
//        StringReader sr = new StringReader(xml);
        InputStream in = getResources().openRawResource(R.raw.person);
        try {
            //设置要解析的文件流
            pull.setInput(in,"UTF-8");
            //获取当前事件类型
            int eventType = pull.getEventType();

            while (eventType!=XmlPullParser.END_DOCUMENT){

                switch (eventType){
                    case XmlPullParser.START_TAG:
                        String tag = pull.getName();
                        if("person".equals(tag)){
                            p = new Person();
                            p.personid = Integer.parseInt(pull.getAttributeValue(null,"personid"));
                        }else if ("name".equals(tag)){
                            p.name = pull.nextText();
                        }else if ("age".equals(tag)){
                            p.age = Integer.parseInt(pull.nextText());
                        }else if ("sex".equals(tag)){
                            p.sex = pull.nextText();
                        }else if("tel".equals(tag)){
                            p.tel = pull.nextText();
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        if ("person".equals(pull.getName())){
                            list.add(p);
                        }
                        break;
                }

                //获取下一个时间类型
                eventType = pull.next();
            }
        } catch (XmlPullParserException | IOException e) {
            e.printStackTrace();
        }
        return list;
    }

在这里插入图片描述

JSON解析

(一)什么是JSON

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。
JSON数据格式的特点
JSON建构于两种结构:
1、“名称/值”对的集合:{“firstName”:“Li”,“lastName”:“Si”}
2、值的有序列表(数组):{“user”:[
{“firstName”:“Li”,“lastName”:“Si”,“email”:“123456@qq.com”},
{“firstName”:“Zhang”,“lastName”:“San”,“email”:“789456@qq.com”}]}

(二)使用JsonReader解析JSON数据

JSONReader是Android.util包下一个用于解析JSON的工具类
JsonReader reader = new JsonReader(new StringReader(jsonData))

public void jsonReaderClick(View v){
        ArrayList<Worker> list = jsonReader();
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
    private ArrayList<Worker> jsonReader(){
//        String json = "{\"user\":[{\"firstName\":\"Li\",\"lastName\":\"Si\",\"email\":\"123456@qq.com\"}," +
//                "{\"firstName\":\"Zhang\",\"lastName\":\"San\",\"email\":\"789456@qq.com\"}]}";
        ArrayList<Worker> list = new ArrayList<>();

        Reader r = new InputStreamReader(getResources().openRawResource(R.raw.worker));
        JsonReader jr = new JsonReader(r);

        try {
            jr.beginObject();
            if(jr.hasNext()){
                if ("user".equals(jr.nextName())){
                    jr.beginArray();//开始解析数组
                    while (jr.hasNext()){
                        Worker w = new Worker();
                        jr.beginObject();//开始解析对象
                        while (jr.hasNext()){
                            String name = jr.nextName();
                            if("firstName".equals(name)){
                                w.firstName = jr.nextString();
                            }else if ("lastName".equals(name)){
                                w.lastName = jr.nextString();
                            }else if("email".equals(name)){
                                w.email = jr.nextString();
                            }
                        }
                        jr.endObject();//结束对象的解析
                        list.add(w);
                    }
                    jr.endArray();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

json数据:

{"user":
  [{"firstName":"Li","lastName":"Si","email":"123456@qq.com"},
  {"firstName":"Zhang","lastName":"San","email":"789456@qq.com"}]
}

在这里插入图片描述

(三)生成一组JSON数据
public void createJSONClick(View v){

        ArrayList<Worker> list = new ArrayList<>();
        Worker w1 = new Worker();
        w1.firstName = "Wang";
        w1.lastName = "Wu";
        w1.email = "456123@qq.com";
        Worker w2 = new Worker();
        w2.firstName = "Zhao";
        w2.lastName = "Liu";
        w2.email = "741852@qq.com";

        list.add(w1);
        list.add(w2);

        JSONObject json = new JSONObject();
        JSONArray array = new JSONArray();

        try {
            for (int i=0;i<list.size();i++){
                Worker w = list.get(i);
                JSONObject obj = new JSONObject();

                obj.put("firstName",w.firstName);
                obj.put("lastName",w.lastName);
                obj.put("email",w.email);
                array.put(obj);
            }
            json.put("worker",array);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        //测试
        System.out.println(json.toString());
    }

在这里插入图片描述

(四)GSON的使用
//使用GSON解析JSON
    public void gsonParseJsonClick(View v){
        Gson gson = new Gson();
        Reader r = new InputStreamReader(getResources().openRawResource(R.raw.worker));
        Type type = new TypeToken<ArrayList<Worker>>(){}.getType();
        ArrayList<Worker> list = gson.fromJson(r,type);
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }

//    class MyTypeToken extends TypeToken<ArrayList<Worker>>{}

//GSON生成JSON
    public void gsonToJsonClick(View v){
        ArrayList<Worker> list = new ArrayList<>();
        Worker w1 = new Worker();
        w1.firstName = "Wang";
        w1.lastName = "Wu";
        w1.email = "456123@qq.com";
        Worker w2 = new Worker();
        w2.firstName = "Zhao";
        w2.lastName = "Liu";
        w2.email = "741852@qq.com";

        list.add(w1);
        list.add(w2);

        Gson gson = new Gson();
        Type type = new TypeToken<ArrayList<Worker>>(){}.getType();
        String json = gson.toJson(list,type);
        System.out.println(json);
    }

json数据:

[{"firstName":"Li","lastName":"Si","email":"123456@qq.com"},
  {"firstName":"Zhang","lastName":"San","email":"789456@qq.com"}]

在这里插入图片描述

(五)JSON vs XML

1、JSON和XML的数据可读性基本相同
2、JSON和XML同样拥有丰富的解析手段
3、JSON相对于XML来讲,数据的体积小
4、JSON与JavaScript的交互更加方便
5、JSON对数据的描述性比XML差
6、JSON的速度要远远快于XML

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值