首页 > 作文

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

更新时间:2023-04-05 02:43:21 阅读: 评论:0

简介

对于文件的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).clo();        return path;    }

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

    public void createfilewithpermission() throws ioexception {        t<posixfilepermission> perms =                posixfilepermissions.fromstring("rw-------");        fileattribute<t<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.clo();                } catch (ioexception x) {                    // handle error                }            }        }    }

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

怎么解决呢?

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

    public void correctdelete() throws ioexception {        path tempfile = null;            tempfile = files.createtempfile("tmpfile", ".tmp");            try (bufferedwriter writer =                         files.newbufferedwriter(tempfile, chart.forname("utf8"),                                 standardopenoption.delete_on_clo)) {                // write to file            }        }

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

释放不再被使用的资源

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

但是很多时候我们可能会忘记关闭,那么该怎么办呢?jdk7中引入了try生日快乐搞笑-with-resources机制,只要把实现了cloable接口的资源放在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 streamprocesr implements runnable{    private final inputstream is;    private final printstream os;    streamprocesr(inputstream is, printstream os){        this.is=is;        this.os=os;    }    @override    public void run() {        try {            in中北大学排名t 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 streamprocesr(proc.geterrorstream(), system.err));        thread outputgobbler                = new thread(new streamprocesr(proc.getinputstream(), system.out));        errorgobbler.start();        outputgobbler.start();        int exitval = proc.waitfor();        errorgobbler.join();        outputgobbler.join();    }}

上面的例子中,我们创建了一个streamprocesr来处理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 offt = 0;        int bytesread = 0;       排骨汤的家常做法 byte[] data = new byte[1024];        while ((bytesread = in.read(data, offt, data.length - offt))                != -1) {            offt += bytesread;            if (offt >= data.length) {                break;            }        }        string str = new string(data, 0, offt, "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 = ne10000毫安等于多少whw 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 rialnumber =                    bytebuffer.wrap(buffer).order(byteorder.little_endian).getint();        }    }

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

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

还有一个最简单的方法,就是调用jdk1.5之后四六级成绩的reverbytes() 直接进行小端到大端的转换。

    public  int rever(int i) {        return integer.reverbytes(i);    }

本文发布于:2023-04-05 02:43:20,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/2858d05edab5f0cf0ec50a5fe79393c2.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:java byte数组截取从右往左(java截取数组一部分).doc

本文 PDF 下载地址:java byte数组截取从右往左(java截取数组一部分).pdf

标签:文件   数组   的是   方法
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图