一、/assets目录下文件的操作;SD卡上文件的操作
将文件资源放置在“项目根目录/assets”文件夹下,在将项目打包成apk时,这些文件资源不会被编译,而是会原样打包进apk。安装apk时,这些文件资源会被部署到用户手机中。
注意:文件操作是耗时操作,最好放置在异步线程中完成。
下面的实例演示是从assets文件夹下读取文本文件里面的文本;从assets文件夹下读取apk到SD卡并安装。
项目结构:
/Get_Assets_test/res/layout/activity_main.xml文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/txt_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test" />
<Button
android:id="@+id/btn_apk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/txt_info"
android:text="安装apk" />
</RelativeLayout>
/Get_Assets_test/src/com/example/get_assets_test/MainActivity.java文件:
//本实例仅仅为了演示从“项目根目录/assets”文件夹下读取文件。所以没有做异步线程,
//但是文件操作是耗时操作,最好放置在异步线程中完成。
package com.example.get_assets_test;
import java.io.File;
//注意,InputStream或者OutputStream只是抽象类,不能实例化!
//FileInputStream或者FileOutputStream才可以实例化!
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView txt_info = (TextView) findViewById(R.id.txt_info);
Button btn_apk = (Button) findViewById(R.id.btn_apk);
// ----------------------------------------------------
// 从asstes文件夹下读取文本文件中的文字
try
{
// getAssets是Context对象的成员函数,open函数参数直接就是assets下文件的文件名
// info-utf-8里面的字符是以utf-8编码的,不经过转码会出现乱码的
// 从assets下读文件不需要任何特殊权限
InputStream inputStream = this.getAssets().open("info-utf-8");
// 在输入流上建立读取器,读取器是一个字符一个字符地读,适合读取文本文件,不适合读取纯字节文件
InputStreamReader fr = new InputStreamReader(inputStream);
int ch = 0;
String result = "";
while ((ch = fr.read()) != -1)
{
result += (char) ch;
}
String info = new String(result.getBytes("UTF-8"), "GBK");
txt_info.setText(result);
// 关闭读取器,输入流
fr.close();
inputStream.close();
} catch (Exception e)
{
txt_info.setText(e.getMessage());
}
// ----------------------------------------------------
// 从asstes文件夹下读取apk文件并安装
// 从assets下读文件不需要任何特殊权限,但是读写SD卡需要权限
// <uses-permission
// android:name="android.permission.WRITE_EXTERNAL_STORAGE"
// />
btn_apk.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
try
{
File filePath = new File("/sdcard/YongYu_IT");
// 如果/sdcard/YongYu_IT文件夹不存在则创建,这一步需要添加写SD卡权限
// <uses-permission
// android:name="android.permission.WRITE_EXTERNAL_STORAGE"
// />
if (!filePath.exists())
{
filePath.mkdirs();
}
String fileName = "meinv_liulanqi.apk";
// 创建文件变量,两个参数,第一个参数是文件目录,第二个参数是文件名
File newApkFile = new File(filePath, fileName);
// 如果这个文件已经在文件系统中不存在则将这个文件变量写到文件系统中
if (!newApkFile.exists())
{
// 将文件变量写到文件系统中
newApkFile.createNewFile();
// 在assets下的指定文件上打开输入流
InputStream inputStream = MainActivity.this.getAssets()
.open("MeiNv_Liulanqi.apk");
// 在文件变量上打开输出流
FileOutputStream fout = new FileOutputStream(newApkFile);
// 设置流缓冲区
byte[] buffer = new byte[1024 * 10];
// 从输入流(在assets下的指定文件上)读到输出流(在文件变量上)
while (true)
{
int len = inputStream.read(buffer);
if (len == -1)
{
break;
}
fout.write(buffer, 0, len);
}
// 关闭输入输出流
inputStream.close();
fout.close();
// 安装这个apk
String apkName = filePath + "/" + fileName;
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(Uri.fromFile(new File(apkName)),
"application/vnd.android.package-archive");
// 向MainActivity报告安装结果
MainActivity.this.startActivityForResult(install, 1111);
}
} catch (Exception e)
{
txt_info.setText(e.getMessage());
}
}
});
}
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
// MainActivity得到了回报数据
if (requestCode == 1111)
{
Toast t = Toast.makeText(this, "安装完毕", 10000);
t.show();
}
}
}
二、res/raw下文件的操作
在/res/raw下放置的文件和在/assets下放置的文件相似,都不会被编译,而是会原样打包进apk。安装apk时,这些文件资源会被部署到用户手机中。
不同的是:1、res/raw下的文件会在R.java中产生映射,而/assets下的文件则不会
2、res/raw下不可再新建目录结构,而/assets下则可以。
3、/assets下的文件可以随意命名,但是res/raw下的文件符合这样的命名规则:must contain only [a-z0-9_.]
4、假设在Activity上下文中。读取文件时,res/raw下文件用的是:InputStream is = getResources().openRawResource(R.raw.filename);
/assets下用的是:InputStream is = getAssets().open("fullfilename");//fullfilename是以 /assets为根的文件全路径名称
上面的实例代码将文件放置在/res/raw下,修改成/res/raw访问方式,效果是一样的。
三、读写应用程序的“私有文件目录”
所谓的应用程序的私有文件目录其实指的就是 /data/data/[Package Full Name] 目录,此目录只有应用程序自身有权限读写,其他应用程序不能读写(当然,如果获取了Root权限就另当别论 了)。
注意,当应用程序卸载时,私有文件目录(及其所有子目录)会被删除。
下面的实例演示的是:操作(读写)“私有文件目录”
/openFileInOrOutPutTest/res/layout/activity_main.xml文件:
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/btn_zhaoxiang"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拍照并保存" />
<!-- 这张图片将来自内存 -->
<ImageView
android:id="@+id/img_zhaopian_neicun"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/btn_zhaoxiang"
android:src="@drawable/ic_launcher" />
<!-- 这张图片将来来自“私有文件目录” -->
<ImageView
android:id="@+id/img_zhaopian_siyoumulu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/img_zhaopian_neicun"
android:src="@drawable/ic_launcher" />
</RelativeLayout>
/openFileInOrOutPutTest/src/com/example/openfileinoroutputtest/MainActivity.java文件:
package com.example.openfileinoroutputtest;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_zhaoxiang = (Button) findViewById(R.id.btn_zhaoxiang);
btn_zhaoxiang.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
// 发起照相,系统Activity
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1111);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1111)
{
// Bitmap是Android系统图像处理中最重要的类之一。
// 借助它可以获取图像文件信息,进行图像剪切、旋转、缩放等操作,可以指定格式保存图像文件。
Bitmap bitmap = null;
// 接收从完成照相的系统Activity里报告过来的图片数据,并用这些数据实例化Bitmap
Bundle bundle = data.getExtras();
bitmap = (Bitmap) bundle.get("data");
// 设置第一个ImageView的图片,注意,此时这个图片来自内存
ImageView img_zhaopian = (ImageView) this
.findViewById(R.id.img_zhaopian_neicun);
img_zhaopian.setImageBitmap(bitmap);
try
{
// 用文件流,以私有方式打开“私有文件目录”
FileOutputStream fout = this.openFileOutput("img.jpeg",
this.MODE_PRIVATE);
// 将Bitmap里面的数据通过FileOutputStream输出到“私有文件目录”的指定文件中
bitmap.compress(CompressFormat.JPEG, 100, fout);
// 关闭输出流
fout.close();
// 不要随便回收Bitmap,因为很多输入输出操作有事异步执行的,在手动回收时可能Bitmap还没用完,这时就会报错
// bitmap.recycle();
// 通过FileInputStream从“私有文件目录”下读入指定文件
FileInputStream fin = this.openFileInput("img.jpeg");
// 借助FileInputStream将文件数据输入到Bitmap中
Bitmap bitmap_from_siyoumulu = BitmapFactory.decodeStream(fin);
ImageView img_zhaopian_siyoumulu = (ImageView) this
.findViewById(R.id.img_zhaopian_siyoumulu);
img_zhaopian_siyoumulu.setImageBitmap(bitmap_from_siyoumulu);
// bitmap_from_siyoumulu.recycle();
} catch (Exception e)
{
Log.e("yongyu_it", e.getMessage());
}
}
}
}
效果: