java中randomaccessfile,java randomaccessfile 多线程 按行读取
00-1010介绍了结构、模式、方法、问题解决、文件覆盖更改和追加、案例文件读写、多线程文件读写、多线程使用RandomAccessFile解决readLine乱码、多线程读写乱码问题。
00-1010随机存取文件是java语言中最丰富的文件存取类。RandomAccessFile类支持随机访问模式,可以跳转到文件的任意位置读写数据。这个类在随机读取文件方面有很大的优势。它可以通过多线程完成一个大文件的读写,通过seek拆分文件,从大文件的不同位置启动线程进行读写。
00-1010随机访问文件他的构造函数只有两种,所以仅限于操作文件,不能访问其他io设备,比如网络、内存镜像等。
底层是c/c操作的,不能自定义。
如果使用RandomAccessFile作为输出流,如果写出的文件不存在,将在执行过程中自动创建。如果写出的文件存在,它将覆盖原始文件内容。(默认情况下,从头覆盖)
模 式R表示以只读模式打开。调用result对象的任何write方法都会导致IOExceptionrw被打开进行读写。如果该文件尚不存在,请尝试创建文件rws以打开进行读写。与“rw”相比,还需要将文件内容或元数据的每次更新写入底层存储设备rwd,以便打开进行读写。与“rw”相比,还要求对文件内容的每次更新都要写入底层存储设备作 用方 法void close()很重要。关闭这个随机访问文件流,释放与这个流相关的所有系统资源。FilechannegetChannel()返回与该文件相关联的唯一FileChannel对象,使用NIO long getFilePointer()返回该文件中的当前偏移量(实时)。long length()返回该文件的长度。int read()从这个文件中读取一个数据字节。int read(byte[] b)将这个文件中最多b.length的数据字节读入字节数组,并返回读取的字节总数。如果因为已经到达文件末尾而没有更多数据,它将返回-1。Int (byte [] b,int off,int len)从该文件的指定初始偏移量off读取最多len个数据字节到字节数组boolean readBoolean()从该文件读取一个boolean,其余的readByte()、readChar()、readDouble()等。类似于字符串readLine()。从这个文件中读取文本的下一行是很重要的(它将是乱码)。将其设置为在文件开头测量的文件指针偏移量。重要的是,下一个读或写操作(字节单元)发生在这个位置,int skipBytes(int n)。尝试跳过输入的n个字节丢弃跳过的字节,返回跳过的字节,void write(byte[] b)。将指定字节数组中的b.length字节写入该文件,void write(byte[] b,int off,Int len)将指定字节数组中的len字节写入该文件,并从offset off开始,void write(int b)将指定字节写入该文件,void writeBoolean(Boolean v)按单字节值将boolean写入该文件,其余writeByte(int v),writeBytes(String s),writeChar(int v)类似。
目录
00-1010 RandomAccessFile作为输入流时,第一次写的时候会从头覆盖文件,以后写的时候会追加(同一个对象)。如果要第一次追加,那么设置写入位置w . seek(w . length());这将在文件的最后一个字节后开始写入。
try(RandomAccessFile r=new RandomAccessFile(new File(readFile), r );RandomAccessFile w=new RandomAccessFile(新文件(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(); }
案例文件读写
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); } } }); }
案例多线程文件读写
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 所以 输出显示是还要在进行一次转码
//需要重新转码才能正常显示 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内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。