《Android 3D游戏开发技术宝典——OpenGL ES 2.0》——2.4节文件I/O

简介:

本节书摘来自异步社区《Android 3D游戏开发技术宝典——OpenGL ES 2.0》一书中的第2章,第2.4节文件I/O,作者 吴亚峰,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.4 文件I/O
Android 3D游戏开发技术宝典——OpenGL ES 2.0
I/O即输入与输出,几乎所有文件操作的工作都离不开I/O。对于Android游戏开发来说,I/O操作尤为重要,游戏中的地图数据、人物图片资源等的流畅读取是保证游戏可玩性的重要方面。因此在开发时,不同的场合必须选用合适的I/O操作方式,才能保证满足用户的需求。

Android中文件I/O分为3种方式:SD卡文件读取、手机中文件夹的访问和应用程序中Assets文件的读取,本节将结合简单的小案例对这几种文件I/O操作进行介绍。

2.4.1 访问SD卡中的文件
伴随着游戏品质的不断提高,游戏数据占用的存储空间也成几何级数增加,以往几十KB、几MB的手机游戏已经发展为几十MB、几百MB甚至几个GB的大型手机游戏。为了适应存储需求的增长,SD卡也一直在进行更新换代,4GB、8GB、16GB大小的SD卡已随处可见。

Android的设计者自然不会忽略这一点,在Android平台上可以轻松地对手机SD卡中的文件进行读取和操作。下面通过一个案例来详细讲解在Android开发中如何访问SD卡中的文件。

1.案例的运行效果
运行本小节案例Sample2_5,在输入框中输入要读取的文件名,然后单击“打开文件”按钮。若SD卡中存在该文本文件,则在文本区域显示出文件的内容,反之则提示未找到该文件。本案例的运行效果如图2-15、图2-16所示。


a9ff80f73452ac5bcd99331e0183341268c7f8cd

提示 运行本案例时要注意SD卡中文本文件的编码格式,在Android系统中一般要采用UTF-8编码才能保证没有乱码的出现。编码格式为UTF-8的文本文件见随书光盘中源代码/第2章目录下的AndroidIO.txt,读者可以将该文件导入到手机或模拟器的SD卡中再对本案例进行测试。
2.案例的开发
介绍完本案例的运行效果以及文本文件编码的注意事项后,接下来将对本案例的主控制类Sample2_5_Activity进行开发,其代码如下。

1 package com/bn/pp5;
2 import java.io.File;          //引入相关包
3 public class Sample2_5_Activity extends Activity {   //创建Activity   
4     @Override
5     public void onCreate(Bundle savedInstanceState) {   //重写onCreate方法
6         super.onCreate(savedInstanceState);
7         setContentView(R.layout.main);      //跳转到主界面
8         Button ok=(Button)this.findViewById(R.id.Button01); //获取打开Button
9         ok.setOnClickListener(        //为打开按钮添加监听器
10           new OnClickListener(){
11           public void onClick(View v) {
12     EditText et1=(EditText)findViewById(R.id.EditText01);
13     String nr=loadText(et1.getText().toString().trim());
14     EditText et2=(EditText)findViewById(R.id.EditText02);
15     et2.setText(nr);      //设置显示框内容
16   }});}    
17     public String loadText(String name){     //加载SD卡文件方法
18        String nr=null;        //内容字符串
19      try{
20       File f=new File("/sdcard/"+name);    //创建对应文件
21          byte[] buff=new byte[(int) f.length()];   //创建响应大小的byte数组
22   FileInputStream fis=new FileInputStream(f);
23   fis.read(buff);        //读入文件
24   fis.close();         //关闭输入流
25   nr=new String(buff,"utf-8");     //转码生成字符串
26   nr=nr.replaceAll("\\r\\n","\n");     //替换换行符
27      }catch (Exception e) {
28   Toast.makeText(getBaseContext(),    //Toast提示用户
29      "对不起,没有找到指定文件。", 
30      Toast.LENGTH_LONG).show();
31  }
32  return nr;           //返回内容字符串    
33 }}

第8-16行为打开文件按钮添加监听器,监听器功能为首先获取文本框中用户输入的文件名,然后调用从SD卡加载文本文件的方法,获取SD卡中的对应文件内容并送入EditText控件显示。
第17-32行为加载SD卡中文本文件的方法,其入口参数为要加载文件的文件名。工作过程为首先用Java 标准的I/O操作来加载指定文本文件中的数据,然后将数据编码为字符串,并替换换行符等空白字符,最后返回加载的内容。

提示 通过上面的小案例可以看出,Android中对SD卡文件的I/O与标准Java相同,因此开发成本很低,易于上手。

2.4.2 访问手机中的文件夹
前一小节中是将文件存放到SD卡中,其实文件也可以存放在手机内部存储(ROM,相当于PC的硬盘)中。不过在Android系统中,其为每个应用程序在手机的ROM中都分配了一个私有的目录,命名规则为“/data/data/<应用程序的包名>”。例如,应用程序的包名为“com.bn”,则系统分配的私有目录为“/data/data/com.bn”。

应用程序开发时,若需要在ROM中存放文件,一般应该存放到系统分配的私有目录中。启动Eclipse,进入其中的DDMS面板,打开File Explorer,即可查看手机ROM中的文件组织情况,如图2-17所示。


p><p><div style=
de51769520630d1a69b6988a965bbb9a282667d9

说明 图2-18为程序一开始运行,显示“/”目录下内容的情况。图2-19为单击进入了dev目录,图2-20为单击了不允许进入或不是文件夹的条目。
了解了本案例的运行效果之后,接下来对本案例中唯一的类——Sample2_6_Activity进行开发,具体代码如下。

1 package com.bn.pp6;         //声明包
2 import java.io.File;          //引入相关类
3 ……//此处省略了部分类的引入代码,读者可自行查看随书光盘的源代码
4 import android.widget.AdapterView.OnItemClickListener; //引入相关类
5 public class Sample2_6_Activity extends Activity {  // 创建Activity
6  String currPath;          // 当前路径字符串
7  String rootPath = "/";        // 根目录路径
8  TextView currDirTV;        //显示当前路径的TextView引用
9  @Override
10  public void onCreate(Bundle savedInstanceState) {
11   super.onCreate(savedInstanceState);
12   setContentView(R.layout.main);      // 跳转到主界面
13   final ListView lv = (ListView) this.findViewById(R.id.lv); // 获取ListView
14   Button back = (Button) this.findViewById(R.id.back);  // 获取返回按钮
15   final File[] files = getFiles(rootPath); 
            // 调用getFiles方法获取根目录下文件列表
16   currDirTV = (TextView) this.findViewById(R.id.currDirTV); // 获取ListView
17   currPath = rootPath;
18   currDirTV.setText("当前路径:" + currPath);  //设置当前路径
19   initListView(files, lv);       // 初始化显示列表
20   back.setOnClickListener       // 返回按钮监听器
21   (new OnClickListener() {
22    @Override
23    public void onClick(View v) {
24     if (!currPath.equals(rootPath)) {// 若当前路径不是根目录,返回到上一层目录
25      File f = new File(currPath);  // 获取当前路径下的文件列表
26      f = f.getParentFile();   // 获取当前路径的上层路径
27      currPath = f.getPath();   // 更改当前路径
28      currDirTV.setText("当前路径:" + currPath);//设置当前路径
29      initListView(getFiles(currPath), lv);  // 初始化显示列表
30  }}});}
31            // 获取当前目录下的文件列表的方法
32  public File[] getFiles(String filePath) {
33   File[] files = new File(filePath).listFiles(); // 获取当前目录下的文件列表
34   return files;        // 返回文件列表
35  }
36  ……//此处省略了初始化ListView的方法,读者可以自行查阅随书光盘中的源代码
37 }

第9-30行为案例整体功能的实现代码。程序运行时,首先调用initListView方法初始化文件显示列表,显示根目录下的文件情况。然后给“返回上一层”按钮添加了监听器,监听器功能为若存在上一层目录,则刷新文件显示列表为上一层目录下的情况。
第32-35行为获取当前路径下所有文件列表的方法。该方法中首先需要获得当前路径对应的File对象,之后返回其下对应的文件列表。

提示 由于篇幅所限,初始化文件列表的代码省略,有需要的读者请自行查阅光盘中的源代码进行学习。

2.4.3 读取assets文件夹下的内容
Android还支持将应用程序所需数据文件打包到apk文件中,省去了使用者安装应用程序后还需要下载数据包的情况。但是要注意的是,打包到apk文件中的数据文件并不是可以放在任何位置,一般应该放到项目中的assets文件夹下。

提示 对于特别大(例如50MB)的数据文件,在实际开发中一般还是与apk安装文件分开的。对于不大的数据文件,就非常适合打包到apk包中的assets文件夹下。
下面将通过一个小案例来说明如何编程访问assets文件夹下的内容,其主要功能是完成对应用程序内部的assets文件夹下文件的读取。操作过程为在案例初始界面可以输入文件名,然后单击打开按钮。若存在该文件,则在下方显示出文件内容;反之则弹出Toast提示用户重新输入。案例运行效果如图2-21、图2-22所示。

了解了本案例的功能后,下面来介绍本案例的开发过程,具体步骤如下。

(1)首先将AndroidIO.txt文本文件复制到项目中的assets文件夹中,如图2-23所示。


6cd71e66b90b6a7859b40049de935f33c3e6b7cf


65a56acdf687a2205b012e27d99a59d923fb0700

(2)将AndroidIO.txt文本文件复制到项目中的assets文件夹后,接下来将开发本案例中唯一的类Sample2_7_Activity,其代码如下。

1   package com/bn/pp7;
2   import java.io.ByteArrayOutputStream;      //引入相关包
3   public class Sample2_7_Activity extends Activity {   //创建Activity
4     public void onCreate(Bundle savedInstanceState) {   //重写onCreate方法
5         super.onCreate(savedInstanceState);
6         setContentView(R.layout.main);      //跳转到主界面        
7         Button ok=(Button)this.findViewById(R.id.Button01); //获取打开按钮的引用
8         ok.setOnClickListener(        //为打开按钮添加监听器
9            new OnClickListener(){
10           public void onClick(View v){
11     EditText et1=(EditText)findViewById(R.id.EditText01);
12     String nr=loadText(et1.getText().toString().trim());
13     EditText et2=(EditText)findViewById(R.id.EditText02);
14     et2.setText(nr);//设置显示框内容
15    }});}    
16     public String loadText(String name){     //加载assets文件方法
17       String nr=null;            //内容字符串
18       try{
19        InputStream is=this.getResources().getAssets().open(name);
20        int ch=0;
21        ByteArrayOutputStream baos=new ByteArrayOutputStream();
22        while((ch=is.read())!=-1) {
23         baos.write(ch);//读取文件
24        }      
25        byte[] buff=baos.toByteArray();   //转化为字节数组
26        baos.close();        //关闭输入输出流
27        is.close();        //关闭输入输出流
28    nr=new String(buff,"utf-8");    //转码生成新字符串
29    nr=nr.replaceAll("\\r\\n","\n");   //替换换行符等空白字符
30   }catch (Exception e){       //没有找到对应文件,进行提示
31    Toast.makeText(getBaseContext(), 
32       "对不起,没有找到指定文件。", 
33       Toast.LENGTH_LONG).show();
34   }
35   return nr;            //返回内容字符串
36     }}

第7-15行首先获取了打开按钮的引用,然后给此按钮添加了监听器。监听器的功能为读取用户输入名称的文件内容,并显示到界面上。
第16-36行为从assets中加载指定名称文本文件的方法,其首先获取了指向指定文件的输入流,然后从输入流中读取数据,接着将数据编码为字符串,并替换换行符等空白字符,最后返回加载的内容。

提示 通过上述几个小节案例的介绍,相信读者对Android平台下文件的存储和读取已经有所掌握。在真正的开发过程中,开发人员应该考虑各方面的因素,在需要时采用最适合自己的存储方式进行存储。

相关文章
|
19天前
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
|
3月前
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
215 1
|
5月前
|
存储 数据库 Android开发
安卓Jetpack Compose+Kotlin,支持从本地添加音频文件到播放列表,支持删除,使用ExoPlayer播放音乐
为了在UI界面添加用于添加和删除本地音乐文件的按钮,以及相关的播放功能,你需要实现以下几个步骤: 1. **集成用户选择本地音乐**:允许用户从设备中选择音乐文件。 2. **创建UI按钮**:在界面中创建添加和删除按钮。 3. **数据库功能**:使用Room数据库来存储音频文件信息。 4. **更新ViewModel**:处理添加、删除和播放音频文件的逻辑。 5. **UI实现**:在UI层支持添加、删除音乐以及播放功能。
|
28天前
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
88 0
|
3月前
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
118 1
|
3月前
|
C# Windows 开发者
当WPF遇见OpenGL:一场关于如何在Windows Presentation Foundation中融入高性能跨平台图形处理技术的精彩碰撞——详解集成步骤与实战代码示例
【8月更文挑战第31天】本文详细介绍了如何在Windows Presentation Foundation (WPF) 中集成OpenGL,以实现高性能的跨平台图形处理。通过具体示例代码,展示了使用SharpGL库在WPF应用中创建并渲染OpenGL图形的过程,包括开发环境搭建、OpenGL渲染窗口创建及控件集成等关键步骤,帮助开发者更好地理解和应用OpenGL技术。
183 0
|
3月前
|
存储 监控 数据库
Android经典实战之OkDownload的文件分段下载及合成原理
本文介绍了 OkDownload,一个高效的 Android 下载引擎,支持多线程下载、断点续传等功能。文章详细描述了文件分段下载及合成原理,包括任务创建、断点续传、并行下载等步骤,并展示了如何通过多种机制保证下载的稳定性和完整性。
85 0
|
5月前
|
缓存 Android开发 Kotlin
【安卓app开发】kotlin Jetpack Compose框架 | 先用OKhttp下载远程音频文件再使用ExoPlayer播放
使用 Kotlin 的 Jetpack Compose 开发安卓应用时,可以结合 OkHttp 下载远程音频文件和 ExoPlayer 进行播放。在 `build.gradle` 添加相关依赖后,示例代码展示了如何下载音频并用 ExoPlayer 播放。代码包括添加依赖、下载文件、播放文件及简单的 Compose UI。注意,示例未包含完整错误处理和资源释放,实际应用需补充这些内容。
|
5月前
|
存储 Android开发 Kotlin
开发安卓app OKhttp下载后使用MediaPlayer播放
在Android Jetpack Compose应用程序中,要使用OkHttp下载远程音频文件并在本地播放,你需要完成以下几个步骤: 1. **添加依赖**:确保`build.gradle`文件包含OkHttp和Jetpack Compose的相关依赖。 2. **下载逻辑**:创建一个`suspend`函数,使用OkHttp发起网络请求下载音频文件到本地。 3. **播放逻辑**:利用`MediaPlayer`管理音频播放状态。 4. **Compose UI**:构建用户界面,包含下载和播放音频的按钮。
|
6月前
|
Android开发
【苹果安卓通用】xlsx 和 vCard 文件转换器,txt转vCard文件格式,CSV转 vCard格式,如何批量号码导入手机通讯录,一篇文章说全
本文介绍了如何快速将批量号码导入手机通讯录,适用于企业客户管理、营销团队、活动组织、团队协作和新员工入职等场景。步骤包括:1) 下载软件,提供腾讯云盘和百度网盘链接;2) 打开软件,复制粘贴号码并进行加载预览和制作文件;3) 将制作好的文件通过QQ或微信发送至手机,然后按苹果、安卓或鸿蒙系统的指示导入。整个过程简便快捷,可在1分钟内完成。
152 6