java实现读取文件并随机指定读取位置

FileInputStream & RandomAccessFile

在访问文件的区别中,RandomAccessFile 使用随机访问的方式,而FileInputStream及FileOutputStream使用的是流式访问的方式。FileInputStream在访问文件时无法回退到之前访问的流位置,FileInputStream更像消费者一样,读取后类似于消费了。要想和RandomAccessFile一样那么就需要缓存区来进行支持。

ByteArrayInputStream & ByteArrayOutputStream

ByteArrayInputStream & ByteArrayOutputStream 对byte类型数据进行写入的类 相当于一个中间缓冲层,将类写入到文件等其他outputStream。它是对字节进行操作,属于内存操作流。

小知识:对于内存操作流是无需进行关闭。

RandomAccessFile

RandomAccessFile是Java 输入/输出流体系中功能最丰富的文件内容访问类,它提供了众多的方法来访问文件内容,它既可以读取文件内容,也可以向文件输出数据。与普通的输入/输出流不同的是,RandomAccessFile支持"随机访问"的方式,程序可以直接跳转到文件的任意地方来读写数据。

RandomAccessFile支持4中模式来进行访问文件(mode)

“r”:以只读方式打开指定文件。如果试图对该RandomAccessFile执行写入方法,都将抛出IOException异常。
“rw”:以读、写方式打开指定文件。如果该文件尚不存在,则尝试创建该文件。
“rws”:以读、写方式打开指定文件。相对于"rw"模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
“rwd”:以读、写方式打开指定文件。相对于"rw"模式,还要求对文件内容的每个更新都同步写入到底层存储设备。

小知识:RandomAccessFile并不属于流类,但具有读写文件数据的功能。

RandomAccessFile实现随机读取文件

public void randomAccessFile() {
    
    
        int init = -1;
        int dataSize = 200;
        byte[] buf = new byte[512];
        RandomAccessFile randomAccessFile = null;
        try {
    
    
            randomAccessFile = new RandomAccessFile(new File("C:\\com\\upload\\bmRev01.bin"), "r");
            while (true) {
    
    
                Scanner scan = new Scanner(System.in);
                if (scan.hasNextLine()) {
    
    
                    int i = scan.nextInt();
                    if (i == -1) {
    
    
                        return;
                    } else {
    
    
                        init = i;
                    }
                    System.out.println("输入的数据为:" + init);
                }
                randomAccessFile.seek(init);
                randomAccessFile.read(buf, 0, dataSize);
                String dataHex = bytesToHexString(buf, dataSize);
                System.out.println(dataHex + "#");
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            try {
    
    
                randomAccessFile.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }

访问结果:

200
输入的数据为:200
F9FE0425274E284F2A003100380001F0F1FE68202049C87102201F49087207201D4948722B201C49887238201A49C8725920194908731D4800783330164948731B48006833301449887319480068000A33301149C87316480068000C33300E49087468200C49487401200400E4B2112C09DA0948407C0849E4B2095D401806494874641CF2E71620034988741321024802F0C6F9F7BD00009811002080140020991100205C1400209B110020BF14002050140020F0B58DB000250020694688718A480078052801D0#
800
输入的数据为:800
0874072024494872BDE22248807C18281DD12048C07C022819D1AD48007833301D490873AB48006833301B494873A9480068000A333018498873A6480068000C33301549C8730620134948729BE21148807C182800D032E20E48C07C032800D02DE200209C49088000200400E4B20F2C1EDA9A48E4B25621614340184078012806D1954800880121A140014392480180641CEBE7780D00209811002080140020991100205C1400209B110020830D002089480088002809D104208949487233208749087333208649#
200
输入的数据为:200
F9FE0425274E284F2A003100380001F0F1FE68202049C87102201F49087207201D4948722B201C49887238201A49C8725920194908731D4800783330164948731B48006833301449887319480068000A33301149C87316480068000C33300E49087468200C49487401200400E4B2112C09DA0948407C0849E4B2095D401806494874641CF2E71620034988741321024802F0C6F9F7BD00009811002080140020991100205C1400209B110020BF14002050140020F0B58DB000250020694688718A480078052801D0#

FileInputStream实现文件读取

    public void parse() {
    
    
        InputStream inputStream = null;
        byte[] buf = new byte[200];
        int len;
        List<String> dataList = new ArrayList<>();
        StringBuilder msgData;
        // 读取文件并CRC加密
        try {
    
    
            File file = new File("C:\\com\\upload\\bmRev01.bin");
            inputStream = new FileInputStream(file);
            while ((len = inputStream.read(buf)) != -1) {
    
    
                msgData = new StringBuilder();
                for (int i = 0; i < len; i++) {
    
    
                    msgData.append(String.format("%02x", buf[i]).toUpperCase());
                }
                String checkStr = "#";
                dataList.add(msgData + checkStr.toUpperCase());
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                assert inputStream != null;
                inputStream.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
        for (String s : dataList) {
    
    
            System.out.println(s);
        }
    }

对于FileInputStream来说是无法支持随机读取,只支持以流式依次往下读取文件信息。要想支持随机访问那边就必须使用ByteArrayInputStream。

ByteArrayInputStream实现随机访问

public void skipParse() {
    
    
        int init = -1;
        int dataSize = 200;
        InputStream inputStream = null;
        ByteArrayInputStream stream = null;
        ByteArrayOutputStream swapStream = null;
        File file = new File("C:\\com\\upload\\bmRev01.bin");
        byte[] buf = new byte[512];
        try {
    
    
            inputStream = new FileInputStream(file);
            swapStream = new ByteArrayOutputStream();
            int ch;
            while ((ch = inputStream.read()) != -1) {
    
    
                swapStream.write(ch);
            }
            stream = new ByteArrayInputStream(swapStream.toByteArray());
            while (true) {
    
    
                Scanner scan = new Scanner(System.in);
                if (scan.hasNextLine()) {
    
    
                    int i = scan.nextInt();
                    if (i == -1) {
    
    
                        return;
                    } else {
    
    
                        init = i;
                    }
                    System.out.println("输入的数据为:" + init);
                }
                stream.reset();
                stream.skip(init);
                stream.read(buf, 0, dataSize);
                String dataHex = bytesToHexString(buf, dataSize);
                System.out.println(dataHex + "#");
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                assert inputStream != null;
                assert stream != null;
                inputStream.close();
                stream.close();
                swapStream.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }

ByteArrayInputStream对读取文件的流进行了缓存,ByteArrayInputStream所有的操作都是在内存中完成的。其中最重要的2方法:reset() 和 skip(long n) 是实现随机访问的关键方法。

reset() : 将缓冲区重置为标记位置。标记的位置为 0,除非标记了另一个位置或在构造函数中指定了偏移量。
skip(long n) : 从此输入流中跳过 n 个字节的输入。如果到达输入流的末尾,则可能会跳过更少的字节。
随机访问的2个核心参数

  1. pos : 流访问的偏移量。
  2. mark : 标记位置。
  3. count : 文件总大小 当执行reset的时候,pos = mark; 当执行skip是 pos = pos += n;

区别

从代码实现上来说RandomAccessFile更加简单方便,且该方法可以提高读取的速度。而ByteArrayInputStream实现起来就就复杂了很多,代码实现起来较为复杂。且如果文件过大这种随机访问方式效率非常低。

猜你喜欢

转载自blog.csdn.net/GBK_8/article/details/126718283