/*****************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()转成字节数组,调用fos的write()方法,关闭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>

[android] 保存文件到手机内存的更多相关文章

  1. 无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)

    1.android下junit测试框架配置 单元测试需要在手机中进行安装测试 (1).在清单文件中manifest节点下配置如下节点 <instrumentation android:name= ...

  2. Android mmap 文件映射到内存介绍

    本文链接: Android mmap 文件映射到内存介绍 Android开发中,我们可能需要记录一些文件.例如记录log文件.如果使用流来写文件,频繁操作文件io可能会引起性能问题. 为了降低写文件的 ...

  3. Android学习笔记-获取手机内存,SD卡存储空间。

    前面介绍到如何保存数据到手机内存或者SD卡,但是问题是,在保存以前,我们还需要对他们的空间(可用空间),进行判断,才可以进行后续操作,所以,本节我们就介绍如何获取手机内存以及Sd卡的空间. //这时获 ...

  4. Android 读取和保存文件(手机内置存储器)

    1:activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/androi ...

  5. android 保存文件的各种目录列表

    一般的,我们可以通过context和Environment来获取要保存文件的目录 ($rootDir) +- /data -> Environment.getDataDirectory() | ...

  6. Android -- 保存文件

    背景                                                                                             我们以常见 ...

  7. [android] 保存文件到SD卡

    /****************2016年5月4日 更新*****************************/ 知乎:为什么很多Android应用要把文件写到/sdcard目录下而不是写到/d ...

  8. Android 写文件到手机

    1)// 在手机中创建文件 FileOutputStream phone_outStream =this.openFileOutput("1.txt", Context.MODE_ ...

  9. android保存文件到SD卡中

    想把文件保存到SD卡中,一定要知道SD卡的路径,有人说可以用File explore来查看,这种方法不太好,因为随着android版本的升级,SD卡的路径可能会发生改变.在1.6的时候SD的路径是/s ...

随机推荐

  1. LeetCode刷题:第七题 整数翻转 第九题 回文数

    第七题题目描述: 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 123 输出: 321 示例 2: 输入: -123 输出: -321 示例 3: 输入 ...

  2. LVS简单介绍

    一.LVS简介 linux virtual server简称LVS,Internet的快速增长使多媒体网络服务器面对的访问数量快速增加,服务器需要具备提供大量并发访问服务的能力,因此对于大负载的服务器 ...

  3. HashMap内部结构及实现原理

    简单介绍 在研究HashMap之前,我们先大概了解下其他数据结构在新增,查找等基础操作执行性能 数组:采用一段连续的存储单元来存储数据.对于指定下标的查找,时间复杂度为O(1):通过给定值进行查找,需 ...

  4. selenium+phantomjs+pyquery 爬取淘宝商品信息

    from selenium import webdriver from selenium.common.exceptions import TimeoutException from selenium ...

  5. 英语演讲稿——Get Along with Fear

    Hi. My name is Zhang Meng. I’m an engineer at Keysight. Today I’m not going to introduce my birthpla ...

  6. 基于Fusioncharts的报表统计

    先了解fusioncharts插件,fusioncharts是一款基于XML和flash的报表组件,支持Java.PHP.AngularJS等等开发语言,所以,开发出来,加入swf文件,就可以出现动态 ...

  7. Javascript高级编程学习笔记(73)—— 表单(1)表单基础

    表单 JS最初的一个用途就是帮助服务器分担处理表单的责任 时至今日,虽然web应用以及JS都有了长足的发展,但是表单依然是现在web应用中比较重要的部分. 因为默认的表单控件很丑,所以有时候我们会使用 ...

  8. php--include 、require

    一.include .require 定义:包含并运行指定文件 问题:查询了这两个语言结构的资料,有人说,什么require  先执行,什么include后执行. 思考:我觉得官方文档已经解释的很清楚 ...

  9. PyTorch--双向递归神经网络(B-RNN)概念,源码分析

    关于概念: BRNN连接两个相反的隐藏层到同一个输出.基于生成性深度学习,输出层能够同时的从前向和后向接收信息.该架构是1997年被Schuster和Paliwal提出的.引入BRNNS是为了增加网络 ...

  10. hbaes之createTable执行流程

    hbase的客户端代码并不想hive一样用java编写,shell调用,而是使用ruby编写. 在admin.rb文件中方法create,其中接受两个参数,其中第二个参数类型为变长参数. 而在crea ...