得学会写博客,以前是觉得逼格,现在发现是为了总结自己的所学,项目做完了不代表会了,东西学完了不代表懂了。总结之后不会、不懂也无所谓,自己的接口调了就行了。当然了,啪啦啪啦,写完做完还不会的,我也不想说什么。看完这篇不会,下次就直接调我的接口吧。代码已经上传到 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里面去,我这样写,纯粹是为了对比给大家看。 比较的学习,我一直认为是比较好用。
谢谢大家,错误之处 还望不吝赐教。