Android数据篇

Android提供了多种方式(XML文件方式、文件方式、数据库方式等)进行数据的存储。开发者可以根据数据类型和设计的需要,选择适当的存储方式进行数据存储。

1.XML文件管理

        XML文件更多的是用来维护应用或系统的配置文件。在Android中,goole提供了SharedPreferences这个轻型的存储类作为XML文件存储的上层接口,其本质上就是<ket, value>值对。

        根据配置信息是否对其他应用开放,SharedPreferences提供了MODE_PRIVATE.、MODE_WORLD_READABLE两种权限。SharedPreferences的操作分为获取配置信息和存储配置信息两种方式。下面是获取配置信息的方法:

                SharedPreferences settings=getSharedPreferences(PREFS_NAME,MODE_PRIVATE);

                boolean silent=settings.getBoolean("silentMode", false);

        存储配置信息和获取配置信息略有不同,下面是存储配置信息的方法:

                SharedPreference settings=getShatedPreferences(PREFS_NAME, MODE_PRIVATE);

                SharedPreference.Editor editor=settings.edit();            //获得编辑器

                editor.putBoolean("silentMode", mSilentMode);

                editor.commit();          //提交

        如果希望配置信息对其他应用开发,在设置权限时,可使用MODE_WORLD_READABLE。在其他应用希望获取相应的配置信息时,必须先获取相应的上下文,方法如下:

                context=createPackageContext("com.miaozl.text", Context.CONTEXT_IGNORE_SECURITY);

                if(context != null){

                        SharedPreference settings=context.getSharedPreference(PREFS_NAME,Context.MODE_WORLD_READABLE);

                        mTest=settings.getString("text", null);

                }

        需要说明的是,在PreferenceActivity中内置了对SharedPreferences的支持。

        如果希望ListPreference保存或查看当前的选择,可以调用的ListPreferences方法如下:

                public void setValue(String value)        //对应“android:entries”属性的值

                public void setValueIndex(int index)        //对应“android:entryValues”属性的值

                public String getValue()

        其他的Preference的操作方法类似于ListPreference。

2.内部文件管理

        对于二进制数据,Android提供了内部存储的方式,开发者可以将数据存储在应用的私有空间中,避免其他程序的访问,内部存储的数据会在应用卸载时删除。

        内部存储的实现非常简单,其权限包括MODE_PRIVATE、MODE_APPEND、MODE_WORLD_READABLE、MODE_WORLD_WRITEABLE等。

        内部存储所在目录为\data\data\com.company.packagename\files。如果文件名为wors,其内部存储的目录为\data\data\com.android.mms\files\words。

        (1)写入数据

                写入字符串数据的方法:

                        FileOutputStream out=context.openFileOutput(file,Context.MODE_WORLD_WRITEABLE);

                        out.write(captureArray.toString().getBytes());

                        out.close();

                写入结构体数据的方法:

                        private static void writeConfiguration(Context context, LocaleConfiguration configuration){

                                DataOutputStream out = null;

                                out=new DataOutputStream(context.openFileOutput(PREFERENCES, MODE_PRIVATE));

                                out.writeUTF(configuration.locale);

                                out.writeInt(configuration.mcc);

                                out.writeInt(configuration.mnc);

                                out.flush();

                      }

        (2)读取数据

                读取字符串数据的方法:

                        StringBuilder sb=new StringBuilder();

                        FileInputStream words=context.openFileInput("word");

                        int c;

                        while((c=words.read()) != -1){

                               if(c=='\r' || c=='\n'){

                                       String word=sb.toString().trim();

                                        if(word.length() > 0){

                                                mWord.add(word);

                                        }

                                        sb.setLength(0);

                              }else{

                                      sb.append((char)c);

                              }

                     }

                     words.close();

                     mWordCount=mWords.size();

                读取数据结构数据的方法:

                        private static void readConfiguration(Context context, LocaleConfiguration configuration){

                                DataInputStream in=null;

                                in=new DataInputStream(context.openFileInput(PREFERENCES));

                                configuration.locale=in,readUTF();

                                configuration.mcc=in.readInt();

                                configuration.mnc=in.readInt();

                                in.close();

                对于应用携带的静态数据,可以放置在应用的assets目录或res、raw目录下。

                对于assets目录下的静态数据,存在单个文件最大仅支持1MB的局限,读取方式:InputStream is=getAssets().open("read_asset.txt");

                对于res、raw目录下的静态数据,读取方式:InputStream.inputStream=resources.openRawResource(R.raw.definitions);

                Android还对创建缓存提供了支持,通过getCacheDir()可以获取应用的缓存路径。在系统可用空间不足时,Android会清空缓存,但对于开发者而言,不应维护过多的缓存。和内部存储一样,在应用卸载时,会清空并删除缓存目录。

3.外部文件管理

         为了便于进行媒体文件的扫描,Android为媒体文件设置了特定目录,目前Android支持DIRECTORY_MUSIC、DIRECTORY_PODCASTS、DIRECTORY_RINGTONES、DIRECTORY_ALARMS、DIRECTORY_NOTIFICATIONS、DIRECTORY_PICTURES、DORECTORY_MOVIES、DIRECTORY_DOWNLOADS等目录。

        Android开始支持在SD卡上的应用私有目录,通过getExtenalFilesDir()可以获取具体路径。该具体路径依赖应用的包名,如com.miaozl.helle,其SD卡上的应用私有目录为\mnt\sdcard\Android\data\com.miaozl.hello\files\。下面是获取图片路径的方法:File path=getExternalFilesDir(Environment.DIRECTORY_PICTURES)。

        如果希望存储在SD上的公共目录下,则可通过getExternalStoragePublicDirectory可以获得公共目录,但需要注意,公共目录的具体路径视需要存储的文件的类型而定。下面是获取公共目录的方法:

                String sdroot=Environment.getExternalStorageDirectory().getAbsolutePath();

                String dwndir=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();

        SD上的应用私有目录和内部存储一样,在应用卸载时,将会被清空并删除。

        如果应用需要的缓存较大,也可以在SD卡上建立缓存目录,通过getExternalCacheDir()可以获取应用在SD卡上的缓存路径。

        在使用SD卡目录时,需要注意SD卡是否挂载,可通过Environment.getExternalStorageState()方法进行判断。如果返回值为Environment.MEDIA_MOUNTED,表示SD卡处于挂载状态,可以放心使用。

4.数据库管理

        通过数据库的方式可以存储复杂的数据,也可以方便对数据的操作,因此数据库存储在Android中非常有用。目前,Android采用SQLite3数据库。SQLite3数据库是一种适合嵌入式平台的轻量级数据库。但是开源版本的SQLite3没有对数据进行加密保护,因此存储敏感数据是一个十分头疼的问题。好在SQLite3在框架层提供了加密算法的接口,有需要的开发者可以自行添加相关的加密算法。

        Android提供了两种SQLite的实现方法,一种是基于Android封装接口来实现的,适合对数据库要求不高或对SQLite不熟悉的开发者;另一种是基于原生SQLite的方法来实现的,可以完全发挥出SQLite的能力,性能稍好,但对SQLite的理解要求较高。至于采用何种实现方法,开发者可以根据应用场和自己对SQLite的理解程度自行把握。

        对于数据读取频繁的场景,必须考虑SQLite的性能,在Android平台上,使用原始SQL语句的执行效率要比封装过的ContentProvider高;对于一次性进行多项处理的场景,应考虑通过事务处理的方式进行批量处理。

        (1)Android封装接口

                考虑到数据库的操作很频繁,在Android中提供了封装类,即SQLiteOpenHelper,通过集成SQLiteOpenHelper,开发者可以很容易地设计和操作数据库。需要注意的是,封装会使Android的性能降低。

                在继承SQLiteOpenHelper时,必须实现onCreate和onUpgrade方法。下面是通过Android封装接口设计数据库的一般步骤:定义数据库名、数据库版本号、数据表名。实现onCreate和onUpgrade方法。实现插入、更新、删除和查询方法。

                实现onCreate方法:

                        public void onCreate(SQLiteDatabase db){

                                db.execSQL("CREATE TABLE "+NOTES_TABLE_NAME+"(" + NoteColumns._ID+ " INTEGER PRIMARY KEY,"+NoteColumns.TITLE+" TEXT,"

                                +NoteColumns.NOTE+" TEXT,"+NoteColumns.CREATED_DATE+" INTEGER," +NoteColumns.MODIFIED_DATE+" INTEGER"+");");

                        }

              实现onUpgrade方法:

                      public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){

                              db.execSQL("DROP TABLE IF EXISTS notes");

                              onCreate(db);

                      }

               事务处理的相关方法:

                       public void begintransaction()

                       public void beginTransactionWithListener(SQLiteTransactionListener transactionListener)

                       public void endTransaction()

                       public boolean inTreansaction()

                       public void setTransactionSuccessful()

        (2)原生方法处理

                 采用raw方法来操作SQLite数据库,可以减少代码和提高处理效率,但必须做好SQL语句异常处理。

                 SQLiteDatabase db;

                 String args[]={id};

                 ContextValue cv=new ContextValues();

                 cv.put("miaozl", id);

                 Cursor c=db.rawQuery("SELECT * FROM table WHERE miaozl =?", args);      //执行本地SQL语句

                 if(c.getCount() !=0){

                 ContextValues cv=new ContextValues();

                 cv.put("miaozl","cwj");

                 db.insert("table", "miaozl", cv);      //插入数据

                 String args[]={id};

                 ContextValues cv2=new ContextValues();

                 cv2.put("miaozl", id);

                 db.delete("table", "miaozl=?", args);

5.数据处理

        进行Android开发,尤其是开发涉及网络的应用时,对数据进行处理是个无法回避的问题。Android采用的是Java数据结构,且基本支持所有的Java数据结构。在本节中,除了讨论基本的Java数据类型外,还将讨论正则表达式、I/O管理、流、JSON等,这些内容对从C/C++迁移过来的开发者非常有用。Java数据结构之间的关系如下图:

               

        Collection和Map是最基本的数据结构。

        所有实现Collection接口的类都必须提供两个标准的构造函数:一个是无参数的构造函数,用于创建空白的Collection;另一个是Collection作为参数的构造函数,用于创建一个新的Collection,这个新的Collecntion与传入的Collection有相同的元素。第二个构造函数允许用户复制一个Collection。

        遍历Collection可以通过iterator方法进行,该方法返回一个迭代因子,利用该迭代因子可逐一访问Collection中的元素。典型用法如下:

                Iterator it=collection.iterator();       //获得一个迭代因子

                while(it.hasNext()){

                        Object obj=it.next();      //得到下一个元素

                }

        由Collection接口派生的两个接口是List和Set。

        (1)Set类

                Set类保持的对象不可重复,Android目前支持的Set类主要包括HashSet、TreeSet、LinkedHashSet等。

                1)HashSet

                        HashSet实现了Set接口和内置哈希表,它不保证集合的迭代顺序。

                        向HashSet中添加集合项的方法:

                                public void addChild(BuildStep child){

                                        if(children == null){

                                                children=new HashSet<BuildStep>();

                                        }

                                       children.add(child)

                                 }

                       HashSet还支持清空、克隆、移除等操作,另外,HashSet还支持从资源文件中加载数组,具体如下:

                              HashSet<String>defaultCorpora=new HashSet<String>();

                              try{

                                      String[]  corpora=mContext.getResource().getStringArray(res);

                                      for(String corpus : corpora){

                                              defaultCorpora.add(corpus);

                                      }

                                      return defaultCorpora;

                             }

                        HashSet不支持线程安全,其集合项可以为null。

                 2)TreeSet

                        TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排列状态。它是J2EE中唯一可实现自动排序的类,TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。向TreeSet中添加集合项的方法:

                                TreeSet smallSet=new TreeSet();      //自然排序

                                for(int i=0; i<50;i++){
                                        smallSet.add(objArray[i]);

                                }

                        对于定制排序的情况,需要先构建一个Comparator类型的排序器,方法如下:

                                public class MyComparator<T> implements Comparator<T>{

                                     public int compare(T arg0, Targ1){
                                             if(arg0.equal(arg1)){

                                                     return 0;

                                             }

                                             return ((Comparable<T> arg0).compare(arg1)*-1;

                                     }

                                }

                                TreeSet<String> treeSet=new TreeSet<String>(myConparator);

                                treeSet.add("A");

                3)LinkedHashSet

                        和HashSet相比,LinkedHashSet中的数据严格按照插入的顺序存放,新增的数据放置在集合的末尾。LinkedHashSet内部通过LinkedHashMap实现,添加集合项的方法:

                                LinkedHashSet<String>ids = new LinkedHashSet<String>();

                                ids.add(TimeZone.getDefault().getID());

                        另外LinkedHashSet还支持清空、复制、移除等操作。具体方法如下:

                                void clear();

                                Object clone();

                                boolean remove(Object object);

                         LinkedHashSet还支持遍历操作,方法如下:

                                 LinkedHashSet<String>addresses=new LinkedHashSet<String>;

                                 Iterator<String> addressIterator=addresses.iterator();

                                 while(addressIterator.hasNext()){

                                         String assress=addressIterator.next();

                                         addressIterator.remove();

                                  }

                         LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是在进行插入曹组时,性能方面稍逊于HashSet。

        (2)Map类

                Map类保存着<key,value>的对应关系。Android目前支持的Map类主要有HashMap、LinkedHashMap和WeakHashMap等。

                1)HashMap

                        HashMap的实现是基于哈希表的,创建HashMap非常简单,方法:Map<String, Boolean>entries=new HashMap<String, Boolean>();

                        如果希望在创建HashMap对象时声明HashMap的容量,方法:Map<AttributedCharcterIterator.Attribute, List<Range>>attributeMap=new HashMap<Attribute,List<Range>>(11);

                        考虑到迭代时间和HashMap的容量和大小成比例,HashMap的初始容量不易设置太大,毕竟当哈希表中的键值对数量超过HashMap的加载因子与HashMap的容量的乘积时,HashMap会自动扩展容量,不会出现容量不够的问题。在默认情况下,HashMap的加载因子为0.75。在创建HashMap对象时,可以自定义HashMap的加载因子。

                        向HashMap中添加键值对的方法:

                                private final Map<AudioStream, Integer> mStream;    

                                mStreams=new HashMap<AudioStream, Integer>();

                                if(!mStreams.containsKey(stream)){        //判断key为“stream”的映射是否存在

                                        int socket=stream.dup();

                                        mStreams.put(stream,socket);

                               }

                        获得HashMap中键值对信息的方法:

                                private final HashMap<String, Integer> mMap;

                                Set<Entry<String, Integer>>mEntries=mMap.entrySet();

                                for(Entry<String, Integer>entry:mEntries){

                                        Integer freg=entry.getValue();

                                        db.delete(AUTODICT_TABLE_NAME, COLUMN_WORD+ "=? AND " + COLUMN_LOCALE+"=?", new String[]{entry.getKey(), mLocale});

                                        if(freq!=null){

                                                db.insert(AUTODICY_TABLE_NAME, null, getContentValues(entry.getKey(),freq, mLocale));

                                       }

                               }

                         HashMap中的另外几个重要方法:

                                 public boolean containsValue(Object value)

                                 public int size()

                                 public boolean isEmpty()

                                 V get(Object key)

                2)LinkedHasMap

                        与HashMap相比,LinkedHashMap维护的是一个具有双重链表的HashMap,LinkedHashMap输出时其键值对是有顺序的,而HashMap输出时其键值对是随机的。对于键值对比较复杂而又要求效率的情况下,最好使用LinkedHashMap。LinkedHashMap支持两种排序方式,一种是插入排序,最近插入的在链表尾部;一种是使用排序,最近使用的会移至链表尾部。

                        private static final float DEFAULT_LOAD_FACTOR=.75F;

                        private final Map<String, AddressCacheEntry>  map;

                        map=new LinkedHashMap<String, AddressCacheEntry>(0, DEFAULT_LOAD_FACTOR, true);    //true表示使用排序,false表示插入排序

                        synchronized(map){

                                map.put(hostname, new AddressCacheEntry(addresses, expiryNanos));

                        }

                        注意,LinkedHashMap并非线程安全的,如果确需实现线程安全,那么可以使用如下方法:

                                Map<String, String>map=Colleations.synchronizedMap(new LinkedHashMap<String, String>)

                3)WeakHashMap

                        WeakHashMap和普通HashMap的不同之处在于其包含的键值对的Key为弱引用,当Key不再被其他对象引用时,相应的键值对可能会被垃圾回收器随时释放。

                        WeakHashMap对象的创建方法:private final WeakHashMap<String, Package>mPackages=new WeakHashMap<String, Package>();

                        WeakHashMap具有的方法和HashMap类似,两者都继承于AbstractMap的。

        (3)list类

                List类存储对象可以重复。Android目前支持的List类主要有ArrayList、LinkedList等。

                1)ArrayList

                        ArrayList是Android中最常用的集合类,本质上是可变数据的实现,允许包括null在内的所有元素。由于插入数据会涉及数组元素的移动,因此所有ArrayList进行数据索引较快,而插入数据较慢。

                        ArrayList<THread>list =new ArrayList<Thread>();

                        for(Node p=tail; p!=null; p=p.prev){

                                Thead t=p.thread;

                                if(t!= null)

                                        list.add(t)

                         }

                        ArrayList也是非线程安全的,和ArrayList类似的一个工具是Vector,所不同的是Vector是线程安全的,其性能比ArrayList稍差。Stack继承自Vector,是一个后进先出的栈。

                2)LinkedList

                        LinkedList利用双向链表实现存储,其插入数据较快,索引数据较慢。

        (4)流类

                Android对流的支持和Java类似,主要有BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter、ByteArrayInputStream、ByteArrayOutputStream、FileInputStream、FileOutputStream、StringReader、StringWriter等。

                1)缓冲流

                        考虑到硬盘存取的速度远低于内存中数据存取速度,为了减小对硬盘的存取,在内存中建立了缓存区,这样可以提高存取的效率。这就是BufferedInputStream、BufferedOutputStream优于InputStream、OutputStream之处。

                         BufferedInputStream和BufferedOutputStream并非改变InputStream和OutputStream等行为,具体的读写仍有InputStream和OutputStream负责。

                         下面是BufferedOutputStream的一个示例:

                                 try{

                                         BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream("\sdcard\a.text"));

                                          for(int i=0; i<200;i++)

                                                  out.write(i);

                                          out.flush();        //写入目标对象

                                 }

                2)字节流

                        在创建实例时ByteArrayInputStream和ByteArrayOutputStream会构建一个byte类型的数组作为缓冲区,以适合传输多个变量的场景。下面是一个示例:

                                CopyOnWriteArrayList q=populatedArray(SIZE);

                                ByteArrayOutputStream bout=new ByteArrayOutputStream(10000);

                                ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(bout));

                                out.writeObject(q);

                                out.close();

                                ByteArrayInputStream bin=new ByteArrayInputStream(bout.toByteArray());

                                ObjectArrayInputStream in=new ObjectInputStream(new BufferedInputStream(bin));

                                CopyOnWriteArrayList r=(CopyOnWriteArrayList)in.readObject();

                3)文件流

                        FileInputStream和FileOutputStream专门用于文件读取,以字节为单位进行流处理,与编码无关,所以不会存在乱码问题。FileReader和FileWriter则以字符为单位进行流处理。下面是一个文件复制的实现:

                                File inFile =new File("source.jpg");

                                File outFile=new File("dest.jpg");

                                FileInputStream inStream=new FileInputStream(inFile);

                                FileOutputStream outStream=new FileOutputStream(outFile);

                                byte[] inOutb=new byte[inStream.available()];

                                inStream.read(inOutb);    //读入流,保存在byte数组

                                outStream.write(inOutb);    //写入流,保存在文件dest.jpg中

                                inStream.close();

                                outStream.close();

                        byte数组的最大存储容量为64MB,当一个文件超过64MB时,需要分多个流进行读写。另外,当在两个不同的线程间进行文件读写时,同步会变得比较困难,这时可以考虑运用管道,即PipedInputStream、PipedOutputStream等。

                        当程序对读写的速率要求较高时,FileChannel会是比FileInputStream/FileOutputStream更好的选择,FileChannel是线程安全的。

                        当需求对内容进行分析时,就需要用到FileReader和FileWriter,他们经常和BufferedReader、BufferedWrite组合使用。FileReader和BufferedReader组合使用的示例如下:

                                BufferedReader input = new BufferedReader(new FileReader(layoutFile));

                                String line;

                                while((line=input.readLine())!=null){

                                }

                        FileWriter和BufferedWriter组合使用的示例如下:

                                BufferedWriter out=null;

                                try{

                                        out=new BufferedWriter(new FileWriter(DOCK_PIN_PATH));

                                        int pin=(int)Math.floor(Math,random()*10000);

                                        mDockPin=String.format("%04d",pin);

                                        out.write(mDockPin);

                                        return true;

                              }

                4)字符串流

                        StringReader和StringWriter是专门针对字符串设计得。StringReader多用于XML的解析的场景。StringReader的用法如下:

                                private static final String XMLFILE=”<feed xmlns='http://www.w3.org/2005/Atom‘><name><id>bob</id></name>"

                                        +"<entry1><id year=\"2009\">james</id></entry1><entry2 year=\"2000\"><id>jim</id></entry2>"

                                        +"<name><id>tom</id></name><name><id>brett</id></name></feed>";

                                SAXParserFactory spfactory=SAXPareserFactory.newInstance();

                                SAXPareser saxPareser=spfactory.newSAXPareser();

                                XMLReader xmlReader=saxPareser.getXMLReader();

                                xmlReader.setContentHandle(root.getContentHander());

                                InputSource source=new InputSource(new StringReader(XMLFILE));

                                xmlReader.parse(source);

                        StringWriter的用法如下:

                                Therowable thrown=r.getThrown();

                                StringWriter sw=new StringWriter();

                                PrintWriter pw=new PrinrWriter(sw);

                                sw.write(r.getMessage());

                                sw.write("\n");

                                throw.printStackTrace(pw);

                                pw.flush();

                                return sw.toString();

                5)正则表达式

                        在Android中使用正则表达式非常简单,相关的类主要有Pattern、Matcher等。对读者来说,最重要的是了解正则表达式的语法规则。下面是几个常用场景的实现

                                String str=“ceponline@yahoo.com.cn";

                                Pattern pattern=Pattern.compile("[\\w\\.\\-]+@([\\w\\-]+\\.)+[\\w\\-]+",Pattern.CASE_INSENSITIVE);

                                Matcher matcher = pattern.matcher(str);

                        替换字符的方式实现:

                                Matcher m=Pattern.compile("[\t\n],").matcher(string);

                                string = m.replaceAll(".").raplace('\n', ' ').replace('\n',' ');

                        查找字符串的实现:

                                private static final Pattern sRepeatedRangePattern=Pattern.compile("Resource entry (.+) already has bag item (.+)\\.");

                                matcher=sRepeatedRangePattern.matcher(message);

                                if(matcher.find()){

                                        String property=matcher,group(2);

                                        return findRange(file, line,property, null);

                                }

        (6)I/O管理

                除了流类型的I/O管理和文件管理外,Android还提供了MemoryFile、FileChannel进行I/O管理。MemoryFile是对Ashmem驱动的封装器,而Ashmem本质上是基于共享内存的。在dev目录下对应的设备为\dev\ashmem。相比于传统的内存分配机制,如malloc,Ashmem的好处是提供了辅助内核内存回收算法的pin\unpin机制,使通过MemoryFile进行I/O操作可以在很大程度上提高效率。

                FileChannel是MMAP的一个上层封装。利用FilehChannel可以更高效地读写文件,而且FileChannel是线程安全的。

                1)MemoryFile

                        创建一个MemoryFile对象即可在共享内存上分配一块区域。通过MemoryFile对象读写数据的方式有流、字节两种。

                         MemoryFile在断言、SQLite等多个领域的读写得到了应用。

                2)FileChannel

                        开发者可以从FileInputStream、FileOutputStream、RandomAccessFile等的对象中获得FileChannel对象,FileChannel是线程安全的。从FileInputStream中得到FileChannel的方法如下:

                                 FileChannel fc=new FileInputStream(new File("temp.tmp")).getChannel();

                                 IntBuffer ib=fc.map(FileChannel.MapMode.READ_ONLY,0,fc.size()).asIntBuffer();

                                 while(ib.hasRemaining())

                                         ib.get();

                                 fc.close();

                         从FileOutputStream、RandomAccessFile等对象获得FileChannel对象的方法和FileInputStream类似。另外在FileChannel中读写数据都是基于缓冲进行的,读取数据的方法如下:

                                 FileChannel fc=new FileInputStream("demo.tex").getChannel();

                                 ByteBuffer buff=ByteBuffer.allocate(BSIZE);

                                 buff.clear();

                                 fc.read(buff);

                                 buff.flip();

                        在FileChannel中写入数据的方法如下:

                                 FileOutputStream fileOutputStream=new FileOutputStream(tmpFile);

                                 FileChannel fileChannel=fileOutputStream.getChannel();

                                 ByteBuffer byteBuffer=ByteBuffer.allocatedirect(BUFFER_LENGTH);

                                 byteBuffer.clear();    //向byteBuffer中写入数据

                                 fileChannel.write(byteBuffer);

                                 fielChannel.Close();

                                 fileOutputStream.close();

                       FileChannel还支持在两个通道间传输,方法如下:

                               FileChannel in=new FileInputStream("source.txt").getChannel();

                               FileChannel out=new FileOutputStream("dest.txt").getChannel();

                               in.transferTo(0, in.size(), out);

                       需要说明的是,FileChannel.MapMode支持3中类型的映射模式,即READ_ONLY、PRIVATE和READ_WRITE。

          (7)JSON实现

                在网络编程中,数据的传递非常重要,JSON(JavaScript Object Notation)和XML各有优点,XML扩展性好,JSON语法简单。JSON支持两种数据结构,一种是数组,即值得有序列表;另一种是对象,即键值对的集合。

                JSON中有一些特殊字符需要注意,如单引号、正斜杠、反斜杠、换行符等。

                Android对JSON的支持比较全面,以前Android通过org.json包提供了对JSON的支持,但功能不够强大,使用起来十分不便。目前,Android引入了JsonWrite、JsonReader两个类,极大地简化了操作。

                1)写入数据

                        JsonWrite本质上是一种输出流,在写入对象数据时,必须以beginObject方法开始,以endObject方法结束;在写入数组数据时,必须以beginArray方法开始,以endArray方法结束。

                        JsonWriter不支持线程安全。

                2)读取数据

                        JsonReader本质上是一种输入流,在读取对象数据时,必须以beginObject方法开始,以endObject方法结束;读取数组数据时,必须以beginArray方法开始,以endArray方法结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值