[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()转成字节数组,调用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] 保存文件到手机内存的更多相关文章
- 无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)
1.android下junit测试框架配置 单元测试需要在手机中进行安装测试 (1).在清单文件中manifest节点下配置如下节点 <instrumentation android:name= ...
- Android mmap 文件映射到内存介绍
本文链接: Android mmap 文件映射到内存介绍 Android开发中,我们可能需要记录一些文件.例如记录log文件.如果使用流来写文件,频繁操作文件io可能会引起性能问题. 为了降低写文件的 ...
- Android学习笔记-获取手机内存,SD卡存储空间。
前面介绍到如何保存数据到手机内存或者SD卡,但是问题是,在保存以前,我们还需要对他们的空间(可用空间),进行判断,才可以进行后续操作,所以,本节我们就介绍如何获取手机内存以及Sd卡的空间. //这时获 ...
- Android 读取和保存文件(手机内置存储器)
1:activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/androi ...
- android 保存文件的各种目录列表
一般的,我们可以通过context和Environment来获取要保存文件的目录 ($rootDir) +- /data -> Environment.getDataDirectory() | ...
- Android -- 保存文件
背景 我们以常见 ...
- [android] 保存文件到SD卡
/****************2016年5月4日 更新*****************************/ 知乎:为什么很多Android应用要把文件写到/sdcard目录下而不是写到/d ...
- Android 写文件到手机
1)// 在手机中创建文件 FileOutputStream phone_outStream =this.openFileOutput("1.txt", Context.MODE_ ...
- android保存文件到SD卡中
想把文件保存到SD卡中,一定要知道SD卡的路径,有人说可以用File explore来查看,这种方法不太好,因为随着android版本的升级,SD卡的路径可能会发生改变.在1.6的时候SD的路径是/s ...
随机推荐
- Python序列结构--字典
字典:反映对应关系的映射类型 字典(dict)是包含若干“键:值”元素的无序可变序列 字典中元素的“键”可以是python中任意不可变数据,例如整数.实数.复数.字符串.元组等类型可哈希数据,“键”不 ...
- NAT技术与代理服务器
1.什么是NAT技术? NAT(network address Translation):网络地址转换 使用端口号的NAT:网络地址与端口号转换 2.理解下图就可以完全知道NAT技术的原理: 3.什么 ...
- ASP.NET Core MVC 源码学习:详解 Action 的匹配
前言 在 上一篇 文章中,我们已经学习了 ASP.NET Core MVC 的启动流程,那么 MVC 在启动了之后,当请求到达过来的时候,它是怎么样处理的呢? 又是怎么样把我们的请求准确的传达到我们的 ...
- ES6之命令妙用
很多人都听说过ES6(也就是ECMAScript的新一代标准)并且对她充满了向往,下面通过一个ES6中小知识点——let命令,来解开她的神秘面纱,让大家初步认识一下ES6的语法规范. ...
- Android Studio 调试各种国产手机经验总结
为何加上“国产”二字呢,因为目前测试时就国产手机存在的安装问题多,而且都很奇葩,不得不说对于开发者时很不友好的. 下面就是个人总结的针对不同的机型调试时出现的问题做的总结: 1.VIVO 手机 解决方 ...
- centos 安装setup命令的方法
yum -y install setuptool 安装setup命令工具 yum -y install ntsysv 安装setup工具配套的系统服务组件 yum -y install system- ...
- GDB dump mem example和命令
使用方法: You can use the commands dump, append, and restore to copy data between target memory and a fi ...
- Kubernetes集群搭建之CNI-Flanneld部署篇
本次系列使用的所需部署包版本都使用的目前最新的或最新稳定版,安装包地址请到公众号内回复[K8s实战]获取 Flannel是CoreOS提供用于解决Dokcer集群跨主机通讯的覆盖网络工具.它的主要思路 ...
- PythonDay02——编程语言、python介绍以及安装解释器、运行程序的两种方式、变量
一.编程语言 1.1 机器语言:直接用计算机能理解的二进制指令编写程序,直接控制硬件 1.2 汇编语言:用英文标签取代二进制指令去编写程序,本质也是直接控制硬件 1.3 高级语言:用人能理解的表达方式 ...
- asp.net core 2.0发布到IIS流程及报错解决方案
我这是个新装的服务器,没有安装任何软件. 一.发布流程 1.安装AspNetCoreModule托管模块,同时会自动安装..net core runtime DotNetCore.2.0.8-Wi ...