您的位置:首页 > 移动开发 > Android开发

android 文件输出操作详解

2011-11-11 23:23 369 查看
数据存储和访问方式一:文件

MVC:V-layout\main.xml;C-Activity;M-业务层

①文件写入操作

//往手机自带的存储空间写入文件

FileOutputStream outStream = this.getContext().openFileOutput("test.txt", Context.MODE_PRIVATE);

outStream.write("西安网星".getBytes());

outStream.close();

openFileOutput(String name, int mode)方法的第一参数用于指定文件名称,不能包含路径分隔符“/”,如果文件不存在,Android应用会自动创建它。

创建的文件保存在/data/data/<package name>/files目录,如:/data/data/com.xawx.file/files/test.txt,

通过点击Eclipse菜单“Window”-“Show View”-“Other”,在对话窗口中展开Android文件夹,选择下面的File Explorer视图,

然后在File Explorer视图中展开/data/data/com.xawx.file/files目录就可以看到保存的文件test.txt。

openFileOutput(String name, int mode)方法的第二参数用于指定操作模式,有四种模式,分别为:

Context.MODE_PRIVATE = 0

Context.MODE_APPEND = 32768

Context.MODE_WORLD_READABLE = 1

Context.MODE_WORLD_WRITEABLE = 2

Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中,可以使用Context.MODE_APPEND。

Context.MODE_APPEND:创建的文件是私有数据,该模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。

Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。

MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。

如果希望该文件被其他应用读和写,可以这样写: openFileOutput("test.txt", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);

android有一套自己的安全模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,如果该应用要去访问其他资源比如文件的时候,就需要userid匹配。

默认情况下,任何应用创建的文件、SharedPreferences、数据库都应该是私有的(位于/data/data/<package name>/files),其他程序无法访问。

除非在创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE ,只有这样设置其他程序才能正确访问。

②文件读取操作

//从手机自带的存储空间里面读取文件

FileInputStream inStream = this.getContext().openFileInput("test.txt");

//定义缓冲区大小

byte [] buffer = new byte[1024];

int len = 0;

//内存输出流

ByteArrayOutputStream outStream = new ByteArrayOutputStream();

//从输入流里面读取数据到缓冲区,如果读取到流的末尾返回-1,否则返回读取到的实际字节长度

while( (len = inStream.read(buffer)) != -1 ){

//往内存中写入数据

outStream.write(buffer, 0, len);

}

//获取内存中该文件的二进制数据

byte [] data = outStream.toByteArray();

outStream.close();

inStream.close();

Activity的getFilesDir()方法:返回/data/data/com.xawx.file/files文件对象

Activity的getCacheDir()方法:返回/data/data/com.xawx.file/cache文件对象,存放一些缓存数据

③往手机的SDCard里面写入文件

在模拟器中使用SDCard,你需要先创建一张SDCard卡(当然不是真的SDCard,只是镜像文件)。创建SDCard可以在Eclipse创建模拟器时随同创建,也可以使用DOS命令进行创建,在DOS窗口中进入android SDK安装路径的tools目录,输入以下命令创建一张容量为2G的SDCard,文件后缀可以随便取,建议使用.img:mksdcard 2048M D:\sdcard.img。

//判断SDCard是否存在,是否允许读取或者写入文件

if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){

//使用SDCard的绝对路径

//File file = new File("/mnt/sdcard", "test.txt");

//获取SDCard所在路径,建议使用此方式

File file = new File(Environment.getExternalStorageDirectory(), "test.txt");

FileOutputStream outStream = new FileOutputStream(file);

outStream.write("西安网星".getBytes());

outStream.close();

}

在程序中访问SDCard,需要申请访问SDCard的权限。

在AndroidManifest.xml中加入访问SDCard的权限,如下所示:

<!-- 在SDCard中创建与删除文件权限 -->

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

<!-- 在SDCard写入数据权限 -->

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

④解析XML文件

在Android平台上可以使用Simple API for XML(SAX)、Document Object Model(DOM)和Android附带的Pull解析器解析XML文件。

下面是要解析的XML文件:

文件名称:person.xml

<?xml version="1.0" encoding="UTF-8"?>

<persons>

<person id="1">

<name>张三</name>

<age>30</age>

</person>

<person id="2">

<name>李四</name>

<age>25</age>

</person>

</persons>

第一种方法:SAX是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备。SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,会判断当前读到的字符是否是合法XML语法中的某部分,如果符合就会触发事件。所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口中。

下面是ContentHandler接口中一些常用的方法:

startDocument()

当遇到文档的开头的时候,调用这个方法,可以在其中做一些预处理的工作。

endDocument()

和上面的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。

startElement(String namespaceURI, String localName, String qName, Attributes atts)

当读到一个开始标签的时候,会触发这个方法。namespaceURI就是命名空间,localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名,通过atts可以得到所有的属性名和相应的值。要注意的是SAX中一个重要的特点就是它的流式处理,当遇到一个标签的时候,它并不会记录下以前所碰到的标签,也就是说,在startElement()方法中,所有你所知道的信息,就是标签的名字和属性,至于标签的嵌套结构、上层标签的名字、是否有子元属等等其它与结构相关的信息,都是不得而知的,都需要你的程序来完成。这使得SAX在编程处理上没有DOM那么方便。

endElement(String uri, String localName, String name)

这个方法和上面的方法相对应,在遇到结束标签的时候,调用这个方法。

characters(char[] ch, int start, int length)

这个方法用来处理在XML文件中读到的内容,第一个参数为整个XML文件的字符串内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch, start, length)就可以获取内容。

person.xml有几种类型的节点?一种是ElementNode,另一种是TextNode(注意<persons><person>之间的空白也是文本节点)。

其中<persons>、<person>这种节点就属于ElementNode,而zhangsan、30这种就属于TextNode。

<?xml version="1.0" encoding="UTF-8"?>---startDocument()

<persons>(--------------------------------startElement(String namespaceURI, String localName, String qName, Attributes atts)

)------characters(char[] ch, int start, int length)<person id="1">

<name>zhangsan</name>--------endElement(String uri, String localName, String name)

<age>30</age>

</person>

<person id="2">

<name>lisi</name>

<age>25</age>

</person>

</persons>

XML文件被SAX解析器载入,由于SAX解析是按照XML文件的顺序来解析,当读入<?xml.....>时,会调用startDocument()方法,当读入<persons>的时候,由于它是个ElementNode,所以会调用startElement(String uri, String localName, String qName, Attributes attributes) 方法,其中第二个参数就是节点的名称,注意:由于有些环境不一样,有时候第二个参数有可能为空,所以可以使用第三个参数,因此在解析前,先调用一下看哪个参数能用,第四个参数是这个节点的属性。由于我们不需要persons这个节点,所以从<person>这个节点开始,当读入时,调用startElement(....)方法,由于只有一个属性id,可以通过attributes.getValue(0)来得到,然后调用characters(char[]
ch, int start, int length)方法,不要以为那里是空白,SAX解析器可不这么认为,SAX解析器会把它认为是一个TextNode,但是这个空白不是我们想要的数据,我们是想要<name>节点下的文本信息,这就要定义一个记录当前节点的名称的tag,在characters(.....)方法中,判断当前节点是不是name,如果是再取值,这样才能取到"zhangsan"。

public class SAXParsePersonService {

public ArrayList<Person> getPersons(InputStream is) throws Exception{

SAXParserFactory factory = SAXParserFactory.newInstance();

SAXParser parser = factory.newSAXParser();

PersonHandler personHandler = new PersonHandler();

parser.parse(is, personHandler);

is.close();

return personHandler.getPersons();

}

private final class PersonHandler extends DefaultHandler{

private ArrayList<Person> persons = null;

private Person person = null;

private String tag = null;

@Override

public void startDocument() throws SAXException {

persons = new ArrayList<Person>();

}

@Override

public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

if("person".equals(localName)){

person = new Person();

person.setId(new Integer(attributes.getValue(0)));

}

//记录当前节点的名称

tag = localName;

}

@Override

public void characters(char[] ch, int start, int length) throws SAXException {

if(tag != null){

String data = new String(ch, start, length);

if("name".equals(tag)){

person.setName(data);

}else if("age".equals(tag)){

person.setAge(new Short(data));

}

}

}

@Override

public void endElement(String uri, String localName, String qName) throws SAXException {

if("person".equals(localName)){

persons.add(person);

person = null;

}

tag = null;

}

public List<Person> getPersons() {

return persons;

}

}

}

第二种方法:DOM解析XML文件时,会将XML文件的所有内容以文档树方式加载到内存中,然后允许使用DOM API遍历XML树、检索所需的数据。使用DOM操作XML的代码看起来是比较直观的,并且在编码方面比基于SAX的实现更加简单。因为DOM需要将XML文件的所有内容以文档树方式加载到内存中,所以对内存的消耗比较大,特别对于运行Android的移动设备来说,因为设备的资源比较宝贵,所以建议采用SAX来解析XML文件。当然,如果XML文件的内容比较小采用DOM也是可行的。

public class DOMParsePersonService {

public List<Person> getPersons(InputStream is) throws Exception{

List<Person> persons = new ArrayList<Person>();

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = factory.newDocumentBuilder();

Document document = builder.parse(is);

Element root = document.getDocumentElement();

NodeList personNodes = root.getElementsByTagName("person");

for(int i = 0; i < personNodes.getLength(); i++){

Person person = new Person();

Element personElement = (Element)personNodes.item(i);

Integer id = new Integer(personElement.getAttribute("id"));

person.setId(id);

NodeList personChilds = personElement.getChildNodes();

for(int j = 0; j < personChilds.getLength(); j++){

if(personChilds.item(j).getNodeType() == Node.ELEMENT_NODE){

Element personChild = (Element)personChilds.item(j);

if("name".equals(personChild.getNodeName())){

String name = personChild.getFirstChild().getNodeValue();

person.setName(name);

}else if("age".equals(personChild.getNodeName())){

Short age = new Short(personChild.getFirstChild().getNodeValue());

person.setAge(age);

}

}

}

persons.add(person);

}

is.close();

return persons;

}

}

第三种方法:使用Android内置的Pull解析器解析XML文件。Pull解析器的运行方式与SAX解析器相似。它提供了类似的事件,例如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型节点的值。

Pull解析器的源码及文档下载网址:http://www.xmlpull.org/

public class PULLParsePersonService {

public static void savePersonsOutputStream(List<Person> persons, OutputStream outStream) throws Exception {

XmlSerializer serializer = Xml.newSerializer();

serializer.setOutput(outStream, "UTF-8");

serializer.startDocument("UTF-8", true);

serializer.startTag(null, "persons");

for(Person person : persons){

serializer.startTag(null, "person");

serializer.attribute(null, "id", person.getId().toString());

serializer.startTag(null, "name");

serializer.text(person.getName());

serializer.endTag(null, "name");

serializer.startTag(null, "age");

serializer.text(person.getAge().toString());

serializer.endTag(null, "age");

serializer.endTag(null, "person");

}

serializer.endTag(null, "persons");

serializer.endDocument();

outStream.flush();

outStream.close();

}

public static void savePersonsWriter(List<Person> persons, Writer writer) throws Exception {

XmlSerializer serializer = Xml.newSerializer();

serializer.setOutput(writer);

serializer.startDocument("UTF-8", true);

serializer.startTag(null, "persons");

for(Person person : persons){

serializer.startTag(null, "person");

serializer.attribute(null, "id", person.getId().toString());

serializer.startTag(null, "name");

serializer.text(person.getName());

serializer.endTag(null, "name");

serializer.startTag(null, "age");

serializer.text(person.getAge().toString());

serializer.endTag(null, "age");

serializer.endTag(null, "person");

}

serializer.endTag(null, "persons");

serializer.endDocument();

writer.flush();

writer.close();

}

public List<Person> getPersons(InputStream is) throws Exception{

List<Person> persons = null;

Person person = null;

XmlPullParser parser = Xml.newPullParser();

parser.setInput(is, "UTf-8");

//产生第一个事件

int eventType = parser.getEventType();

//判断是不是文档结束事件

while(eventType != XmlPullParser.END_DOCUMENT){

switch (eventType) {

//开始文档

case XmlPullParser.START_DOCUMENT:

persons = new ArrayList<Person>();

break;

//开始元素

case XmlPullParser.START_TAG:

//获取解析器当前指向的元素名称

String name = parser.getName();

if("person".equals(name)){

person = new Person();

//获取解析器当前指向的元素的第一个属性的值

person.setId(new Integer(parser.getAttributeValue(0)));

}

if(person != null){

if("name".equals(name)){

//获取解析器当前指向的元素的下一个文本节点的值

person.setName(parser.nextText());

}else if("age".equals(name)){

person.setAge(new Short(parser.nextText()));

}

}

break;

//结束元素

case XmlPullParser.END_TAG:

String pname = parser.getName();

if("person".equals(pname)){

persons.add(person);

person = null;

}

break;

default:

break;

}

//进入下一个事件

eventType = parser.next();

}

return persons;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: