java的String,io,编码随记

由一道题引出的一些东西(求助文章!)

题目: 用io对进行文件简单的加密解密
思路一: 用字节流读取出来存入byte数组,然后创建String对象,再追加到StringBuilder对象上. 然后一直循环追加,最后再将StringBuilder对象转为String对象,再转回byte数组,最后存入文件中.
代码演示:
//加密代码

public static void main(String[] args) throws IOException {
        byStringBuilder();
    }

    public static void byStringBuilder() throws IOException {
        //读取图片
        BufferedInputStream inBuffer =
                new BufferedInputStream(new FileInputStream("src/lab/second/page_643/in.jpg"), 1024);
        //存读取的字节
        byte[] storageArr = new byte[1024];
        //用StringBuilder将byte数组先拼接,然后转回为byte数组
        StringBuilder builder = new StringBuilder();
        int read;
        while ((read = inBuffer.read(storageArr, 0, storageArr.length)) != -1) {
            //先根据byte数组创建String对象,然后追加到StringBuilder对象上
            builder.append(new String(storageArr, 0, read));
        }
        inBuffer.close();
        //重新转化为byte
        byte[] bytes = new String(builder).getBytes();
        //加密方式为byte数组每个元素加5
        for (int i = 0; i < bytes.length; i++)
            bytes[i] += 5;

        //存入out.jpg文件中
        BufferedOutputStream outBuffer = new BufferedOutputStream(
                new FileOutputStream("src/lab/second/page_643/out.jpg"), 1024);
        outBuffer.write(bytes);
        outBuffer.close();
    }

//解密代码

public static void main(String[] args) throws IOException {
        byStringBuilder();
    }

    public static void byStringBuilder() throws IOException {
        String path = "src/lab/second/page_643/out.jpg";
        //读取加密的文件
        BufferedInputStream inBuffer =
                new BufferedInputStream(new FileInputStream(path));
        BufferedInputStream buffer = new BufferedInputStream(inBuffer, 1024);
        //用byte数组存读取的字节
        byte[] storage = new byte[1024];
        int read;
        //读出来的字节,用StringBuilder拼接
        StringBuilder builder = new StringBuilder();
        while ((read = buffer.read(storage, 0, storage.length)) != -1) {
            //追加到builder对象上
            builder.append(new String(storage, 0, read));
        }
        //转为byte数组
        byte[] bytes = builder.toString().getBytes();
        //解密
        for (int i = 0; i < bytes.length; i++)
            bytes[i] -= 5;
        //写到同一个文件中,将原来加密的文件覆盖
        BufferedOutputStream outBuffer = new BufferedOutputStream(
                new FileOutputStream("src/lab/second/page_643/out.jpg"), 1024);
        outBuffer.write(bytes);
        outBuffer.close();
    }

思路二: 不用StringBuilder,读出来的字节放在storage这个byte数组中,然后复制一个byte数组,再将复制的byte数组放入ArrayList中,最后向文件循环写出list中的byte数组.
代码演示:
//加密代码

public static void main(String[] args) throws IOException {
        byArrayList();
    }
    public static void byArrayList() throws IOException {
        //读取图片
        BufferedInputStream inBuffer = new BufferedInputStream(
                new FileInputStream("src/lab/second/page_643/in.jpg"), 1024);
        //存读取的字节的byte数组
        byte[] storageArr = new byte[1024];
        //存若干个byte数组(因为图片大小肯定大于1kb,所以用若干数组存)
        ArrayList<byte[]> list = new ArrayList<>();
        int read;
        while ((read = inBuffer.read(storageArr, 0, storageArr.length)) != -1) {
            //拷贝数组
            byte[] clone = Arrays.copyOfRange(storageArr, 0, read);
            //拷贝后添加到list中
            list.add(clone);
        }
        inBuffer.close();
        //所有元素值加5
        for (byte[] bytes : list) {
            addFive(bytes);
        }
        //存入out.jpg文件中
        BufferedOutputStream outStream = new BufferedOutputStream(
                new FileOutputStream("src/lab/second/page_643/out.jpg"), 1024);
        for (byte[] bytes : list) {
            outStream.write(bytes);
        }
        outStream.close();
    }
    //给byte数组,每个元素的值加5
    public static void addFive(byte[] arr) {
        for (int i = 0; i < arr.length; i++)
            arr[i] += 5;
    }

//解密代码

public static void main(String[] args) throws IOException {
        byArrayList();
    }
    public static void byArrayList() throws IOException {
        //读取图片
        BufferedInputStream inBuffer =
                new BufferedInputStream(new FileInputStream("src/lab/second/page_643/out.jpg"), 1024);
        //存读取的字节
        byte[] storageArr = new byte[1024];
        //存复制的byte数组
        ArrayList<byte[]> list = new ArrayList<>();
        int read;
        while ((read = inBuffer.read(storageArr, 0, 1024)) != -1) {
            //将byte数组克隆,并将其加到list中
            byte[] clone = Arrays.copyOfRange(storageArr, 0, read);
            list.add(clone);
        }
        for (byte[] bytes : list) {
            divide(bytes);
        }
        //没开追加模式,直接将原来加密文件覆盖
        BufferedOutputStream outBuffer = new BufferedOutputStream(
                new FileOutputStream("src/lab/second/page_643/out.jpg"), 1024);
        for (byte[] bytes : list) {
            outBuffer.write(bytes);
        }
        outBuffer.close();
    }
    //给byte数组,每个元素值减5
    public static void divide(byte[] arr) {
        for (int i = 0; i < arr.length; i++)
            arr[i] -= 5;
    }

这种方式成功的实现了加密和解密,所以推断第一种方式问题出在字符串问题上. 询问GPT得知,可能是new String时未指定编码,然后果断在while循环中new String和获取字符串的byte数组时指定了utf8编码

builder.append(new String(storageArr, 0,read,StandardCharsets.UTF_8));
byte[] bytes = builder.toString().getBytes(StandardCharsets.UTF_8);

结果仍然不行,突然想起java中char和String好像是utf-16编码,所以果断去测试一把应该用哪种编码
根据最初的byte数组中的值,和经过不同编码方式转化为字符串再转换回来的值进行比较
表达得不是很清楚,直接上代码:

 public static void main(String[] args) throws IOException {
        //读取图片
        BufferedInputStream inBuffer =
                new BufferedInputStream(new FileInputStream("src/lab/second/page_643/in.jpg"), 1024);
        //byte数组,存储读到的字节
        byte[] bytes = new byte[1024];
        inBuffer.read(bytes, 0, bytes.length);
        //打印原本的
        System.out.println("原本的:");
        printArr(bytes);
        //使用utf8编码转换为字符串,然后转换回来
        StringBuilder builderUTF8 = new StringBuilder().append(new String(bytes, StandardCharsets.UTF_8));
        byte[] arrUTF8 = builderUTF8.toString().getBytes(StandardCharsets.UTF_8);
        System.out.println("utf8编码的:");
        printArr(arrUTF8);
        //使用utf16转换为字符串,然后转换回来
        StringBuilder builderUTF_16 = new StringBuilder().append(new String(bytes, StandardCharsets.UTF_16));
        byte[] arrUTF_16 = builderUTF_16.toString().getBytes(StandardCharsets.UTF_16);
        System.out.println("utf16编码的:");
        printArr(arrUTF_16);
        //使用UTF_16BE转换为字符串,然后转换回来
        StringBuilder builderUTF_16BE = new StringBuilder().append(new String(bytes, StandardCharsets.UTF_16BE));
        byte[] arrUTF_16BE = builderUTF_16BE.toString().getBytes(StandardCharsets.UTF_16BE);
        System.out.println("UTF_16BE编码的:");
        printArr(arrUTF_16BE);
        //使用UTF_16LE转换为字符串,然后转换回来
        StringBuilder builderUTF_16LE = new StringBuilder().append(new String(bytes, StandardCharsets.UTF_16LE));
        byte[] arrUTF_16LE = builderUTF_16LE.toString().getBytes(StandardCharsets.UTF_16LE);
        System.out.println("UTF_16LE编码的:");
        printArr(arrUTF_16LE);
    }
    //打印byte数组中的值
    public static void printArr(byte[] bytes) {
        for (int i = 0; i < 10; i++) {
            System.out.print(bytes[i] + "  ");
        }
        System.out.println("\n-------------");
    }

运行结果:
在这里插入图片描述
可见,用UTF_16BE编码先转为字符串再转回byte数组,值是没有变的.
GPT似乎也肯定了我的想法,
在这里插入图片描述
改完后自信运行,仍然失败(哭
直接气急败坏把StandardCharsets类里面全部编码试一遍
在这里插入图片描述
仍然失败(哭
求大佬解答!
其他:
关于UTF_16BEUTF_16LE:
个人理解: UTF_16BE就是从右往左存,UTF_16LE就是相反
官方话术:
GPT的回答:
在这里插入图片描述
在<<JAVA核心技术:卷二>>中也有一小段介绍:
在这里插入图片描述
研究这些,一起面试造火箭!(doge

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值