java学习笔记24

来源:互联网 发布:亿阳信通程序员怎么样 编辑:程序博客网 时间:2024/06/16 04:25

1、几个目的文件就几个流,因为一个流关联一个文件。

文件切割器,以1MB为单位切割,就声明一个1MB长的数组,如果切成100M,那就还声明1MB,但是循环写100次。




4、文件切割合并+配置文件

切割文件时,必须记录下被切割文件的名称,以及切割出来碎片文件的个数。以方便与合并。

而这个信息为了进行藐视,使用键值对的方式,用到了properties对象。

windows中存储键值对信息的文件是.inin,而java中存储键值对信息的文件是.properties

5、操作对象的字节流ObjectOutputStream

通过在六中使用文件可以实现对象的持久存储。对象的序列化就是将对象排队存到硬盘上,换句话说也就是实现了对象的持久化。想把对象存入到硬盘,那么对象要实现implements Serializable接口,使得对象可序列化,这样才能按顺序存到硬盘上, Serializable接口里面没东西,所以不需要覆盖,直接实现以下就可以了。还有就是对象里面不全是文本信息,所以是不能用txt挂着码表去解析的,所以存储对象的文件后缀一般是.object


FileOutputStream是不能操作对象的,还需功能加强,所以就类似以前的Buffered,这里在外面套上一个ObjectOutputStream。



6、发送过来的.object文件,要想从硬盘中读入到内存中,必须要同时发过来那个对象所属的类文件.class,必须有了大框架,你发过来具体信息才能被正确理解接收。




反序列化就是把存在硬盘上的对象用ObjectInputStream来读取出来。

7、当对象实现Serializable接口后,Serializable接口的作用就是将由这个类所特有的成员的特性如:String name(数字签名)由算法得到一个ID,由这个类产生的对象都是这个ID。这样如果类的定义被改变,也就是类的class文件被改变后,自然ID就变了,拿以前类产生的对象和改变后的类的ID作对比肯定是不一样的,也就是会报错。这个机制保证了文件反序列过程的安全性


版本号尽量写出了,自己定义,因为不同版本的编译器产生的ID 号可能稍有不同。下图中就是自己定义了ID号,只要ID号不变,哪怕String name的权限由private变成public哦都市可以反序列化的。关键就在于ID号是自己定义的,而且还没有改变。


对象中的成员如果有静态的,由于是存储在方法区,没存在对象里,所以是没有写入硬盘的。




关键字transient短暂的(瞬态的),静态的Static是公共数据,不会被序列化写到硬盘上,有些数据是私有非静态的,也不想被序列化,就可以用关键字transient来修饰。

这样在反序列化时,就不会显示那个成员。

下图中的两个成员都没写进去,所以反序列化时,什么都读不出来

9、RandomAcessFile随机访问文件,本质是把输出流和输出流以及一个byte数组封装到了一起。




这里只保证数据写进去了,但是未必能用记事本解析出来。张三是2个字符,4个字节


609是4个字节,但是write(609)只写了609的最低字节也就是十进制的97,想把4个字节都写进去,要用writeint(609)


注意RandomAcessFile和一般流的区别在于

一般的流文件不存在则创建,文件存在,也要创建同名的覆盖掉以前的。


随机读取其实也就是随便读取,因为可以设置指针的位置,决定从哪里开始读取内容。RandomAcessFile里面有一个大型数组,所以对准某个文件时,就把文件里的数据先读到大型数组中,再从大型数组中读取到临时数组中,来操作。



随机写入也就是随便写入,如果没有指定写入指针位置的话就默认从大型数组的0角标写起,如果指定了raf.seek(3*8)就从指定的那个位置写起。

随机操作2个特点,1、大型数组,2、seek指针

随机访问数据要求有规律,也可以和多线程技术结合在一起。不同线程从不同的地方同时开始读取数据。


12、之前输入流和输出流之间没有关系,之间要通过变量或者数组来做中转。但是管道流Pipe的InputStream和PipedOutStream的输入和输出可以直接进行连接。



out.write()是字节流不能直接写字符数据,所以通过“hi,管道来了!”.getBytes()转换为byte[]就可以用字节流来操作了。


对于管道流,由于输入和输出是套在一起的,如果用单线程先读的话,会因为还没写入数据而造成读取阻塞,死锁在哪里。所以一般都是用多线程就算一个在等待读取,只要另一个线程写入了,就能读到数据。

13、操作基本数据类型的流对象DataOUtputStream

也是装饰增强类,和Buffered都是增强的效果。UTF-8修改版中一个汉字是3个字节,这是DataOutputStream和DataInputStream中所特有的码表。流操作基本数据时尽量都要用Data这个流来进行装饰。

14、操作数组的流对象

数组只在内存中,也就是说流的源和目的都在内存中。之前学的FIle是硬盘上的文件,System是键盘控制台的。

由于ByteArrayOutputStream流对象操作的是内存中的数据而不需要调用系统底层资源(操作硬盘),所以流不用关闭,也不会抛IO异常.



UTF-8字符能一个字节能表示就用一个字节,一个不够的用2个字节,最多用3个字节

6、每个中文对应2个字节,高位都是1,所以是负数。

 由字符串得到字符数组,就类似把字对应编码表变成数字,也即编码的过程(由看不懂的变成看得懂的)。反之,由存取数字的字节数组变成字符串就是解码。

getByte()这个函数默认用的就是GBK码表。也即str.getBytes()和str.getBytes("GBK")的效果是一样的。




buf是字节数组,也就是用printBytes(buf)打印出来的是数字,而String s1 = new String(buf),相当于解码过程,把字节数组默认按照GBK编码表转为字符串,String s1 = new String(buf)和String s1 = new String(buf,“GBK”)的结果是一样的。如果用别的码表来解码,就无法恢复原来的字符串。例如下图:


可能真正的编码顺序是字符串-->GBK编码-->Unicode编码-->Unicode解码-->GBK解码-->字符串,真正底层中转还用了Unicode码,本地电脑系统确定了什么实际用的是中国的GBK,还是欧洲的ISO8859-1。



编对了,但是解错了,有可能有救的意思是说,假设用GBK进行编码,用ISO8859解码(得到错误结果),那么就再用ISO8895进行编码,重新用GBK进行解码,这样就可以恢复正确。但是为什么是是有可能,而不是绝对呢?

因为当用GBK编码后,UTF-8解码时,遇到查不到的字节直接变成解码成?(-17 -65 -67),这样符号都变了,就算你用UTF-8重新再编码,那样得到的也不再是最初的信息了。


9、IO流(联通问题),存放在硬盘上的0101数据如何才能被UTF-8识别为该读1个字节,还是该读2个字节,还是该读3个字节对应一个字符?

这个有下面的格式所确定了,凡是1个字节8位010开头是0的,就把一个字节对应码表翻译为一个字符,如果开头是110,后8为数据开头是10,那就把这两个字节连起来在UTF-8码表查对应的字符,3个字节是同样道理。



而“联通”两个字的GBK编码和UTF-8译码刚好一致,GBK编完码刚好形成下面4个字节,但是在译码时则由于刚好符合UTF-8的识别准则,所以


GBK2312中文都是2个字节,并且都是负数,所以必然是2个负数字节构成了一个字符。但是GBK则是第一个一定是负的,第二个有可能是正的。

UtF-8是3个负数对应一个汉字


0 0
原创粉丝点击