1、第第7 7章章 AndroidAndroid中的数据存取中的数据存取数据存储实例数据存储实例7.1 文件存储文件存储 android是基于是基于java语言的,在语言的,在java中提供了一套完整中提供了一套完整的输入输出流操作体系,与文件相关的有的输入输出流操作体系,与文件相关的有FileInputStream,FileOutputStream等,通过这些类可等,通过这些类可以非常方便地访问磁盘上的文件内容。同样的以非常方便地访问磁盘上的文件内容。同样的android也也支持这种方式来访问手机上的文件。支持这种方式来访问手机上的文件。Android手机中的文手机中的文件有两个存储位置:件有两
2、个存储位置:内置存储空间内置存储空间和和外部外部SD卡卡,针对不同,针对不同位置的文件的存储的有所不同,下面分别对它们的操作。位置的文件的存储的有所不同,下面分别对它们的操作。DiagramContextContext提供了如提供了如下两个方法来打下两个方法来打开本应用程序的开本应用程序的数据文件夹里的数据文件夹里的文件文件IOIO流。流。FileInputStreamFileInputStream openFileInputopenFileInput(String name):(String name):打开打开应用程序的数据文件夹下的应用程序的数据文件夹下的namename文件文件对应输入
3、流。对应输入流。FileOutputStream FileOutputStream openFileOutputopenFileOutput(String name,int(String name,int mode):mode):打开应用程序的数据文件夹下打开应用程序的数据文件夹下的的namename文件对应输出流。文件对应输出流。第一参数用于指定文件名称指定文件名称,不能包含路径分隔符不能包含路径分隔符“/”/”,如果文件不存在,Android Android 会自动创建它会自动创建它。第二参数用于指定操作模式指定操作模式,有四种模式。uContext.MODE_PRIVATE=Contex
4、t.MODE_PRIVATE=0 0:默认操作模式默认操作模式,代表该文件,代表该文件是私有数据,只能被应用本身访问,在该模式下,是私有数据,只能被应用本身访问,在该模式下,写入的写入的内容会覆盖原文件的内容内容会覆盖原文件的内容,如果想把新写入的内容追加到,如果想把新写入的内容追加到原文件中,可以使用原文件中,可以使用Context.MODE_APPEND Context.MODE_APPEND。uContext.MODE_APPEND=Context.MODE_APPEND=3276832768:模式会检查文件是否存在,模式会检查文件是否存在,存在就往文件存在就往文件追加内容,否则就创建新
5、文件追加内容,否则就创建新文件;uContext.MODE_WORLD_READABLE=Context.MODE_WORLD_READABLE=1 1:表示当前文件表示当前文件可以可以被其他应用读取被其他应用读取;uContext.MODE_WORLD_WRITEABLE=Context.MODE_WORLD_WRITEABLE=2 2:表示当前文件表示当前文件可以可以被其他应用写入被其他应用写入。7.1.17.1.1 手机内置存储空间文件的存取手机内置存储空间文件的存取如果希望如果希望文件被其他应用读和写文件被其他应用读和写,可以传入,可以传入:Context.MODE_WORLD_REA
6、DABLE+Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE Context.MODE_WORLD_WRITEABLE 应用程序的数据文件默认保存在应用程序的数据文件默认保存在/data/data/data/data/files/files目录下,文件的后缀名随意。目录下,文件的后缀名随意。7.1.17.1.1 手机内置存储空间文件的存取手机内置存储空间文件的存取在手机内置存储空间中创建文件、写入内容的一般步骤在手机内置存储空间中创建文件、写入内容的一般步骤:(1 1)调用)调用openFileOutput()openFileOu
7、tput()方法,传入文件的名称和操作方法,传入文件的名称和操作的模式,该方法将会的模式,该方法将会返回一个文件输出流返回一个文件输出流;(2 2)调用)调用writewrite()()方法,向这个文件输出流中方法,向这个文件输出流中写入内容写入内容;(3 3)调用)调用closeclose()()方法,方法,关闭文件输出流关闭文件输出流。读取手机内置存储空间中文件的一般步骤:读取手机内置存储空间中文件的一般步骤:(1 1)调用)调用openFileInput()openFileInput()方法,传入需要读取数据的文方法,传入需要读取数据的文件名,该方法将会返回一个文件输入流对象;件名,该方
8、法将会返回一个文件输入流对象;(2 2)调用)调用read()read()方法方法读取文件的内容读取文件的内容;(3 3)调用)调用close()close()方法,方法,关闭文件输入流关闭文件输入流。7.1.17.1.1 手机内置存储空间文件的存取手机内置存储空间文件的存取 1 1、当我们手机上不存在该文件时,我们、当我们手机上不存在该文件时,我们先写后读先写后读与与先先读后写读后写有区别吗?程序会不会出错?有区别吗?程序会不会出错?(具体做法具体做法:把手机上的:把手机上的content.txtcontent.txt文件删除,然后分别进文件删除,然后分别进行先写后读与先读后写操作,观察效果
9、)。行先写后读与先读后写操作,观察效果)。2 2、不同操作模式的区别,当我们多次执行写入操作时,、不同操作模式的区别,当我们多次执行写入操作时,文件里的内容文件里的内容是是被覆盖被覆盖还是不断的在文件末尾还是不断的在文件末尾附加新数据附加新数据?(具体做法具体做法:修改修改openFileOutput()openFileOutput()方法的第二个参数方法的第二个参数)。)。7.1.17.1.1 手机内置存储空间文件的存取手机内置存储空间文件的存取 单击单击writewrite按钮按钮,将第一个文本编辑框,将第一个文本编辑框(writeText)(writeText)的内容的内容写入到指定的文
10、件中写入到指定的文件中(content.txtcontent.txt),单击),单击readread按按钮钮,从指定的文件中从指定的文件中(content.txt)(content.txt)读取数据并显示在第二读取数据并显示在第二个文本框个文本框(readText)(readText)上上。7.1.1 7.1.1 案例案例程序清单:程序清单:FileTestFileTest resres layoutlayout activity_main.xmlactivity_main.xmlLinearLayout xmlns:android=http:/ android:orientation=ver
11、tical EditText android:hint=string/hint/Button android:text=string/write/设置文本输入框最少为两行设置文本输入框最少为两行设置文本输入框的提示信息设置文本输入框的提示信息7.1.1 7.1.1 案例案例 EditText android:hint=string/readhint/Button android:text=string/read/程序清单:程序清单:FileTestFileTest resres layoutlayout activity_main.xmlactivity_main.xml7.1.1 7.1.1
12、 案例案例 在在MainActivity.javaMainActivity.java中分别为写入内容和读取内容按钮添加事件处理中分别为写入内容和读取内容按钮添加事件处理.程序清单:程序清单:FileTestFileTest srcsrc ietiet jxufejxufe cncn androidandroid MainActivity.javaMainActivity.java public class MainActivity extends Activity public class MainActivity extends Activity private Button read,wr
13、ite;private Button read,write;private EditText readText,writeText;private EditText readText,writeText;private String fileName=content.txt;private String fileName=content.txt;public void onCreate(Bundle savedInstanceState)public void onCreate(Bundle savedInstanceState)super.onCreate(savedInstanceStat
14、e);super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);setContentView(R.layout.activity_main);read=(Button)findViewById(R.id.read);read=(Button)findViewById(R.id.read);write=(Button)findViewById(R.id.write);write=(Button)findViewById(R.id.write);readText=(EditText)findViewById(
15、R.id.readText);readText=(EditText)findViewById(R.id.readText);writeText=(EditText)findViewById(R.id.writeText);writeText=(EditText)findViewById(R.id.writeText);read.setOnClickListener(new OnClickListener()read.setOnClickListener(new OnClickListener()public void onClick(View v)public void onClick(Vie
16、w v)readText.setText(read();readText.setText(read();););设置保存的文件名设置保存的文件名获取读取内容按钮获取读取内容按钮获取写入内容按钮获取写入内容按钮添加事件处理添加事件处理将读取的内容显示在文本编辑框上将读取的内容显示在文本编辑框上7.1.1 7.1.1 案例案例 write.setOnClickListener(new OnClickListener()write.setOnClickListener(new OnClickListener()public void onClick(View v)public void onClic
17、k(View v)write(writeText.getText().toString();write(writeText.getText().toString();););public void write(String content)public void write(String content)try try FileOutputStream fos=openFileOutput(fileName,FileOutputStream fos=openFileOutput(fileName,Context.MODE_APPEND);Context.MODE_APPEND);当第二个参数为
18、当第二个参数为Context.MODE_PRIVATEContext.MODE_PRIVATE时,后写入的内容会覆盖原有内容。时,后写入的内容会覆盖原有内容。PrintStream ps=new PrintStream(fos);PrintStream ps=new PrintStream(fos);ps.print(content);ps.print(content);catch(Exception e)catch(Exception e)e.printStackTrace();e.printStackTrace();将文本编辑框的内容写入文件将文本编辑框的内容写入文件该方法将字符串内容写入
19、文件该方法将字符串内容写入文件程序清单:程序清单:FileTestFileTest srcsrc ietiet jxufejxufe cncn androidandroid MainActivity.javaMainActivity.java7.1.1 7.1.1 案例案例 public String read()public String read()StringBuilder sbBuilder=new StringBuilder();StringBuilder sbBuilder=new StringBuilder();try try FileInputStream is=openFil
20、eInput(fileName);FileInputStream is=openFileInput(fileName);byte buffer=new byte64;byte buffer=new byte64;int hasRead;int hasRead;while(hasRead=is.read(buffer)!=-1)while(hasRead=is.read(buffer)!=-1)sbBuilder.append(new String(buffer,0,hasRead);sbBuilder.append(new String(buffer,0,hasRead);catch(Exce
21、ption e)catch(Exception e)e.printStackTrace();e.printStackTrace();return sbBuilder.toString();return sbBuilder.toString();程序清单:程序清单:FileTest/src/iet/jxufe/cn/android/MainActivity.javaFileTest/src/iet/jxufe/cn/android/MainActivity.java该方法用于读取文件信息,并以字符串返回该方法用于读取文件信息,并以字符串返回获取文件输入流获取文件输入流定义缓冲区的大小定义缓冲区的
22、大小记录每次读取的字节数记录每次读取的字节数 对于手机而言,内存非常宝贵,也是比较小的。内存空对于手机而言,内存非常宝贵,也是比较小的。内存空间会影响到手机的运行速度,通常不建议将数据保存到手机间会影响到手机的运行速度,通常不建议将数据保存到手机内存中,特别是一些比较大的资源如图片、音频、视频等。内存中,特别是一些比较大的资源如图片、音频、视频等。那么这些资源存放在哪里呢?存放在外存上,几乎所有的那么这些资源存放在哪里呢?存放在外存上,几乎所有的AndroidAndroid设备,都会配有外存设备,最常见的就是设备,都会配有外存设备,最常见的就是SDSD卡。可卡。可以把以把SDSD卡看作是卡看作
23、是移动硬盘或移动硬盘或U U盘盘。读取读取SDSD卡上的文件和读取手机上的文件类似,都是通过卡上的文件和读取手机上的文件类似,都是通过文件操作流的方式读取的,文件操作流的方式读取的,AndroidAndroid中没有提供单独的中没有提供单独的SDSD卡卡文件操作类,直接文件操作类,直接使用使用JavaJava中的文件操作中的文件操作即可,关键是如何即可,关键是如何确定文件的位置。因为确定文件的位置。因为SDSD卡的可移动性卡的可移动性,因此,在访问之前,因此,在访问之前,需要需要验证手机的验证手机的SDSD卡的状态卡的状态。要想在模拟器中使用要想在模拟器中使用SDSD卡,首先需要卡,首先需要创
24、建一张创建一张SDSD卡卡(当然当然不是真的不是真的SDSD卡,只是一个镜像文件卡,只是一个镜像文件)。创建)。创建SDSD卡可以在卡可以在EclipseEclipse创建模拟器时随同创建创建模拟器时随同创建,也可以使用,也可以使用AndroidAndroid提供的命提供的命令令在命令行进行创建在命令行进行创建。打开命令行窗口打开命令行窗口进入进入android SDKandroid SDK安装路径的安装路径的toolstools目录目录下,下,输入以下命令在输入以下命令在D D盘创建一张容量为盘创建一张容量为2G2G的的SDSD卡,卡,文件后缀名可文件后缀名可以随便取以随便取,建议使用,建议
25、使用.img.img,生成的文件为镜像文件。如果你在,生成的文件为镜像文件。如果你在环境变量中添加了环境变量中添加了Android toolsAndroid tools目录,则可直接输入相应的目录,则可直接输入相应的命令即可。命令即可。mksdcard 2048M D:sdcard.imgmksdcard 2048M D:sdcard.img7.1.2 7.1.2 SDSD卡文件存取卡文件存取读、写读、写SDSD卡上的文件步骤如下:卡上的文件步骤如下:1 1、调用、调用EnvironmentEnvironment的的getExternalStorageState()getExternalSto
26、rageState()方法方法判判断手机上是否插入了断手机上是否插入了SDSD卡卡,并且应用程序,并且应用程序具有读写具有读写SDSD卡的权限卡的权限。Environment.getExternalStorageState()Environment.getExternalStorageState()方法用于方法用于获取获取SDCardSDCard的状态的状态,如果手机装有,如果手机装有SDCardSDCard,并且可以进行读写,那么方法返,并且可以进行读写,那么方法返回的状态等于回的状态等于Environment.MEDIA_MOUNTEDEnvironment.MEDIA_MOUNTED。2
27、 2、调用、调用EnvironmentEnvironment的的getExternalStorageDirectory()getExternalStorageDirectory()方方法来获取外部存储器,也就是法来获取外部存储器,也就是SDSD卡的目录卡的目录。3 3、使用、使用FileInputStreamFileInputStream、FileOutputStreamFileOutputStream、FileReaderFileReader、FileWriterFileWriter读、写读、写SDSD卡里的文件。卡里的文件。7.1.2 7.1.2 SDSD卡文件存取卡文件存取注意:注意:文
28、件读取之前,应确认文件读取之前,应确认手机上已插入手机上已插入SDSD卡卡,对于模拟器来,对于模拟器来说,可以说,可以通过通过mksdcardmksdcard命令命令来创建虚拟存储卡;来创建虚拟存储卡;为了读、写为了读、写SDSD卡上的数据,必须在应用程序的清单文件卡上的数据,必须在应用程序的清单文件(AndroidManifest.xmlAndroidManifest.xml)中)中添加读、写添加读、写SDSD卡的权限卡的权限。在在SDCardSDCard中创建与删除文件权限中创建与删除文件权限 uses-permission”/往往SDCardSDCard写入数据权限写入数据权限 uses
29、-permission”/7.1.2 7.1.2 SDSD卡文件存取卡文件存取7.1.2 7.1.2 案例案例 下面仍然以上面的程序为例,只是这次将数据写入到下面仍然以上面的程序为例,只是这次将数据写入到SDSD卡上的文件,程序卡上的文件,程序界面布局一致,在此不再列出。界面布局一致,在此不再列出。关键代码区别在于,在读写之前需先判断手机关键代码区别在于,在读写之前需先判断手机上是否存在上是否存在SDSD卡卡,然后运用,然后运用javajava的输入输出流技术进行读写操作,关键代码如的输入输出流技术进行读写操作,关键代码如下:下:public class MainActivity extend
30、s Activity public class MainActivity extends Activity private Button read,write;private Button read,write;private EditText readText,writeText;private EditText readText,writeText;private String fileName=content.txt;private String fileName=content.txt;public void onCreate(Bundle savedInstanceState)pub
31、lic void onCreate(Bundle savedInstanceState)super.onCreate(savedInstanceState);super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);setContentView(R.layout.activity_main);read=(Button)findViewById(R.id.read);read=(Button)findViewById(R.id.read);write=(Button)findViewById(R.id.wr
32、ite);write=(Button)findViewById(R.id.write);readText=(EditText)findViewById(R.id.readText);readText=(EditText)findViewById(R.id.readText);writeText=(EditText)findViewById(R.id.writeText);writeText=(EditText)findViewById(R.id.writeText);read.setOnClickListener(new OnClickListener()read.setOnClickList
33、ener(new OnClickListener()public void onClick(View v)public void onClick(View v)readText.setText(read();readText.setText(read();););程序清单:程序清单:SDCardFileTestSDCardFileTest srcsrc ietiet jxufejxufe cncn androidandroid MainActivity.javaMainActivity.java7.1.2 7.1.2 案例案例 write.setOnClickListener(new OnCl
34、ickListener()write.setOnClickListener(new OnClickListener()public void onClick(View v)public void onClick(View v)write(writeText.getText().toString();write(writeText.getText().toString();););public void write(String content)public void write(String content)try if(Environment.getExternalStorageState(
35、).equals(try if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)Environment.MEDIA_MOUNTED)File sdCardDir=Environment.getExternalStorageDirectory();File sdCardDir=Environment.getExternalStorageDirectory();File destFile=new File(sdCardDir.getCanonicalPath()File destFile=new File
36、(sdCardDir.getCanonicalPath()+File.separator+fileName);+File.separator+fileName);System.out.println(System.out.println(*+destFile.getAbsolutePath();+destFile.getAbsolutePath();RandomAccessFile raf=new RandomAccessFile(destFile,rw);RandomAccessFile raf=new RandomAccessFile(destFile,rw);raf.seek(destF
37、ile.length();raf.seek(destFile.length();raf.write(content.getBytes();raf.write(content.getBytes();raf.close();raf.close();catch(Exception e)catch(Exception e)e.printStackTrace();e.printStackTrace();向文件中写入内容向文件中写入内容判断手机中判断手机中SDSD卡状态卡状态获取获取SDSD卡目录卡目录根据路径和文件名创建文件根据路径和文件名创建文件把指针定位到文件末尾把指针定位到文件末尾在文件末尾追加新
38、的内容在文件末尾追加新的内容关闭文件关闭文件程序清单:程序清单:SDCardFileTestSDCardFileTest srcsrc ietiet jxufejxufe cncn androidandroid MainActivity.javaMainActivity.java public String read()public String read()StringBuilder sbBuilder=new StringBuilder();StringBuilder sbBuilder=new StringBuilder();try try if(Environment.getExter
39、nalStorageState().if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)equals(Environment.MEDIA_MOUNTED)File sdCard=Environment.getExternalStorageDirectory();File sdCard=Environment.getExternalStorageDirectory();File destFile=new File(sdCard.getCanonicalPath()File destFile=new F
40、ile(sdCard.getCanonicalPath()+File.separator+fileName);+File.separator+fileName);FileInputStream fis=new FileInputStream(destFile);FileInputStream fis=new FileInputStream(destFile);byte buffer=new byte64;byte buffer=new byte64;int hasRead;int hasRead;while(hasRead=fis.read(buffer)!=-1)while(hasRead=
41、fis.read(buffer)!=-1)sbBuilder.append(new String(buffer,0,hasRead);sbBuilder.append(new String(buffer,0,hasRead);return sbBuilder.toString();return sbBuilder.toString();catch(Exception e)e.printStackTrace();catch(Exception e)e.printStackTrace();return null;return null;7.1.2 7.1.2 案例案例判断手机中是否存在可用的判断手
42、机中是否存在可用的SDSD卡卡从文件中读取内容从文件中读取内容判断手机中是否存判断手机中是否存在可用的在可用的SDSD卡卡创建文件输入流创建文件输入流定义临时缓存区大小定义临时缓存区大小记录每次读取的字节大小记录每次读取的字节大小不断循环直到文件末尾不断循环直到文件末尾在字符串后追加内容在字符串后追加内容程序清单:程序清单:SDCardFileTestSDCardFileTest srcsrc ietiet jxufejxufe cncn androidandroid MainActivity.javaMainActivity.java 程序中程序中raf.seek(destFile.leng
43、th()raf.seek(destFile.length()用于用于将文件的指针将文件的指针定位到文件的末尾定位到文件的末尾,从而实现,从而实现将新内容附加到文件的目的将新内容附加到文件的目的。如。如果没有这句代码,多次向文件中写入内容时,后写的内容会替果没有这句代码,多次向文件中写入内容时,后写的内容会替换前面的内容。读取操作时,采用的是简单的文件输入输出流,换前面的内容。读取操作时,采用的是简单的文件输入输出流,每次都是读取整个文件内容。每次都是读取整个文件内容。JavaJava的的RandomAccessFileRandomAccessFile类支持类支持随机访问文件内容随机访问文件内容,主要,主要是通过是通过seek()seek()方法来方法来设定文件指针的位置设定文件指针的位置,每次读写内容时,每次读写内容时,都是都是从该指针处开始进行读取从该指针处开始进行读取的,从而实现了随机访问该文件的,从而实现了随机访问该文件内容的功能。该类还有一个特点,就是内容的功能。该类还有一个特点,就是既可以读也可以写既可以读也可以写,创,创建时需指定它的模式。详细用法可查看建时需指定它的模式。详细用法可查看JavaJava帮助文档。帮助文档。SDSD卡中文件保存在卡中文件保存在/mnt/sdcard/mnt/sdcard目录下。目录下。7.1.2 7.1.2 SDSD卡文件存取卡文件存取