java byte数组截取从右往左(java截取数组一部分)
java byte数组截取从右往左(java截取数组一部分)
2024-06-30 04:25:51  作者:心上之妃  网址:https://m.xinb2b.cn/sport/quu380252.html

对于文件的IO操作应该是我们经常会使用到的,因为文件的复杂性,我们在使用File操作的时候也有很多需要注意的地方,下面我一起来看看吧,我来为大家科普一下关于java byte数组截取从右往左?下面希望有你要的答案,我们一起来看看吧!

java byte数组截取从右往左(java截取数组一部分)

java byte数组截取从右往左

简介

对于文件的IO操作应该是我们经常会使用到的,因为文件的复杂性,我们在使用File操作的时候也有很多需要注意的地方,下面我一起来看看吧。

创建文件的时候指定合适的权限

不管是在windows还是linux,文件都有权限控制的概念,我们可以设置文件的owner,还有文件的permission,如果文件权限没有控制好的话,恶意用户就有可能对我们的文件进行恶意操作。

所以我们在文件创建的时候就需要考虑到权限的问题。

很遗憾的是,java并不是以文件操作见长的,所以在JDK1.6之前,java的IO操作是非常弱的,基本的文件操作类,比如FileOutputStream和FileWriter并没有权限的选项。

Writer out = new FileWriter("file");

那么怎么处理呢?

在JDK1.6之前,我们需要借助于一些本地方法来实现权限的修改功能。

在JDK1.6之后,java引入了NIO,可以通过NIO的一些特性来控制文件的权限功能。

我们看一下Files工具类的createFile方法:

    public static Path createFile(Path path, FileAttribute<?>... attrs)        throws IOException    {        newByteChannel(path, DEFAULT_CREATE_OPTIONS, attrs).close();        return path;    }

其中FileAttribute就是文件的属性,我们看一下怎么指定文件的权限:

    public void createFileWithPermission() throws IOException {        Set<PosixFilePermission> perms =                PosixFilePermissions.fromString("rw-------");        FileAttribute<Set<PosixFilePermission>> attr =                PosixFilePermissions.asFileAttribute(perms);        Path file = new File("/tmp/www.flydean.com").toPath();        Files.createFile(file,attr);    }

注意检查文件操作的返回值

java中很多文件操作是有返回值的,比如file.delete(),我们需要根据返回值来判断文件操作是否完成,所以不要忽略了返回值。

删除使用过后的临时文件

如果我们使用到不需要永久存储的文件时,就可以很方便的使用File的createTempFile来创建临时文件。临时文件的名字是随机生成的,我们希望在临时文件使用完毕之后将其删除。

怎么删除呢?File提供了一个deleteOnExit方法,这个方法会在JVM退出的时候将文件删除。

注意,这里的JVM一定要是正常退出的,如果是非正常退出,文件不会被删除。

我们看下面的例子:

    public void wrongDelete() throws IOException {        File f = File.createTempFile("tmpfile",".tmp");        FileOutputStream fop = null;        try {            fop = new FileOutputStream(f);            String str = "Data";            fop.write(str.getBytes());            fop.flush();        } finally {            // 因为Stream没有被关闭,所以文件在windows平台上面不会被删除            f.deleteOnExit(); // 在JVM退出的时候删除临时文件            if (fop != null) {                try {fop.close();                } catch (IOException x) {// Handle error                }            }        }    }

上面的例子中,我们创建了一个临时文件,并且在finally中调用了deleteOnExit方法,但是因为在调用该方法的时候,Stream并没有关闭,所以在windows平台上会出现文件没有被删除的情况。

怎么解决呢?

NIO提供了一个DELETE_ON_CLOSE选项,可以保证文件在关闭之后就被删除:

    public void correctDelete() throws IOException {        Path tempFile = null;            tempFile = Files.createTempFile("tmpfile", ".tmp");            try (BufferedWriter writer =     Files.newBufferedWriter(tempFile, Charset.forName("UTF8"),             StandardOpenOption.DELETE_ON_CLOSE)) {                // Write to file            }        }

上面的例子中,我们在writer的创建过程中加入了StandardOpenOption.DELETE_ON_CLOSE,那么文件将会在writer关闭之后被删除。

释放不再被使用的资源

如果资源不再被使用了,我们需要记得关闭他们,否则就会造成资源的泄露。

但是很多时候我们可能会忘记关闭,那么该怎么办呢?JDK7中引入了try-with-resources机制,只要把实现了Closeable接口的资源放在try语句中就会自动被关闭,很方便。

注意Buffer的安全性

NIO中提供了很多非常有用的Buffer类,比如IntBuffer, CharBuffer 和 ByteBuffer等,这些Buffer实际上是对底层的数组的封装,虽然创建了新的Buffer对象,但是这个Buffer是和底层的数组相关联的,所以不要轻易的将Buffer暴露出去,否则可能会修改底层的数组。

    public CharBuffer getBuffer(){         char[] dataArray = new char[10];         return CharBuffer.wrap(dataArray);    }

上面的例子暴露了CharBuffer,实际上也暴露了底层的char数组。

有两种方式对其进行改进:

    public CharBuffer getBuffer1(){        char[] dataArray = new char[10];        return CharBuffer.wrap(dataArray).asReadOnlyBuffer();    }

第一种方式就是将CharBuffer转换成为只读的。

第二种方式就是创建一个新的Buffer,切断Buffer和数组的

    public CharBuffer getBuffer2(){        char[] dataArray = new char[10];        CharBuffer cb = CharBuffer.allocate(dataArray.length);        cb.put(dataArray);        return cb;    }

注意 Process 的标准输入输出

java中可以通过Runtime.exec()来执行native的命令,而Runtime.exec()是有返回值的,它的返回值是一个Process对象,用来控制和获取native程序的执行信息。

默认情况下,创建出来的Process是没有自己的I/O stream的,这就意味着Process使用的是父process的I/O(stdin, stdout, stderr),Process提供了下面的三种方法来获取I/O:

getOutputStream()getInputStream()getErrorStream()

如果是使用parent process的IO,那么在有些系统上面,这些buffer空间比较小,如果出现大量输入输出操作的话,就有可能被阻塞,甚至是死锁。

怎么办呢?我们要做的就是将Process产生的IO进行处理,以防止Buffer的阻塞。

public class StreamProcesser implements Runnable{    private final InputStream is;    private final PrintStream os;    StreamProcesser(InputStream is, PrintStream os){        this.is=is;        this.os=os;    }    @Override    public void run() {        try {            int c;            while ((c = is.read()) != -1)                os.print((char) c);        } catch (IOException x) {            // Handle error        }    }    public static void main(String[] args) throws IOException, InterruptedException {        Runtime rt = Runtime.getRuntime();        Process proc = rt.exec("vscode");        Thread errorGobbler                = new Thread(new StreamProcesser(proc.getErrorStream(), System.err));        Thread outputGobbler                = new Thread(new StreamProcesser(proc.getInputStream(), System.out));        errorGobbler.start();        outputGobbler.start();        int exitVal = proc.waitFor();        errorGobbler.join();        outputGobbler.join();    }}

上面的例子中,我们创建了一个StreamProcesser来处理Process的Error和Input。

InputStream.read() 和 Reader.read()

InputStream和Reader都有一个read()方法,这两个方法的不同之处就是InputStream read的是Byte,而Reader read的是char。

虽然Byte的范围是-128到127,但是InputStream.read()会将读取到的Byte转换成0-255(0x00-0xff)范围的int。

Char的范围是0x0000-0xffff,Reader.read()将会返回同样范围的int值:0x0000-0xffff。

如果返回值是-1,表示的是Stream结束了。这里-1的int表示是:0xffffffff。

我们在使用的过程中,需要对读取的返回值进行判断,以用来区分Stream的边界。

我们考虑这样的一个问题:

FileInputStream in;byte data;while ((data = (byte) in.read()) != -1) {}

上面我们将InputStream的read结果先进行byte的转换,然后再判断是否等于-1。会有什么问题呢?

如果Byte本身的值是0xff,本身是一个-1,但是InputStream在读取之后,将其转换成为0-255范围的int,那么转换之后的int值是:0x000000FF, 再次进行byte转换,将会截取最后的Oxff, Oxff == -1,最终导致错误的判断Stream结束。

所以我们需要先做返回值的判断,然后再进行转换:

FileInputStream in;int inbuff;byte data;while ((inbuff = in.read()) != -1) {  data = (byte) inbuff;  // ... }

拓展阅读:

这段代码的输出结果是多少呢? (int)(char)(byte)-1

首先-1转换成为byte:-1是0xffffffff,转换成为byte直接截取最后几位,得到0xff,也就是-1.

然后byte转换成为char:0xff byte是有符号的,转换成为2个字节的char需要进行符号位扩展,变成0xffff,但是char是无符号的,对应的十进制是65535。

最后char转换成为int,因为char是无符号的,所以扩展成为0x0000ffff,对应的十进制数是65535.

同样的下面的例子中,如果提前使用char对int进行转换,因为char的范围是无符号的,所以永远不可能等于-1.

FileReader in;char data;while ((data = (char) in.read()) != -1) {  // ...}

write() 方法不要超出范围

在OutputStream中有一个很奇怪的方法,就是write,我们看下write方法的定义:

    public abstract void write(int b) throws IOException;

write接收一个int参数,但是实际上写入的是一个byte。

因为int和byte的范围不一样,所以传入的int将会被截取最后的8位来转换成一个byte。

所以我们在使用的时候一定要判断写入的范围:

    public void writeInt(int value){        int intValue = Integer.valueOf(value);        if (intValue < 0 || intValue > 255) {            throw new ArithmeticException("Value超出范围");        }        System.out.write(value);        System.out.flush();    }

或者有些Stream操作是可以直接writeInt的,我们可以直接调用。

注意带数组的read的使用

InputStream有两种带数组的read方法:

public int read(byte b[]) throws IOException

public int read(byte b[], int off, int len) throws IOException

如果我们使用了这两种方法,那么一定要注意读取到的byte数组是否被填满,考虑下面的一个例子:

    public String wrongRead(InputStream in) throws IOException {        byte[] data = new byte[1024];        if (in.read(data) == -1) {            throw new EOFException();        }        return new String(data, "UTF-8");    }

如果InputStream的数据并没有1024,或者说因为网络的原因并没有将1024填充满,那么我们将会得到一个没有填充满的数组,那么我们使用起来其实是有问题的。

怎么正确的使用呢?

    public String readArray(InputStream in) throws IOException {        int offset = 0;        int bytesRead = 0;        byte[] data = new byte[1024];        while ((bytesRead = in.read(data, offset, data.length - offset))                != -1) {            offset += bytesRead;            if (offset >= data.length) {                break;            }        }        String str = new String(data, 0, offset, "UTF-8");        return str;    }

我们需要记录实际读取的byte数目,通过记载偏移量,我们得到了最终实际读取的结果。

或者我们可以使用DataInputStream的readFully方法,保证读取完整的byte数组。

little-endian和big-endian的问题

java中的数据默认是以big-endian的方式来存储的,DataInputStream中的readByte(), readShort(), readInt(), readLong(), readFloat(), 和 readDouble()默认也是以big-endian来读取数据的,如果在和其他的以little-endian进行交互的过程中,就可能出现问题。

我们需要的是将little-endian转换成为big-endian。

怎么转换呢?

比如,我们想要读取一个int,可以首先使用read方法读取4个字节,然后再对读取的4个字节做little-endian到big-endian的转换。

    public void method1(InputStream inputStream) throws IOException {        try(DataInputStream dis = new DataInputStream(inputStream)) {            byte[] buffer = new byte[4];            int bytesRead = dis.read(buffer);  // Bytes are read into buffer            if (bytesRead != 4) {                throw new IOException("Unexpected End of Stream");            }            int serialNumber =ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt();        }    }

上面的例子中,我们使用了ByteBuffer提供的wrap和order方法来对Byte数组进行转换。

当然我们也可以自己手动进行转换。

还有一个最简单的方法,就是调用JDK1.5之后的reverseBytes() 直接进行小端到大端的转换。

    public  int reverse(int i) {        return Integer.reverseBytes(i);    }

  • 酷暑拍摄的技巧(拍摄冷饮的6个实用技巧)
  • 2024-06-30拍摄冷饮的6个实用技巧拍摄冷饮的6个实用技巧,让你的冷饮更有食欲,手机和相机都可用炎炎夏日,冷饮、雪糕、冰淇淋都成了我们在夏天必吃的食物,不过你有没有发现,冷饮都很好看,不管是颜色还是形状上,都很吸引人我们吃冷饮的时候,不。
  • 散文经典十篇(字字珠玑言之凿凿)
  • 2024-06-30字字珠玑言之凿凿读好书,能潜移默化地影响我们的气质我们读过的书和走过的路,都藏于自己的气质之中本期书单关键词:【散文集书单】,领略没有焦虑、没有迷茫,只有幸福和惬意的慢时光1《人间草木》不开心的时候,多去菜市场感受一。
  • 螺鲤钓鲤鱼绝密方法(掌握这六大钓鲤技巧)
  • 2024-06-30掌握这六大钓鲤技巧鲤鱼是我国淡水鱼中产量最高的鱼种,也是钓鱼人最常钓的鱼种,无论是休闲野钓,还是竞技、黑坑,都少不了它的身影鲫鱼喜欢栖息于水域的底层,它们喜欢在水色比较暗淡、不太透明的水域生活鲤鱼天生胆小,生性贪吃,而。
  • 美人谷二日游攻略(听一曲自然的田园交响曲)
  • 2024-06-30听一曲自然的田园交响曲你喜欢贝多芬的《田园交响曲》吗?他在第一乐章中表达了到达乡村时的快乐感受,全曲和谐、明朗、纯朴、愉快,让人置身于鸟语花香的田野里,沐浴着温暖的阳光,呼吸着新鲜的空气五个乐章都遵循了和谐规律展示着和谐的。
  • 干菜包子的做法(怎么做干菜包子)
  • 2024-06-30怎么做干菜包子主料:面粉1000克、干菜500克、酵母10克辅料:粉丝150克、豆腐皮200克、鸡蛋8个、虾皮20克干菜提前泡好,洗净挤干水份,切碎豆腐皮切碎粉丝提前泡好沥干水切碎鸡蛋打入碗中,加入少许盐打散入油锅。
  • 老婆出轨一直反感我解决办法(老婆出轨我哥们)
  • 2024-06-30老婆出轨我哥们图片来自网络,图文无关网友来信如是说:我和老婆结婚已经四年多,最近几个月,老婆的日常行为有些不正常就在昨天,老婆醉酒到家后倒头就睡着了,我趁机偷看了老婆手机聊天记录,并发现,老婆已经把我绿了,她的出轨。
  • 2023年艺术生 2023高考艺术类专业省统考报考简章发布
  • 2024-06-302023年艺术生 2023高考艺术类专业省统考报考简章发布浙江2023年普通高考艺术类考生注意除文化科目考试外还须参加专业考试我省八大类专业省统考报考简章发布来看报考要点遵守防疫要求,带齐双证赴考我省艺术类省统考分八个类别:美术类、音乐类、舞蹈类、时装表演类。
  • 关于林冲的故事情节及其性格特点(林冲三黔之驴)
  • 2024-06-30林冲三黔之驴林冲金子般的性格,具有很好的延展性但这句话不是褒义,我敢保证,当林冲的面说,他不敢反将我太知道他了当高衙内二戏林娘子的时候,林冲该不该反将太该了,即使不杀,与鲁智深两个高手暗地里教训他可以吧高衙内并不。
  • 怎么做烙馅饼(三种烙馅饼的家常做法)
  • 2024-06-30三种烙馅饼的家常做法先和面,放置20分钟西葫芦洗净去瓤,用搽菜板搽成细丝后,用盐揉揉出水份,切碎大头菜洗净切条后,放入开水中焯一下,淋干水、切碎拌馅:加入少许水在肉馅中,搅拌一下,再加入适量豆油、精盐、酱油、花椒面、味精。
  • 闫妮早年电视剧大全(经典不输张曼玉的客栈老板娘)
  • 2024-06-30经典不输张曼玉的客栈老板娘华语影视剧里最经典的客栈老板娘形象,一个是张曼玉在电影《新龙门客栈》扮演的金镶玉,还有一个就是电视剧《武林外传》里闫妮塑造的佟湘玉金镶玉可以用风骚泼辣、世俗多情来形容,而如果也要找一个词来形容佟湘玉,。
  • 展信安和展信佳什么意思
  • 2024-06-30展信安和展信佳什么意思展信安和展信佳意思是对收信人的祝愿,展信佳是对收信人的祝愿,展信安是对收信人的问候,所以展信佳最好展信安和展信佳是写在信的开头,在信的开头写上“展信安和展信佳”是对收信人的祝愿。
  • 铝合金门窗20大常识(铝合金门窗20大常识)
  • 2024-06-30铝合金门窗20大常识1、什么是普通铝合金型材?就是内外相通无空气层,表面做喷涂防腐处理2、什么是断桥铝合金型材?它的优点是什么?断桥式铝合金窗的原理是利用隔热条将室内外两层铝合金既隔开又紧密连接成一个整体,构成一种新的隔。