1.内部外部存储文件
一、Android中内部存储,外部存储的概念
(1)内部存储
概念:注意内部存储不是内存。内部存储位于系统中很特殊的一个位置,如果你想将文件存储于内部存储中,那么文件默认只能被你的应用访问到,且一个应用所创建的所有文件都在和应用包名相同的目录下。也就是说应用创建于内部存储的文件,与这个应用是关联起来的。当一个应用卸载之后,内部存储中的这些文件也被删除。从技术上来讲如果你在创建内部存储文件的时候将文件属性设置成可读,其他app能够访问自己应用的数据,前提是他知道你这个应用的包名,如果一个文件的属性是私有(private),那么即使知道包名其他应用也无法访问。 内部存储空间十分有限,因而显得可贵,另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。所以对于内部存储空间,我们要尽量避免使用。Shared Preferences和SQLite数据库都是存储在内部存储空间上的。内部存储一般用Context来获取和操作。
访问内部存储的API方法:
1、Environment.getDataDirectory()
2、getFilesDir().getAbsolutePath()
3、getCacheDir().getAbsolutePath()
4、getDir(“myFile”, MODE_PRIVATE).getAbsolutePath()
(2)外部存储
概念:最容易混淆的是外部存储,因为老的Android系统的跟新的Android系统是有差别的,很多人去网上查找资料,看了一下以前的资料,又看了一下现在的资料,但是发现它们说法不一样然后就困惑了。首先说一个大家普遍的概念“如果在pc机上是区分外部存储和内部存储的话,那么电脑自带的硬盘算是内部存储,U盘或者移动硬盘就是外部存储了。”因此很多人带着这样的理解去看待安卓手机,把内置存储(机身存储)当做内部存储,而把扩展的SD卡当做是外部存储。这么认为确实没错,因为在4.4(API19)以前的手机上确实是这样的,手机自身带的存储卡就是内部存储,而扩展的SD卡就是外部存储。但是从4.4的系统开始,很多的中高端机器都将自己的机身存储扩展到了8G以上,比如有的人的手机是16G的,有的人的手机是32G的,但是这个16G,32G是内部存储吗,不是的!!!,它们依然是外部存储,也就是说4.4系统及以上的手机将机身存储存储(手机自身带的存储叫做机身存储)在概念上分成了”内部存储internal” 和”外部存储external” 两部分。既然16G,32G是外部存储,那有人又有疑惑了,那4.4系统及以上的手机要是插了SD卡呢,SD卡又是什么呢,如果SD卡也是外部存储的话,那怎么区分机身存储的外部存储跟SD卡的外部存储呢?对,SD卡也是外部存储,那怎么区分呢,在4.4以后的系统中,API提供了这样一个方法来遍历手机的外部存储路径:
File[] files;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
files = getExternalFilesDirs(Environment.MEDIA_MOUNTED);
for(File file:files){
Log.e(“main”,file);
}
}
如果你的手机插了SD卡的话,那么它打印的路径就有两条了,例如我的华为荣耀7插了SD卡,它的结果如下:
/storage/emulated/0/Android/data/packname/files/mounted
/storage/B3E4-1711/Android/data/packname/files/mounted
其中/storage/emulated/0目录就是机身存储的外部存储路径
而/storage/B3E4-1711/就是SD卡的路径
他们统称为外部存储
访问外部存储的API方法:
1、Environment.getExternalStorageDirectory().getAbsolutePath()
2、Environment.getExternalStoragePublicDirectory(“”).getAbsolutePath()
3、getExternalFilesDir(“”).getAbsolutePath()
4、getExternalCacheDir().getAbsolutePath()
1、Environment.getDataDirectory() = /data
这个方法是获取内部存储的根路径
2、getFilesDir().getAbsolutePath() = /data/user/0/packname/files
这个方法是获取某个应用在内部存储中的files路径
3、getCacheDir().getAbsolutePath() = /data/user/0/packname/cache
这个方法是获取某个应用在内部存储中的cache路径
4、getDir(“myFile”, MODE_PRIVATE).getAbsolutePath() = /data/user/0/packname/app_myFile
这个方法是获取某个应用在内部存储中的自定义路径
方法2,3,4的路径中都带有包名,说明他们是属于某个应用
…………………………………………………………………………………………
5、Environment.getExternalStorageDirectory().getAbsolutePath() = /storage/emulated/0
这个方法是获取外部存储的根路径
6、Environment.getExternalStoragePublicDirectory(“”).getAbsolutePath() = /storage/emulated/0
这个方法是获取外部存储的根路径
7、getExternalFilesDir(“”).getAbsolutePath() = /storage/emulated/0/Android/data/packname/files
这个方法是获取某个应用在外部存储中的files路径
8、getExternalCacheDir().getAbsolutePath() = /storage/emulated/0/Android/data/packname/cache
这个方法是获取某个应用在外部存储中的cache路径
2.具体使用方法
public static String getFilePath(Context context,String dir) {
String directoryPath="";
if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ) {//判断外部存储是否可用
directoryPath =context.getExternalFilesDir(dir).getAbsolutePath();
}else{//没外部存储就使用内部存储
directoryPath=context.getFilesDir()+File.separator+dir;
}
File file = new File(directoryPath);
if(!file.exists()){//判断文件目录是否存在
file.mkdirs();
}
return directoryPath;
}
3.使用sharedPreferences
用于存放应用中格式简单的轻量数据,如配置信息,以key-value形式保存
案例:
public class MainActivity extends Activity
{
SharedPreferences preferences;
SharedPreferences.Editor editor;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取只能被本应用程序读、写的SharedPreferences对象
preferences = getSharedPreferences("crazyit", MODE_PRIVATE);//将在/data/data/packageName/shared_prefs创建crazyit.xml文件
editor = preferences.edit();
Button read = (Button) findViewById(R.id.read);
Button write = (Button) findViewById(R.id.write);
read.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
// 读取字符串数据
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();
}
});
write.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
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();
}
});
}
}
4.File存储
public class MainActivity extends Activity
{
final String FILE_NAME = "crazyit.bin";
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
System.out.println(new StringBuilder("a").append("b").append("c")
.toString());
// 获取两个按钮
Button read = (Button) findViewById(R.id.read);
Button write = (Button) findViewById(R.id.write);
// 获取两个文本框
final EditText edit1 = (EditText) findViewById(R.id.edit1);
final EditText edit2 = (EditText) findViewById(R.id.edit2);
// 为write按钮绑定事件监听器
write.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View source)
{
// 将edit1中的内容写入文件中
write(edit1.getText().toString());
edit1.setText("");
}
});
read.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
// 读取指定文件中的内容,并显示出来
edit2.setText(read());
}
});
}
private String read()
{
try
{
// 打开文件输入流
FileInputStream fis = openFileInput(FILE_NAME);
byte[] buff = new byte[1024];
int hasRead = 0;
StringBuilder sb = new StringBuilder("");
// 读取文件内容
while ((hasRead = fis.read(buff)) > 0)
{
sb.append(new String(buff, 0, hasRead));
}
// 关闭文件输入流
fis.close();
return sb.toString();
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
private void write(String content)
{
try
{
// 以追加模式打开文件输出流
FileOutputStream fos = openFileOutput(FILE_NAME, MODE_APPEND);
// 将FileOutputStream包装成PrintStream
PrintStream ps = new PrintStream(fos);
// 输出文件内容
ps.println(content);
// 关闭文件输出流
ps.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
案例:文件浏览器
public class MainActivity extends Activity
{
ListView listView;
TextView textView;
// 记录当前的父文件夹
File currentParent;
// 记录当前路径下的所有文件的文件数组
File[] currentFiles;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取列出全部文件的ListView
listView = (ListView) findViewById(R.id.list);
textView = (TextView) findViewById(R.id.path);
// 获取系统的SD卡的目录
File root = new File("/mnt/sdcard/");
// 如果 SD卡存在
if (root.exists())
{
currentParent = root;
currentFiles = root.listFiles();
// 使用当前目录下的全部文件、文件夹来填充ListView
inflateListView(currentFiles);
}
// 为ListView的列表项的单击事件绑定监听器
listView.setOnItemClickListener(new OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id)
{
// 用户单击了文件,直接返回,不做任何处理
if (currentFiles[position].isFile()) return;
// 获取用户点击的文件夹下的所有文件
File[] tmp = currentFiles[position].listFiles();
if (tmp == null || tmp.length == 0)
{
Toast.makeText(MainActivity.this
, "当前路径不可访问或该路径下没有文件",
Toast.LENGTH_SHORT).show();
}
else
{
// 获取用户单击的列表项对应的文件夹,设为当前的父文件夹
currentParent = currentFiles[position]; // ②
// 保存当前的父文件夹内的全部文件和文件夹
currentFiles = tmp;
// 再次更新ListView
inflateListView(currentFiles);
}
}
});
// 获取上一级目录的按钮
Button parent = (Button) findViewById(R.id.parent);
parent.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View source)
{
try
{
if (!currentParent.getCanonicalPath()
.equals("/mnt/sdcard"))
{
// 获取上一级目录
currentParent = currentParent.getParentFile();
// 列出当前目录下所有文件
currentFiles = currentParent.listFiles();
// 再次更新ListView
inflateListView(currentFiles);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
});
}
private void inflateListView(File[] files) // ①
{
// 创建一个List集合,List集合的元素是Map
List<Map<String, Object>> listItems =
new ArrayList<Map<String, Object>>();
for (int i = 0; i < files.length; i++)
{
Map<String, Object> listItem =
new HashMap<String, Object>();
// 如果当前File是文件夹,使用folder图标;否则使用file图标
if (files[i].isDirectory())
{
listItem.put("icon", R.drawable.folder);
}
else
{
listItem.put("icon", R.drawable.file);
}
listItem.put("fileName", files[i].getName());
// 添加List项
listItems.add(listItem);
}
// 创建一个SimpleAdapter
SimpleAdapter simpleAdapter = new SimpleAdapter(this
, listItems, R.layout.line
, new String[]{ "icon", "fileName" }
, new int[]{R.id.icon, R.id.file_name });
// 为ListView设置Adapter
listView.setAdapter(simpleAdapter);
try
{
textView.setText("当前路径为:"
+ currentParent.getCanonicalPath());
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
4.Sqlite
4.1 创建数据库
4.2数据库操作步骤
具体代码:
1.创建数据库
2.建表
3.对数据操作
4.获取结果,渲染视图
4.3 CRUD
5.SQLiteHelper
1.打开或关闭数据库
2.需要重写的回调方法
public class MainActivity extends Activity
{
SQLiteDatabase db;
Button bn = null;
ListView listView;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 创建或打开数据库(此处需要使用绝对路径)
db = SQLiteDatabase.openOrCreateDatabase(
this.getFilesDir().toString()
+ "/my.db3", null); // ①
listView = (ListView) findViewById(R.id.show);
bn = (Button) findViewById(R.id.ok);
bn.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View source)
{
// 获取用户输入
String title = ((EditText) findViewById(
R.id.title)).getText().toString();
String content = ((EditText) findViewById(R.id.content))
.getText().toString();
try
{
insertData(db, title, content);
Cursor cursor = db.rawQuery("select * from news_inf"
, null);
inflateList(cursor);
}
catch (SQLiteException se)
{
// 执行DDL创建数据表
db.execSQL("create table news_inf(_id integer"
+ " primary key autoincrement,"
+ " news_title varchar(50),"
+ " news_content varchar(255))");
// 执行insert语句插入数据
insertData(db, title, content);
// 执行查询
Cursor cursor = db.rawQuery("select * from news_inf"
, null);
inflateList(cursor);
}
}
});
}
private void insertData(SQLiteDatabase db
, String title, String content) // ②
{
// 执行插入语句
db.execSQL("insert into news_inf values(null , ? , ?)"
, new String[] {title, content });
}
private void inflateList(Cursor cursor)
{
// 填充SimpleCursorAdapter
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
MainActivity.this,
R.layout.line, cursor,
new String[] { "news_title", "news_content" }
, new int[] {R.id.my_title, R.id.my_content },
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); // ③
// 显示数据
listView.setAdapter(adapter);
}
@Override
public void onDestroy()
{
super.onDestroy();
// 退出程序时关闭SQLiteDatabase
if (db != null && db.isOpen())
{
db.close();
}
}
}