[android] 保存文件到手机内存详解手机开发

/*****************2016年5月4日 更新*******************************/

知乎:Android 没有沙盒保护机制吗,WhatsApp 信息为何可被随意访问?

pansz

Android 对每个应用程序定义了私有的存储区域,这个区域通过 Linux 的文件系统权限控制,仅仅应用自己可以随意读写,问其他应用无法访问不属于自己的私有数据。私有目录的路径可以通过 Context->getFilesDir() 来获取。

 

除了私有存储区域以外,SD 卡上都是公共区域,所有人可读写。

 

一个 app 选择将隐私数据保存在公共区域,那是 App 选择取向问题。与系统其实没有什么关系。当然可以问 android 为什么要允许读写 SD 卡上任意目录,个人觉得这是历史问题,如果现在禁止了,估计一大堆读写 SD 卡的应用程序会出现兼容性问题,为了保证这种兼容性,感觉 android 不会将读写 SD 卡这种功能禁止掉。

 

Kifile

我觉得更应该是由于储存空间的关系。 在以前,不是任何一台设备都拥有几个g的系统储存空间,他们很多都只有100~200m的位置来存放app文件。 android中私有文件放在/data/data/$pakage 中,但是/data属于系统目录,如果把文件储存在里面,那势必会减少存放app文件的空间,这是得不偿失的。所以很多与系统文件无关的资源文件就只能放在sdcard中。 由于这种历史原因,虽然很多最新版的设备已经大幅提升其系统储存空间,但开发者们仍旧会将自身的资源文件放到sdcard中。 并且在最新的android4.4中,对于android程序的资源文件建议储存在/sdcard/Android/$package 中,我觉得这是一个很好的进步,规范了文件的储存位置,离它的访问权限管理还会远吗?

 

知乎:为什么 Android 4.4 KitKat 限制第三方应用的 SD 卡读写权限?

pansz

就目前而言,第二 SD 卡仍然是可以读写的,只是要读写到指定的目录(具体应该在 /Android/data/)。这样的规定意味着应用程序只能对 SD 卡的指定目录进行读写,不能读写任意目录。相当于 Google 出手对 SD 卡目录结构进行了规范。之前 android 不限制目录,所以各种应用就随意的在 SD 卡上建一个目录。然后 SD 卡上的目录到处都是,用户对这种现象早就深恶痛绝了!如果 Google 对这件事情下狠手,只能说是大快人心。

 

另外说一下,SD 卡上的指定目录是这样获取的:

1,程序相关的 内置存储目录,这个目录位于内置 flash,应用程序可以随意读写:

getFilesDir();

2,程序相关的 SD 卡外部存储目录,这个目录位于 SD 卡,应用程序可以随意读写:

getExternalFilesDir(null);

3,SD 卡公共目录,这些目录仍然可以访问,不受权限限制:

Environment.getExternalStoragePublicDirectory(x)

其中 x 可以是 Environment.DIRECTORY_ALARMS 等预定义的常量。可以查找 Environment 的帮助。

 

如果大家要存储数据,可以用 1 或者 2 的方法,获取正确的目录,然后进行任意读写,这样不会把 SD 卡的目录写乱。

/*****************************************************************************/

 

 

1. 界面的准备工作,普通登录界面,采用线性布局和相对布局。

<Checkbox/>有个属性 android:checked=”true”,默认选中状态,相对布局里面<Button/>位于右边android:layout_alignParentRight=”true”,位于父控件的右面。密码框星号显示android:inputType=”textPassword”

 

2. 遇到device not found等错误可以直接忽略掉,布局文件属性里面绑定点击方法,传入的参数View对象代表当前按钮,控件首先都声明在Activity的成员属性里面,在onCreate()方法里面初始化,初始化控件一定要在setContentView()方法加载完界面之后才行。

 

3. 复选框判断是否选中使用CheckBox对象的isChecked()方法,判断字符串是否相等用String对象的equals()方法,logcat如果无法打印日志,关闭logcat重开或者关闭eclipse

 

4. 保存文件javaSE里面是直接new File(“aaa.txt”),文件默认保存在工程的目录下面,但是在android系统里面,这样默认是创建在/data/app 目录下面,这里是不允许创建文件的。Android下每一个应用都有自己的数据文件夹/data/data/包名/

 

5. 新建一个业务类来处理保存信息的操作。这里的写法和javaSE一样,new File(“/data/data/包名/文件名”)对象,new FileOutputStream() 对象,此时会有异常抛出,因为我们这个方法有返回boolean值,所以我们捕获掉,如果是无返回值那就throws Exception抛出去。字符串信息getBytes()转成字节数组,调用foswrite()方法,关闭fos。当这个方法没有使用类的成员属性的时候,谷歌推荐把这个方法定义成static静态的,效率更高

 

6. 文件路径部分,如果按照上面所写,灵活性很差。当我改变包名的时候,程序会报错,R文件要从新导一下,并且android会认为是个新的应用。谷歌提供了一个api来获取应用的数据目录,调用Context上下文对象的getFilesDir()方法,返回的是/data/data/包名/files/。因此可以这样new File(context.getFilesDir(),”info1.txt”);来写。

 

7. 数据目录还有个文件夹是cache目录,调用Context对象的getCacheDir()来获取,这个目录可以通过设置里面清除缓存清掉,这个目录不能存放过大的文件

 

8. 上下文就是一个类提供了方便的api可以得到应有程序的环境,可以获取包名,文件路径,资源路径,资产路径等

 

9. 读取保存文件的信息,同样new File() ,new FileInputStream() ,

 

activity代码:

 

package com.tsh.savefile; 
 
import java.util.Map; 
 
import org.w3c.dom.Text; 
 
import com.tsh.savefile.service.LoginService; 
 
import android.app.Activity; 
import android.os.Bundle; 
import android.text.TextUtils; 
import android.view.View; 
import android.widget.CheckBox; 
import android.widget.EditText; 
import android.widget.Toast; 
 
public class MainActivity extends Activity { 
    private EditText et_username; 
    private EditText et_password; 
    private CheckBox cb_rember; 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
        et_username=(EditText) findViewById(R.id.et_username); 
        et_password=(EditText) findViewById(R.id.et_password); 
        cb_rember=(CheckBox) findViewById(R.id.cb_rember); 
        //读取 
        Map<String, String> info=LoginService.getSavedUserInfo(this); 
        if(info != null){ 
            et_username.setText(info.get("username")); 
            et_password.setText(info.get("password")); 
        } 
    } 
    /** 
     * 登陆 
     * @param v 
     */ 
    public void login(View v){ 
        String username=et_username.getText().toString().trim(); 
        String password=et_password.getText().toString().trim(); 
        if(TextUtils.isEmpty(username)||TextUtils.isEmpty(password)){ 
            Toast.makeText(this, "用户名和密码不能为空", Toast.LENGTH_SHORT).show(); 
        } 
        //记住密码 
        if(cb_rember.isChecked()){ 
            Boolean res=LoginService.saveUserInfo(this,username, password); 
            if(res){ 
                Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show(); 
            }else{ 
                Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show(); 
            } 
        } 
        //验证 
        if(username.equals("taoshihan")&&password.equals("1")){ 
            Toast.makeText(this, "登陆成功", Toast.LENGTH_SHORT).show(); 
        }else{ 
            Toast.makeText(this, "用户名或密码错误", Toast.LENGTH_SHORT).show(); 
        } 
    } 
}

 

业务类代码:

package com.tsh.savefile.service; 
 
import java.io.BufferedReader; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.InputStreamReader; 
import java.util.HashMap; 
import java.util.Map; 
 
import android.content.Context; 
 
public class LoginService { 
    /** 
     * 保存用户名和方法的业务方法 
     * @param context 上下文 
     * @param username 用户名 
     * @param password 方法 
     * @return 
     */ 
    public static boolean saveUserInfo(Context context,String username,String password){ 
        File file=new File(context.getFilesDir(),"info1.txt"); 
        try { 
            FileOutputStream fos=new FileOutputStream(file); 
            String info=username+"##"+password; 
            fos.write(info.getBytes()); 
            fos.close(); 
            return true; 
        } catch (Exception e) { 
            e.printStackTrace(); 
            return false; 
        } 
         
    } 
    /** 
     * 读取 
     * @return 
     */ 
    public static Map<String,String> getSavedUserInfo(Context context){ 
        File file=new File(context.getFilesDir(),"info1.txt"); 
        try { 
            FileInputStream fis=new FileInputStream(file); 
            BufferedReader br=new BufferedReader(new InputStreamReader(fis)); 
            String[] res=br.readLine().split("##"); 
            Map<String, String> map=new HashMap<String,String>(); 
            map.put("username", res[0]); 
            map.put("password", res[1]); 
            return map; 
        } catch (Exception e) { 
            e.printStackTrace(); 
            return null; 
        } 
         
    } 
}

layout代码:

<LinearLayout 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" 
    android:orientation="vertical" 
    tools:context="com.tsh.savefile.MainActivity" > 
 
    <TextView 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" 
        android:text="登录名" /> 
 
    <EditText 
        android:id="@+id/et_username" 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" /> 
 
    <TextView 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" 
        android:text="密码" /> 
 
    <EditText 
        android:id="@+id/et_password" 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" 
        android:inputType="textPassword" /> 
 
    <RelativeLayout 
        android:layout_width="match_parent" 
        android:layout_height="wrap_content" > 
 
        <CheckBox 
            android:id="@+id/cb_rember" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:layout_centerVertical="true" 
            android:checked="true" 
            android:text="记住密码" /> 
 
        <Button 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:layout_alignParentRight="true" 
            android:onClick="login" 
            android:text="登陆" /> 
    </RelativeLayout> 
 
</LinearLayout>

 

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/5505.html

(0)
上一篇 2021年7月16日
下一篇 2021年7月16日

相关推荐

发表回复

登录后才能评论