JavaSE01_Day03(中)-RandomAccessFile复制文件、对字符串进行读写操作

JavaSE01_Day03(中)

附:递归算法删除非空文件夹原理图:

        从外向里遍历子文件,从里向外删除文件

 

针对于RandomAccessFile所学习的所有知识作为了解,如果以后用的时候,打开包老师所书写的代码,能进行阅读并使用即可,在工作中RandomAccessFile使用并不多。

一、RandomAccessFile复制文件

1.1 一字节一字节进行读写操作,完成复制案例

原理:

       将源文件中的内容按照一字节一字节的顺序进行读取到内存中,然后再进行写出到另一个文件中,这个过程其实就是对文件的复制操作。

 package cn.tedu;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 
 /**
  * 使用RAF完成文件的复制操作
  *
  * 原理:将源文件中的内容按照一字节一字节的顺序进行读取到内存中,
  * 然后再进行写出到另一个文件中,这个过程其实就是对文件的复制操作。
  * @author cjn
  *
  */
 public class RAFCopyDemo01 {
 
  public static void main(String[] args) throws IOException {
  /*
  * 复制步骤:
  * 1.在电脑中准备一个需要进行复制的文件
  * 2.创建RAF对象进行对源文件的读取操作
  * 3.创建RAF对象进行将内存中读取的资源进行写出操作
  * 4.因为每次进行读写操作时一字节一字节进行读写,
  *   整个文件会有很多的字节需要进行读写操作,所以使用循环完成(while)
  * 5.辅助信息的打印,查看复制完成的时间
  */
         //待复制的文件
  RandomAccessFile src = new RandomAccessFile("G_E_M_ 邓紫棋 - 句号.mp3", "r");
         //复制后的文件
  RandomAccessFile desc = new RandomAccessFile("G_E_M_ 邓紫棋 - 句号copy.mp3", "rw");
  //用于临时保存每次读取的字节内容
  int len = 0;
  //获取读取内容之前的时间
  long start = System.currentTimeMillis();
  //将每次读取的字节赋值给变量len
  while ((len = src.read()) != -1) {
  //如果len变量的值不等于-1,证明没有读到文件末尾,可以进行读取操作
  //读完需要进行写出操作
  desc.write(len);
  }
  //获取复制内容结束后的时间
  long end = System.currentTimeMillis();
  System.out.println("复制文件消耗的时间为:"+(end-start)+"ms");
  //使用完毕后要关闭资源
  src.close();
  desc.close();
  }
 
 }

测试结果:

 复制文件消耗的时间为:13776ms

注意:复制时间不会一模一样,和电脑的配置等多方面因素有关系。

1.2 批量进行读写复制操作(优化)

  • write(byte[] d)方法:RAF提供了一个可以向文件中写出一组字节的方法,该方法会根据当前指针的位置连续性的写出给定字节数组的单位的所有字节内容。

  • write(byte[] d,int offset,int len)方法:RAF提供了三个参数的write重载方法,在上面方法的基础上,添加了两个参数,第二个参数是从数据的某一个下标位置处开始进行写出,第三个参数是表示连续性写出len个字节。

  • int read(byte[] b)方法:RAF提供了可以批量进行读取字节的方法。方法返回值是一个int类型,表示的是可以返回实际读取到的字节量。注意:实际读取到的字节内容是会存储到传递方法参数的字节数组中。

 package cn.tedu;
 
 import java.io.RandomAccessFile;
 
 /**
  * 批量(块)读写完成复制的案例演示
  *
  * 优点:相比较于一字节一字节进行读写复制,
  * 块读写方案可以减少读写的次数,提高读写的效率,
  * 由之前的读写次数过多--->少次数的进行读写,从而减少了文件的复制时间
  * @author cjn
  *
  */
 public class RAFCopyDemo02 {
 
  public static void main(String[] args) throws Exception {
         //待复制的文件
  RandomAccessFile src = new RandomAccessFile("等什么君 - 难渡.mp3", "r");
         //复制后的文件
  RandomAccessFile desc = new RandomAccessFile("等什么君 - 难渡copy.mp3", "rw");
 
  /*
  * 1byte字节   8bit位
  * 1kb         1024byte
  * 1Mb         1024kb
  * 1Gb         1024Mb
  */
 
  //定义批量读写的字节大小8kb~10kb
  byte[] data = new byte[1024*10];//10kb
  //定义一个用于存储实际读取的字节量的变量
  int len = 0;
  //获取读取内容之前的时间
  long start = System.currentTimeMillis();
  //当文件读取到文件末尾,返回值为-1
  while ((len = src.read(data)) != -1) {
  //将读取到的字节量进行写出操作
  desc.write(data, 0, len);
  }
  //获取复制内容结束后的时间
  long end = System.currentTimeMillis();
  System.out.println("复制文件消耗的时间为:"+(end-start)+"ms");
  //使用完毕后要关闭资源
  src.close();
  desc.close();
  }
 
 }

测试结果:

 复制文件消耗的时间为:5ms

注意:复制时间不会一模一样,和电脑的配置等多方面因素有关系。但是比之间一字节一字节进行复制要优化很多。

补充:关于while ((len = src.read(data)) != -1),每次将读取的字节都存到data数组中,前面的是每读满10kb后就写出一次(相当于data的长度等于len),最后一次是读到-1就结束,写出最后读取的字节量,也就是len的大小。

 

二、RandomAccessFile对字符串进行读写操作

2.1 将字符串转换为字节序列进行写出操作

 package cn.tedu;
 
 import java.io.RandomAccessFile;
 
 /**
  * 使用RandomAccesFile对字符串进行写出操作
  * @author cjn
  *
  */
 public class RAFWriteStringDemo03 {
 
  public static void main(String[] args) throws Exception {
  //创建RAF对象,向bao.txt文件写入数据
  RandomAccessFile raf = new RandomAccessFile("bao.txt", "rw");
 
  String str = "今天是端午节后的第一节课";
  /*
   * 将字符串转换为字节序列
   * String类中提供了一个对象方法,方法名称是getBytes,
   * 这个方法支持在方法参数中传递字符集编码,再将字符串
   * 转化为字节序列的时候会按照指定的字符集编码进行转换
   *
   * 字符集编码(常用):UTF-8、GBK
   * 有关于编码的书写可以是大写,也可以是小写,
   * 但是不要既有大写又有小写。
   *
  */
         //将字符串按照UTF-8字符集编码转换为字节序列
  byte[] data = str.getBytes("utf-8");
         //写出数据
  raf.write(data);
 
  String str1 = ",同学们应该加加油,把后面的课程提前预习一下!!!";
  data = str1.getBytes("utf-8");
  raf.write(data);
 
  System.out.println("写出完毕!!!");
  //使用完毕后要关闭资源
  raf.close();
  }
 
 }
问题:将字符串转换为字节序列进行写出操作中:byte[] data = str.getBytes("utf-8");raf.write(data);
字符串转化为字节序列后,写入的数据不应该是字节序列吗,为什么保存后的文件内容还是字符串内容。


答案
这样理解不正确,写一个字符串内容,如果用RAF写出到文本中不能直接写出,计算机数据之间的传输是二进制数据间的传输,
把内容记录进去。就好比你在本上写字,你的字是不是用笔画组成的,那最后你能说为什么不是显示笔画呢。
再比如:搬一张桌子,门比较小,不能直接将桌子抬过去,就会把桌子拆解搬运,那么在写的时候RAF就只能写字节,数据或者
文件的写出就是进行按照字节单位进行读写,为什么一个文件会显示大小的单位是kb呢,在这里就是一种搬运数据的单位而已,
都搬完了,这个字符串又组成完整的了。

              即:只是读取的时候将字符串转化为字节序列,但最后读到的仍然是字符串。只是传递数据的方式不同而已。

 

2.2 从文件中将字符串内容进行读取操作

 package cn.tedu;
 
 import java.io.RandomAccessFile;
 
 /**
  * 使用RandomAccessFile对文本中的字符串进行读取操作
  * @author cjn
  *
  */
 public class RAFReadStringDemo04 {
 
  public static void main(String[] args) throws Exception {
  //创建RAF对象,加载bao.txt文件
  RandomAccessFile raf = new RandomAccessFile("bao.txt", "r");
 
  /*
  * 批量读取
  * raf.length()获取bao.txt文件的字节大小
  */
         //此处需要强制类型转换,如果是long会超出int范围,如果是byte、short会自动转换
  byte[] data = new byte[(int)raf.length()];//可以这么写,但是不建议,一般都是每次8-10kb读取。
         //读取数据
  raf.read(data);
 
  //将读取到的字节内容(字节内容在读取的时候存储到了data字节数组中)转化为字符串
  String str = new String(data, "utf-8");
  System.out.println(str);
  //使用完毕后要关闭资源
  raf.close();
  }
 
 }

问题:从文件中将字符串内容进行读取操作中: byte[] data = new byte[(int)raf.length()];此处考虑到raf.length()的长度可能为long类型,需要进行强制类型转换,但强转后,会存在丢失信息的可能吧,还是说遇到数据较大时,不会采用这种方法,就避免了这个问题。

答案:如果一次读取的话,可以使用raf.length(),但是不建议使用这种,实际在定义字节数组时还是8kb~10kb,另外int的范围为正负21亿,一般的数据文件内容都不会超过这个范围,不会丢失数据。

posted @ 2021-06-16 00:01  Coder_Cui  阅读(326)  评论(0编辑  收藏  举报