6.10 如何进行整型读写
我们在前面的小节里面也谈到了对整型的读取,接下来我们通过FileAdapter来介绍对本地整型数据的操作,以及整型列表对象的使用,并与java.util.ArrayList的性能进行对比。
与读取字节类似,在构建一个FileAdapter对象后,可以通过getIntWriter方法获取IntWriteAdapter对象进行整数写操作:
- FileAdapter fa = new FileAdapter(path);
- IntWriteAdapter wa = fa.getIntWriter();
或者指定开始位置,向后写入intNum个整数:
- IntWriteAdapter wa = getIntWriter(long beginIndex, long intNum)
如果不指定起始位置,默认是追加到最后。注意,在使用时容易出现不追加到最后,而反复覆盖已有位置的情况,比如:
- IntWriteAdapter wa = fa.getIntWriter();
- int[] nums = new int[5];
- wa.writeInt(nums);
- wa.writeInt(nums);
- wa.writeInt(nums);
上面代码的结果是nums没有追加到文件最后,而是反复覆盖相同位置,如果修改为:
- IntWriteAdapter wa = fa.getIntWriter();
- int[] nums = new int[5];
- wa.writeInt(nums);
- wa = fa.getIntWriter();
- wa.writeInt(nums);
- wa = fa.getIntWriter();
- wa.writeInt(nums);
结果就每次追加到文件最后了,这是因为每次调用fa.getIntWriter(),它会自动调整文件大小,计算文件的最后位置,如果沿用旧的IntWriteAdapter,则没有获取到文件更新后的最后位置,导致反复覆盖相同位置。
同样,构建一个FileAdapter对象后,可以通过getIntReader方法获取IntReadAdapter对象进行整数读操作:
- FileAdapter fa = new FileAdapter(path);
- IntReadAdapter ra = fa.getIntReader();
或者指定开始位置读取intNum个整数:
- IntReadAdapter ra = fa.getIntReader(long beginIndex, long intNum);
跟上面谈到的FTTP使用类似,操作结束时,需要进行关闭:
- fa.close();
除了提供对整型数据的便利操作外,框架还提供了ListInt数组用于对整型数据的存放,ListInt在容量和排序的性能上都比java.util.ArrayList要高,接下来我们以一个综合的demo:ListIntTest来演示对整型数据的读写、装载、排序,分别在运行时输入参数0、1、2进行区分。
下面介绍运行步骤。
1)读写演示,代码如下:
- java -cp fourinone.jar; ListIntTest 0
如果命令参数是0,ListIntTest调用了writeReadTest,首先在同一运行目录下建立一个"data.txt"的数据文件,写入了100个整数(每个整数是随机生成的,取值范围在1千万内),然后再每10个一批地将所有整数读出并输出显示,如图6-6所示。
图6-6 ListIntTest0
2)装载演示,代码如下:
- java -cp fourinone.jar; ListIntTest 1
如果命令参数是1,ListIntTest调用了capacityTest,它按先后顺序运行了ListInt和ArrayList的装载容量测试进行对比。
首先通过ArrayAdapter获取到一个ListInt实例:
- ListInt ai = ArrayAdapter.getListInt();
然后往里面写入2千万个整数(取值范围为1千万内)。接着,再建立一个ArrayList的实例,同样往里面写入2千万个整数,为了能看清楚过程,每写入1千万后会输出一条信息。运行结果如图6-7所示。
图6-7 ListIntTest1
我们发现,向ListInt写入2千万个整数是可以顺利完成的,但是向ArrayList写入2千万个整数则导致内存溢出,查看内容输出可以看到,向ArrayList写入1千万个整数是正常完成的,但是再大就出现问题了(这里用的是一台普通的内存为4GB的PC,JVM的内存使用会小于4GB)。
3)排序演示,代码如下:
- java -cp fourinone.jar; ListIntTest 2
如果命令参数是2,ListIntTest调用了sortTest,比方法可以输入一个参数,用来表示要测试排序多少个整数,这里测试了5百万个数字排序。首先程序建立了一个"data.txt"文件并生成了5百万个无序整数(取值范围为1千万以内),然后先后使用ListInt和ArrayList进行排序。
对于ListInt排序,我们可以看到先从文件中读出所有整数到一个数组中,然后使用ListInt的sort方法,输入该数组进行排序,最后再输出前100个数字进行验证。对于ArrayList来说,先通过readListIntAll直接从文件读取所有整数到一个ArrayList中,然后再利用Collections.sort对该ArrayList进行排序,最后同样读取前100个数字进行验证。结果如图6-8所示。
图6-8 ListIntTest2
我们可以看到,在同台(2.4GHz,4G内存)机器上,利用ListInt完成5百万数字排序时间是1秒,而ArrayList则用了7秒。我们大体可以看到ListInt相对于ArrayList,对于整数可以存储更多,排序更快,使用起来更高效。
完整demo源码如下:
- // ListIntTest
- import com.fourinone.FileAdapter;
- import com.fourinone.FileAdapter.IntReadAdapter;
- import com.fourinone.FileAdapter.IntWriteAdapter;
- import com.fourinone.ArrayAdapter;
- import com.fourinone.ArrayAdapter.ListInt;
- import java.util.Random;
- import java.util.ArrayList;
- import java.util.Collections;
- public class ListIntTest
- {
- public void intWrite(String path, int num)
- {
- System.out.println("write "+num+" number to "+path+"...");
- FileAdapter fa = new FileAdapter(path);
- fa.delete();
- IntWriteAdapter wa = fa.getIntWriter();
- Random rad = new Random();
- int[] nums = new int[num];
- for(int i=0;i<nums.length;i++){
- int thenum = rad.nextInt(10000000);
- nums[i]=thenum;
- }
- wa.writeInt(nums);
- System.out.println("write done.");
- fa.close();
- }
- public void intRead(String path)
- {
- System.out.println("read number from "+path+"...");
- FileAdapter fa = new FileAdapter(path);
- IntReadAdapter ra = null;
- int total=0;
- for(int n=0;n<10;n++){
- ra = fa.getIntReader(n*10,10);
- int[] its = ra.readIntAll();
- for(int i:its){
- System.out.println(i);
- total++;
- }
- }
- System.out.println("total:"+total);
- fa.close();
- }
- public void listintCapacity()
- {
- System.out.println("insert int into ListInt...");
- ListInt ai = ArrayAdapter.getListInt();
- Random rad = new Random();
- for(int i=0;i<20000000;i++)
- ai.add(rad.nextInt(10000000));
- System.out.println(ai.size()+" number be inserted.");
- }
- public void arraylistCapacity()
- {
- System.out.println("insert int into ArrayList...");
- ArrayList<Integer> al = new ArrayList<Integer>();
- Random rad = new Random();
- int i=0;
- while(i<20000001){
- al.add(rad.nextInt(10000000));
- if(i%10000000==0){
- System.out.println(i+" number be inserted.");
- }
- i++;
- }
- }
- public void listintSort()
- {
- FileAdapter fa = new FileAdapter("data.txt");
- int[] rls = fa.getIntReader().readIntAll();
- ListInt is = ArrayAdapter.getListInt();
- System.out.println("ListInt sort begin...");
- long begin = (new java.util.Date()).getTime();
- is.sort(rls);
- long end = (new java.util.Date()).getTime();
- System.out.println("sort done time:"+(end-begin)/1000+"s");
- System.out.print("check top 100 data:");
- for(int i=0;i<100;i++)
- {
- System.out.print(rls[i]+" ");
- }
- System.out.println("...");
- }
- public void arraylistSort()
- {
- FileAdapter fa = new FileAdapter("data.txt");
- ArrayList<Integer> rls = (ArrayList)fa.getIntReader().readListIntAll();
- System.out.println("ArrayList sort begin...");
- long begin = (new java.util.Date()).getTime();
- Collections.sort(rls);
- long end = (new java.util.Date()).getTime();
- System.out.println("sort done time:"+(end-begin)/1000+"s");
- System.out.print("check top 100 data:");
- for(int i=0;i<100;i++)
- {
- System.out.print(rls.get(i)+" ");
- }
- System.out.println("...");
- }
- public static void writeReadTest()
- {
- ListIntTest test = new ListIntTest();
- test.intWrite("data.txt",100);
- test.intRead("data.txt");
- }
- public static void capacityTest()
- {
- ListIntTest test = new ListIntTest();
- test.listintCapacity();
- test.arraylistCapacity();
- }
- public static void sortTest(int num)
- {
- ListIntTest test = new ListIntTest();
- test.intWrite("data.txt",num);
- test.listintSort();
- test.arraylistSort();
- }
- public static void main(String[] args)
- {
- if(args[0].equals("0"))
- {
- writeReadTest();
- }
- else if(args[0].equals("1"))
- {
- capacityTest();
- }
- else if(args[0].equals("2"))
- {
- sortTest(5000000);
- }
- }
- }