服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java-Io-RandomAccessFile任意位置读写数据的操作小结

Java-Io-RandomAccessFile任意位置读写数据的操作小结

2022-12-01 16:19胡安民 Java教程

RandomAccessFile类支持随机访问方式,可以跳转到文件的任意位置读写数据,这个类在文件随机读取时有很大的优势,可利用多线程完成对一个大文件的读写,本文给大家介绍Java-Io-RandomAccessFile(任意位置读写数据)的相关知识,需要的朋友

介绍

RandomAccessFile是java语言中最丰富的文件访问类。RandomAccessFile类支持随机访问方式,可以跳转到文件的任意位置读写数据,这个类在文件随机读取时有很大的优势,可利用多线程完成对一个大文件的读写,利用seek对文件进行切分,从大文件的不同位置开线程进行读写。

构造,模式,方法

RandomAccessFile他的构造函数只有两种,所以仅限于操作文件,不能访问其他io设备,比如网络,内存映像等。

Java-Io-RandomAccessFile任意位置读写数据的操作小结

而底层是使用c/c++进行操作的,所以无法进行自定义操作

Java-Io-RandomAccessFile任意位置读写数据的操作小结

如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建 如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)

模 式 作 用
r 表示以只读方式打开,调用结果对象的任何write方法都将导致抛出IOException
rw 打开以便读取和写入,如果该文件尚不存在,则尝试创建该文件
rws 打开以便读取和写入,相对于"rw",还要求对文件内容或元数据的每个更新都同步写入到底层存储设备
rwd 打开以便读取和写入,相对于"rw",还要求对文件内容的每个更新都同步写入到底层存储设备
方 法 作 用
void close() 重要,关闭此随机访问文件流并释放与该流关联的所有系统资源
FileChannel getChannel() 返回与此文件关联的唯一FileChannel对象,NIO用到
long getFilePointer() 返回此文件中的当前偏移量(实时)
long length() 返回此文件的长度
int read() 从此文件中读取一个数据字节
int read(byte[] b) 将最多b.length个数据字节从此文件读入byte数组,返回读入的总字节数,如果由于已经达到文件末尾而不再有数据,则返回-1。
int read(byte[] b, int off, int len) 将最多len个数据字节从此文件的指定初始偏移量off读入byte数组
boolean readBoolean() 从此文件读取一个boolean,其余readByte()、readChar()、readDouble()等类似
String readLine() 从此文件读取文本的下一行 (会乱码)
void seek(long pos) 重要,设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作(字节单位)
int skipBytes(int n) 重要,尝试跳过输入的n个字节以丢弃跳过的字节,返回跳过的字节数
void write(byte[] b) 将b.length个字节从指定byte数组写入到此文件中
void write(byte[] b, int off, int len) 将len个字节从指定byte数组写入到此文件,并从偏移量off处开始
void write(int b) 向此文件写入指定的字节
void writeBoolean(boolean v) 按单字节值将boolean写入该文件,其余writeByte(int v)、writeBytes(String s)、writeChar(int v)等都类似

问题解决

文件覆盖改追加

在RandomAccessFile作为输入流时候,第一次写的时候会将文件从头覆盖,后面在写就是追加(同一个对象) ,如果想在第一次就追加的话那么就设置写的位置w.seek(w.length());这样就会从文件的最后一个字节之后开始写了

?
1
2
3
4
5
6
7
8
9
10
11
12
13
try (
         RandomAccessFile r = new RandomAccessFile(new File(readFile), "r");
         RandomAccessFile w = new RandomAccessFile(new File(writeFile), "rw");
        ){
      w.seek(w.length()); // 将指针指向文件最后,进行追加
      byte[] bytes = new byte[1024];
      int len = -1;
      while ((len = r.read(bytes)) != -1) {
        w.write(bytes);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }

案例文件读写

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CodeStartAndStopTimeUtil.creator(
       () -> {
         File file = ResourceFileUtil.getFile("mp4/mp4_2.zip");
         String readFile = file.getAbsolutePath();
         String writeFile = file.getParent() + File.separator + "mp4_11112.zip";
         byte[] bytes = new byte[2048];
         try (RandomAccessFile r = new RandomAccessFile(new File(readFile), "r");
             RandomAccessFile w = new RandomAccessFile(new File(writeFile), "rw"); ) {
           int len = -1;
           while ((len = r.read(bytes)) != -1) {
             w.write(bytes);
           }
         }
       });
 }

案例多线程文件读写

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
CodeStartAndStopTimeUtil.creator(
        () -> {
          File file = ResourceFileUtil.getFile("mp4/mp4.zip");
          String readFile = file.getAbsolutePath();
          String writeFile = file.getParent() + File.separator + "mp4_11112.zip";
          long length = new File(readFile).length(); // 文件一共大小
          int num = (int)length/8; // 每个线程读写多少字节   20971520(20mb)  2.5个g4~5秒左右
          List<long[]> longs = DataGroup.dataGroupOnce(length, num);
          List<Future<?>> futures = new ArrayList<>();
          for (long[] aLong : longs) {
            long l = aLong[0]; // 起始位置
            // 创建线程并运行
            Future<?> randomAccessFile =
                ExecutorUtils.createFuture(
                    "RandomAccessFile",
                    () -> {
                      byte[] bytes = new byte[num];
                      try (
                      // 在线程内部创RandomAccessFile对象
                      RandomAccessFile r = new RandomAccessFile(new File(readFile), "r");
                      RandomAccessFile w = new RandomAccessFile(new File(writeFile), "rw"); ) {
                        r.seek(l);
                        int len = r.read(bytes);
                        if (len < num) {
                          // 调整数组
                          bytes = ArrayByteUtil.getActualBytes(bytes);
                        }
                        // 写入文件
                        w.seek(l);
                        w.write(bytes);
                        System.out.println(l );
                      } catch (IOException e) {
                        e.printStackTrace();
                      }
                    });
            futures.add(randomAccessFile);
          }
          // 阻塞全部线程执行完毕
          ExecutorUtils.waitComplete(futures);
        });

问题

多线程使用RandomAccessFile

常见的使用多线程的场景: 断点续传和断点下载,或者文件加密解密等

断点续传原理就是:

  • 前端将文件安装百分比进行计算,每次上传文件的百分之一(文件分片),给文件分片做上序号
  • 后端将前端每次上传的文件,放入到缓存目录
  • 等待前端将全部的文件内容都上传完毕后,发送一个合并请求
  • 后端使用RandomAccessFile进多线程读取所有的分片文件,一个线程一个分片
  • 后端每个线程按照序号将分片的文件写入到目标文件中,
  • 在上传文件的过程中发生断网了或者手动暂停了,下次上传的时候发送续传请求,让后端删除最后一个分片
  • 前端重新发送上次的文件分片

解决readLine乱码的问题

RandomAccessFile 读写文件时,不管文件中保存的数据编码格式是什么 使用 RandomAccessFile对象方法的 readLine() 都会将编码格式转换成 ISO-8859-1 所以 输出显示是还要在进行一次转码

?
1
2
3
4
//需要重新转码才能正常显示
   System.out.println(
   new String(r.readLine().getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)
   );

多线程读写乱码的问题

RandomAccessFile对象是不能线程共享的,一个RandomAccessFile对象的文件指针只有一个,多个线程如果都去操作这个指针进行seek的话,那么读写就会被来回的跳转,导致多个线程的读写混乱,所以每个线程必须在线程内部创建RandomAccessFile,这样每个线程都有一个自己的文件指针了, 正确案例

Java-Io-RandomAccessFile任意位置读写数据的操作小结

到此这篇关于Java-Io-RandomAccessFile(任意位置读写数据)的文章就介绍到这了,更多相关Java-Io-RandomAccessFile内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/weixin_45203607/article/details/124559955

延伸 · 阅读

精彩推荐
  • Java教程@SpringBootApplication注解的使用

    @SpringBootApplication注解的使用

    这篇文章主要介绍了@SpringBootApplication注解的使用,帮助大家更好的理解和学习使用springboot框架,感兴趣的朋友可以了解下...

    vivo互联网技术9462021-09-06
  • Java教程java之swing表格实现方法

    java之swing表格实现方法

    这篇文章主要介绍了java之swing表格实现方法,以实例形式分析了swing构建表格的方法,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    cj_gameboy4052020-01-05
  • Java教程java版微信公众平台后台接入

    java版微信公众平台后台接入

    这篇文章主要为大家详细介绍了java版微信公众平台后台接入,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    享叔11692021-05-12
  • Java教程Java泛型 T与T的使用方法详解

    Java泛型 T与T的使用方法详解

    这篇文章主要介绍了Java泛型 T与T的使用方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参...

    yaominghui6782020-07-02
  • Java教程spring mvc配置bootstrap教程

    spring mvc配置bootstrap教程

    这篇文章主要为大家详细介绍了spring mvc配置bootstrap,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Chester Huang3792020-11-28
  • Java教程使用Jackson来实现Java对象与JSON的相互转换的教程

    使用Jackson来实现Java对象与JSON的相互转换的教程

    这篇文章主要介绍了使用Jackson来实现Java对象与JSON的互相转换的教程,文中罗列了3中Jackson的使用方式,需要的朋友可以参考下 ...

    死神的丧钟14742020-03-21
  • Java教程Java8处理集合的优雅姿势之Stream

    Java8处理集合的优雅姿势之Stream

    这篇文章主要给大家介绍了关于Java8优雅处理集合之Stream的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用java8具有一定的参考学习价...

    Hollis5892021-07-20
  • Java教程SpringBoot中使用监听器的方法详解

    SpringBoot中使用监听器的方法详解

    这篇文章主要为大家详细介绍了SpringBoot中使用监听器的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望...

    即将翻身的咸鱼3932022-09-21