Android文件操作,数据读写,数据存储,存储路径,一篇全部搞定

       得学会写博客,以前是觉得逼格,现在发现是为了总结自己的所学,项目做完了不代表会了,东西学完了不代表懂了。总结之后不会、不懂也无所谓,自己的接口调了就行了。当然了,啪啦啪啦,写完做完还不会的,我也不想说什么。看完这篇不会,下次就直接调我的接口吧。代码已经上传到 github上面去了,网址:https://github.com/KEYD111/AndroidFileOperation

  经过ARM板-RK3288和小米手机的测试。亲测可以使用。

       博客中写的欠缺的地方,无所谓,直接去看代码,里面的注释很详细。程序员看代码就行了,每个函数全部封装好了,废话不多话。博客很长,大家慢慢看,看完一劳永逸,以后直接调我的函数就行了,但是讲的很详细,全部都是对比的来实现,方便大家的阅读。

总体:大家依据直接饿的需求去看

      一、先大体的介绍一下理论部分,这里还是很重要的。

      二、常见的存储数据的方式

       三、IO 文件流的读取方式

       四、sharedPreference 存储

       五、SQLite的存储方式

       六、assets的存储方式 

       七、res的存储方式

       八、raw的存储方式

       一、先大体的介绍一下理论部分,这里还是很重要的。

      安卓存储文件、数据的地方: RAM、ROM、内存(内部存储器)、APP程序里面(Assets,raw,res),SD卡(早期的安卓的可以插卡,现在的不支持了,但是有些 arm板 嵌入式方向的还是带卡槽的),总体上来说就是这些了,网络。

      接下来再细分:

       1、RAM、ROM 这些东西我们就别碰了,不然一大堆问题,Environment.getRootDirectory()  需要获取root权限,不合适

      2、内存和SD卡  大家得理解  Environment.getExternalStorageState()  代表的是什么意思,不是插卡的SD卡,而是说你买了开发板、手机,厂家送你的存储地方(直接你得让他送你哈)。  这部分作为主要的存储路径,小数据和大数据都适用。

      3、SD卡,黑色那张卡,老古董,现在手机都没有了,不建议大家使用,非要去使用,我也写了相关的代码(根据机型,不通用,切记,不能用不能怪我,这个只提供思路)。

     4、网络,请求自己的服务器,读取数据,URI的方式,httpClient    post 和 get 两种请求数据的方式

      存储的地方就这么多了。

     二、常见的存储数据的方式

      1、sharedPreference,  将数据保存为 xml 的格式,

      2、数据库  将SQLite的方式

      3、contentprovider  APP之间交互数据的方式。(这里不讲,没有用过,没有发言权)

      4、文件的读取(IO流) 和 Java的操作类似。

      5、Android内部的存储 assets,res, raw,  三者的区别

           assets 和 raw 是不会随着 APP进行编译, res下的文件会随着app一起编译,每次 shift+alt+x 都要等好久

           assets目录下可以创建子文件夹     raw 不可以

    三、IO 文件流的读取方式

       IO文件流最常见了,你得知道文件的存储路径才可以看代码中:

/**
 * @Function: 常见的文件路径的读取只是简单的介绍一下(没什么用)
 * 根据自己的需要,根据实际的要求来进行操作。私有 和 APP绑定  生成文件
 * 简单的测试几个路径的例子
 * @Return:
 */
private void getFilePath(String definedPath) {
    String a = Environment.getDataDirectory().toString();
    String b = getFilesDir().getAbsolutePath();
    String c = getCacheDir().getAbsolutePath();
    String d = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getPath();
    String e = Environment.getExternalStorageDirectory().getPath();
    String f = getExternalFilesDir("Documents").getPath();
    Log.i(LOG_Info + "a: ", "Environment.getDataDirectory().toString():-----" + a);
    Log.i(LOG_Info + "b: ", "getFilesDir().getAbsolutePath():----- " + b);
    Log.i(LOG_Info + "c: ", "getCacheDir().getAbsolutePath():----- " + c);
    Log.i(LOG_Info + "d: ", "Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getPath():----- " + d);
    Log.i(LOG_Info + "e: ", "Environment.getExternalStorageDirectory().getPath():----- " + e);
    Log.i(LOG_Info + "f: ", "getExternalFilesDir(\"Documents\").getPath():----- " + f);
}

常用的路径存储方式:大家看看就行了 我着重讲三种的存储方式,最有用。

/**
 * 会了这常见的三种方式足够了
 * 一种是跟 app 绑定在一起的 数据库SQLite操作的时候需要使用  跟随着APP的生命周期而变换 apk私有目录 不会导致数据残留  卸载就没了  但是重新烧录不会改变数据库   数据库操作(亲测)
 * 一种是存在内存当中的,会一直存在  图片保存 数据库操作 (亲测)Environment 方式获取路径 公共目录
 * 还有一种就是挂载的SD卡 这类就比较烦  而且是特别烦,除非必须使用,一般不推荐使用 容易出错  现在的手机不支持外部SD卡了, 保存图片 亲测可以用
 */
/**
 * @param FileDirName:你想创建的文件夹的名字
 * @Function: 测试内部存储
 * @attention: 数据跟APP绑定 app卸载后就没有了
 * 生成的文件 存储在 NANDFlash --> Android --> data   里面是的 app的包名 com.XXX.......---> files 这种格式 找到对应的就可以了
 * @Return: 返回文件夹的路径,可以在文件夹下继续创建文件
 */
private String TestFilePathApkPrivate(Context context, String FileDirName) {
    //不需要挂载测试,因为 app 都可以装 为什么 会没有数据
    String filedirpath = context.getExternalFilesDir(FileDirName).getPath();  //文件夹
    File fileDir = new File(filedirpath);                   //创建文件夹
    if (fileDir.exists()) {    //判断文件是否存在  很重要  别每次都会去覆盖数据
        fileDir.setWritable(true);
        Log.i(LOG_Info, "文件夹已经存在    TestFilePathInternalData()");
    } else {
        try {
            fileDir.mkdir();
            Log.i(LOG_Info, "文件夹创建成功    TestFilePathExternalData()");
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(LOG_Error, "文件夹创建错误   TestFilePathExternalData()" + e.getMessage());
        }
    }
    return filedirpath;
}

上面的这种方式  数据会随着的app的生命周期而变换,卸载就没有了

/**
 * @param filesname: 文件夹的名字
 * @Function: 测试内部存储  在公共存储目录下新建文件夹
 * @attention: 一直存在 app卸载后依然存在 存储在文件的公共目录下的 比如说 打开 NANDFlash 会出现 Movies Pictures Downlaod 等等
 * @Return:
 */
private String TestFilePathExternalData(String filesname) {
    String pulicfileDir = null;
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { //测试是否挂载SD卡,并且是否加载了权限
        pulicfileDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getPath();
        File filedir = new File(pulicfileDir, filesname);
        if (filedir.exists()) {
            Log.i(LOG_Info, "文件夹已经存在     TestFilePathExternalData()");
        } else {
            try {
                filedir.mkdir();
                Log.i(LOG_Info, "文件夹创建成功    TestFilePathExternalData()");
            } catch (Exception e) {
                e.printStackTrace();
                Log.i(LOG_Error, "文件夹创建错误   TestFilePathExternalData()" + e.getMessage());
            }
        }
    } else
        Log.i(LOG_Error, "没有挂载SD卡或是没有打开权限");
    return (pulicfileDir + File.separator + filesname);   //返回的是文件的目录
}

上面的这种方式   数据不会随着的app的生命周期而变换,一直会存在,只能去手动删除

/**
 * @Function: 外部SD卡
 * @attention: 注意getExternal 和 SD 卡是不一样的 这种骚气的写法,在我的开发板上测试可以,但是强烈不推荐大家去使用
 * @Return:
 */
private void TestFilePathSDCard() {
    File fileDir1 = new File("/mnt/sdcard/SQLite1");    //这是内部挂载的SD卡  和 公共的是同级目录,无法靠代码获取,经验
    File fileDir2 = new File("/mnt/sdcard2/SQLite2");    //这是外部插卡式的SD卡,ARM板上支持,绝大部分手机已经凉了
    fileDir1.mkdir();
    fileDir2.mkdir();
}

上面的这种方式 数据存储在 黑色的插卡的SD卡中,气自求多福,不同的手机的路径是不一样的。而且无法用代码获取
你非要用 用手机找到 那个目录——————>找到属性--->查看路径 ----> 将路径复制到 代码去使用,,,理论上是可以的,我试过。

          IO流文件数据的读写操作 基本上常用的方法都有了

/**
 * @param content:    要写的内容
 * @param filedirname 文件夹的名字
 * @param filename:   文件的名字
 * @param mode:       以什么方式往里面去写 0 1 2 3
 * @param ways:       两种方式 Buffer RandomAccessFile  Print  0 1 2
 * @Function: 将content写到指定的文件的指定的目录下去
 * @Return:
 */
private void WriteDataToStorage(String content, String filedirname, String filename, int mode, int ways) {
    String FileName = filedirname + File.separator + filename;   //拼接字符串  文件的存储路径
    File subfile = new File(FileName);  //文件夹路径和文件路径   判断文件是否存在
    if (subfile.exists()) {
        subfile.setWritable(true);
        boolean readable = subfile.canRead();
        boolean writeable = subfile.canWrite();
        Log.i(LOG_Info, "文件创建成功" + "readable:" + readable + " writeable:" + writeable);
    } else {
        try {
            subfile.createNewFile();
        } catch (IOException e) {
            Log.i(LOG_Error, "文件创建出错  " + e.getMessage());
            e.printStackTrace();
        }
    }
    int Context_Mode = mode;
    int Ways = ways;
    if (Context_Mode == 0) {
        Context_Mode = Context.MODE_PRIVATE;  //该文件只能被当前程序读写。
    } else if (Context_Mode == 1) {
        Context_Mode = Context.MODE_APPEND;   //以追加方式打开该文件,应用程序可以向该文件中追加内容。
    } else if (Context_Mode == 2) {
        Context_Mode = Context.MODE_WORLD_READABLE;  //该文件的内容可以被其他应用程序读取。
    } else if (Context_Mode == 3) {
        Context_Mode = Context.MODE_WORLD_WRITEABLE;  //该文件的内容可由其他程序读、写。
    } else {
        Context_Mode = Context.MODE_WORLD_WRITEABLE;  //省的烦   反正都可以读
    }
    if (Ways == 0) {
        Log.i(LOG_Info, "BufferWriter");
        FileOutputStream fileOutputStream = null;
        BufferedWriter bufferedWriter = null;
        OutputStreamWriter outputStreamWriter = null;
        try {
            //fileOutputStream = openFileOutput(FileName, Context_Mode);  contains a path separator 报错
            fileOutputStream = new FileOutputStream(subfile);
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileOutputStream, "utf-8"));  //解决输入中文的问题
            bufferedWriter.write(content + "\t");
            bufferedWriter.flush();
            bufferedWriter.close();
            //outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8");   //两种方式都可以
            //outputStreamWriter.write(content);
            //outputStreamWriter.flush();
            //outputStreamWriter.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(LOG_Error, "写入数据出错 " + e.getMessage());
        } finally {
            if (bufferedWriter != null) {
                try {
                    bufferedWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    } else if (Ways == 1) {
        Log.i(LOG_Info, "RandomAccessFile");
        try {
            RandomAccessFile raf = new RandomAccessFile(subfile, "rw");
            raf.seek(subfile.length());
            raf.write(content.getBytes());
            raf.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(LOG_Error, "写入数据出错 " + e.getMessage());
        }
    } else if (Ways == 2) {
        Log.i(LOG_Info, "Printer");
        try {
            FileOutputStream fileoutputStream = new FileOutputStream(subfile);
            //openFileOutput("text2", Context.MODE_PRIVATE);
            PrintStream ps = new PrintStream(fileoutputStream);
            ps.print(content + "\t");
            ps.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    } else
        Ways = 0;
}
/**
 * @param fileDirName: 文件夹的路径
 * @Function: 列出文件夹下所有文件的名字
 * @Return:
 */
private File[] ListFileDirName(String fileDirName) {
    File fileDir = new File(fileDirName);
    File[] files = new File[0];
    if (fileDir.isDirectory()) {
        files = fileDir.listFiles();
    }
    for (File a : files) {   //可以利用适配器做成界面  完成为了玩没意思
        Log.i(LOG_Info, a.toString());
    }
    return files;
  /*  /storage/emulated/0/Documents/SQLite/abcd.txt  手机的测试结果
      /mnt/internal_sd/Documents/SQLite/abcd.txt ARM板的测试结果*/
}
/**
 * @param fileDirName:文件夹目录
 * @param fileName:文件名字
 * @param ways:读取文件的方式
 * @Function: 从存储路径中读出数据
 * @Return:
 */
private void ReadDataFromStorage(String fileDirName, String fileName, int ways) throws IOException {
    File file = new File(fileDirName, fileName);
    int Ways = ways;
    if (Ways == 0) {
        Log.i(LOG_Info, "FileInputStream");
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            byte[] bytes = new byte[fileInputStream.available()];
            fileInputStream.read(bytes);
            String result = new String(bytes);
            Log.i(LOG_Info, "读取的内容是:" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else if (Ways == 1) {   //最好使用 Buffer 缓冲流,安全机制 大量的文件
        Log.i(LOG_Info, "Bufferreader");
        try {
            BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
            String readline = "";
            StringBuffer stringBuffer = new StringBuffer();
            while ((readline = bufferedReader.readLine()) != null) {
                stringBuffer.append(readline);
            }
            if (bufferedReader != null) {
                bufferedReader.close();
                Log.i(LOG_Info, "读取的内容是:" + stringBuffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else if (Ways == 2) {
        Log.i(LOG_Info, "Input+Buffer");
        try {
            String fileContent = null;
            InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8");
            BufferedReader reader = new BufferedReader(read);
            String line;
            while ((line = reader.readLine()) != null) {
                fileContent += line;
            }
            reader.close();
            read.close();
            Log.i(LOG_Info, fileContent);
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(LOG_Error, e.getMessage());
        }
    } else
        Ways = 2;
}

/**
 * @param file: 文件/文件夹的路径
 * @Function: 文件夹  文件的删除
 * @Return:
 */
private void DeleteFileDirORFile(File file) {
    if (file.exists() == false) {
        return;
    } else {
        if (file.isFile()) {
            file.delete();
            return;
        }
        if (file.isDirectory()) {
            File[] childFile = file.listFiles();
            if (childFile == null || childFile.length == 0) {
                return;
            }
            if (childFile.length > 1) {
                for (File f : childFile) {
                    DeleteFileDirORFile(f);
                }
            }
        }
    }
}

         我想到的 IO 流的读取方式都在这了,,亲测可以使用,能力有限,漏的方法,大家自行百度,网络数据的请求,请参考另外一篇博客 httpClient 的请求,和第三方框架的使用。

    四、sharedPreference 存储

     使用与小数据的读取,理论的操作方式,网上一搜一大堆,我只贴代码

//从 SharedPreferences在中读出数据
private void ReadFromSharedPrefernces() {

    // 读取字符串数据
    String time = preferences.getString("time", null);
    // 读取int类型的数据
    int randNum = preferences.getInt("random", 0);
    String result = time == null ? "您暂时还未写入数据" : "写入时间为:"
            + time + "\n上次生成的随机数为:" + randNum;
    // 使用Toast提示信息
    Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
}

//往SharedPreferences中写入数据
private void WriteToSharedPrefernces() {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 "
            + "hh:mm:ss");
    // 存入当前时间
    editor.putString("time", sdf.format(new Date()));        // 存入一个随机数
    editor.putInt("random", (int) (Math.random() * 100));
    // 提交所有存入的数据
    editor.commit();
}

sharedPrefernces的存储方式和 map是一样的,存储为  .xml 文件,大家可以在这个目录下找到

DeviceFileExplorer:

 

找不到的,跟权限有关

 

    五、SQLite的存储方式

       数据的存储方式,我使用的 xUtils的第三方框架,具体的使用看我另外一篇博客 SQLite 的使用方法,在我的github上可以找到具体的SQLite和ROS的实战项目。更加利用大家的学习,这边只给出代码。大家可以下载。

    六、assets的存储方式 

    assets 目录可以继续建立 多个子文件夹  注意建立后修改路径
/**
 * @param fileName:  文件名字
 * @param index:文件类型 文本   图片  音乐  0 1 2
 * @Function: 读取 Assets下的文件
 * @Return:
 */
public void getTextFromAssets(String fileName, int index) {
    if (index == 0) { //文本操作
        String Result = "";
        try {
            InputStreamReader inputReader = new InputStreamReader(getResources().getAssets().open(fileName));
            BufferedReader bufReader = new BufferedReader(inputReader);
            String line = "";
            while ((line = bufReader.readLine()) != null)
                Result += line;
            Log.i(LOG_Info + "Assets", Result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else if (index == 1) {  //图片操作
        Bitmap bitmap = null;
        InputStream is = null;
        try {
            is = getAssets().open(fileName);
            bitmap = BitmapFactory.decodeStream(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        DC_ImageViewShow = (ImageView) findViewById(R.id.DC_ImageViewShow);
        DC_ImageViewShow.setImageBitmap(bitmap);
    } else if (index == 2) {   //音乐操作
        try {
            // 打开指定音乐文件,获取assets目录下指定文件的AssetFileDescriptor对象
            AssetFileDescriptor afd = assetManager.openFd(fileName);
            mPlayer.reset();
            // 使用MediaPlayer加载指定的声音文件。
            mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
            // 准备声音
            mPlayer.prepare();
            // 播放
            mPlayer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    } else
        Log.i(LOG_Error, "ERROR");
}

    七、res的存储方式

     相信  findbyId  没有人不会吧。

 

    八、raw的存储方式

       

public String getTextFromRaw() {
    String Result = "";
    try {
        InputStreamReader inputReader = new InputStreamReader(getResources().openRawResource(R.raw.abc));
        BufferedReader bufReader = new BufferedReader(inputReader);
        String line = "";

        while ((line = bufReader.readLine()) != null)
            Result += line;
        Log.i(LOG_Info + "Raw", Result);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return Result;
}

     

总结:  Android 上面所有的文件操作都在这里了,注释很详细了,大家可以下载 github上面的代码,网址: https://github.com/KEYD111/AndroidFileOperation

好好去研究,不要怕麻烦,因为小编以前也是每次写代码,Ctrl + c   ctrl +v  人家的代码,这个不行,换一个,往往不知道问题出在哪里,大家用的时候,可以将路径直接放到 read和writer里面去,我这样写,纯粹是为了对比给大家看。 比较的学习,我一直认为是比较好用。

谢谢大家,错误之处 还望不吝赐教。

 

  • 9
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值