IO知识梳理3
---------------------------------------------------------------------------------------------------------------------------------------------
1、在IO中设计到集合的是;
SepenceInputStream
在IO中涉及到多线程的是: 管道流2、随机访问流 RandomAccessFile
new RandomAccessFile("E:\\Demo\\test\\a.txt","rw");3、基本数据流 能直接的操作基本数据类型:
该类只能操作文件。其模式: r 读--- rw 读写
1、模式
2、直接写入数据基本类型
3、通过seek 方法改变指针的位置来进行指定位置的数据读取和写入。【重点】
DataInputStream---DataOutputStream4、管道流
指定编码表
new DataOutputStream(new FileOutputStream("E:\\Demo\\utfdate.txt"));
PipendInputStram --PipendOutputStream5、字节数组流
输入输出可以直接进行连接,通过结合线程使用。
管道流的特点::当多线程时进行读写功能时,
不论是先执行读,还是写 都不重要,最后终究会先执行写,然后再打印
用于操作字节数组的流对象:
ByteArrayInputStream 在构造时,需要接收数据源,而且数据源是一个字节数组
ByteArrayOutputStream 在构造时,不用定义数据目的,因为该对象中已经在内部封装
6、字节数组流 因为这两个流对象 都操作的是数组,并没有使用系统资源,了可变长度的字节数组,这就是数据目的。
所以不用进行 close 关闭。7、【操作【字节】数组】 、【操作【字符】数组】、【操作字符串】 都基本相同。
【字节】数组: ByteArrayInputStream --- ByteArrayOutputStream8、操作流 、序列化
【字符】数组: CharArrayReader ------ CharArrayWriter
【字符串】 : StringReader ---- StringWriter
ObjectInputStream--ObjectOutputStream
Serializable
1、被操作的对象必须实现 Serializable 接口
这接口太爽了,只需要实现,其他什么也不用写
2、自定义序列号
static final long serialVersionUID = 42L; 42L为自定义序列号
3、静态成员变量不能被序列号
(静态在方法区,能被序列的都在堆内存中)
4、 普通成员变量想要不被序列号必须加关键字:
4让 普通成员变量也不被序列化呢?这样该成员不被序列号,但存在与堆内存中。
java 提供了一个关键字: transizent5、给类设定一个固定序列号,以保证唯一性
static final long serialVersionUID = 42L;9、
编码: 字符串 变 字节数组。
解码: 字节数组 变 字符串。
String --> byte[] : str.getBytes(charsetName);
[charsetName 指定编码表(不指定用默认GBK编码表)]
byte --> String: newString(byte[],charsetName);10、“联通”是 GBK 编码 但是 产生的二进制形式 居然和 UTF-8 一致
这就是为什么 会出现乱码了,因为识别的时候,为上列第2中
然后去查UTF-8码表。自然就错了。
---------------------------------------------------------------------
【6】
随机访问流
【重点】
【6】
随机访问流
【重点】
1、模式2、直接写入数据基本类型3、通过seek 方法改变指针的位置来进行指定位置的数据读取和写入。【重点】
RandomAccessFile
自身具备读写方法 达到随机访问。skipBytes(int i)seek(int i)skipBytes(int i) 跳过几个字节 只能往下跳不能往回 了解该方法即可。
1、模式
2、写入方法
3、seek 指定指针位置。
---------------------------------------------------------------------
该类不算是IO 体系中的子类 (后缀没有父类)
而直接继承自Object
但是它是 IO 包中成员,因为它具备读和写功能。
内部封装了一个 byte 数组 ,而通过指针对数组的元素进行操作。
可以通过geitFilePointer 获取指针位置。
其实,完成读写原理就是内部封装了 字节写入流 和输出流
通过构造函数可以看出,该类只能操作文件。
而操作文件的模式: r 读--- rw 读写
如果模式为只读: r 不会创建文件,会去读取一个已存在的文件,如果文件不存在
2、写入方法
3、seek 指定指针位置。
---------------------------------------------------------------------
该类不算是IO 体系中的子类 (后缀没有父类)
而直接继承自Object
但是它是 IO 包中成员,因为它具备读和写功能。
内部封装了一个 byte 数组 ,而通过指针对数组的元素进行操作。
可以通过geitFilePointer 获取指针位置。
其实,完成读写原理就是内部封装了 字节写入流 和输出流
通过构造函数可以看出,该类只能操作文件。
而操作文件的模式: r 读--- rw 读写
如果模式为只读: r 不会创建文件,会去读取一个已存在的文件,如果文件不存在
则会出现异常。
如果模式:rw
操作的文件不存在,会自动创建,如果存在则不会覆盖。
---------------------------------------------------------------------
---------------------------------------------------------------------
1、通过指针的设定达到随意性的访问。2、数据是有规律的。
1、能够进行数据的分段写入,比如下载,就是设计了多个线程,分别在写入数据通过该方法给每个线程不同的段落,不会有任何冲突。用一般流写数据因为是从头到尾,会导致数据都存完了,最后读出来是错误的,解码错误。
//问题:如何把名字搞为16的字节格式??
class $3RandomAccessFile { public static void main(String[] args) throws IOException{ method_3(); //method_2(); //method_1(); } public static void method_3()throws IOException{ RandomAccessFile raf =new RandomAccessFile("E:\\Demo\\test\\a.txt","rw"); raf.seek(8*4);//指针直接把位置指向8个字节的 第4个。 raf.write("德吉".getBytes()); raf.writeInt(99);//直接写 基本数据类型 raf.close(); } public static void method_2()throws IOException{ RandomAccessFile raf =new RandomAccessFile("E:\\Demo\\test\\a.txt","rw"); byte [] by = new byte [4]; raf.seek(8*2);// 在数据规律的情况下*0表示第一个,*1第二个。。。 raf.read(by); String name = new String(by); int age = raf.readInt(); System.out.println(name+">>"+age); raf.close(); } public static void method_1() throws IOException{ RandomAccessFile raf = new RandomAccessFile("E:\\Demo\\test\\a.txt","rw"); raf.write("张三".getBytes()); raf.writeInt(90); raf.write("姜末".getBytes()); raf.writeInt(99); raf.write("上官".getBytes()); raf.writeInt(97); raf.close(); } }【7】
基本数据流
操作基本数据类型: (使用频率比 较高。)
DataInputStream---DataOutputStream
主要用于操作基本数据类型的对象。 [专业操作数据]
(ObjectInputStream、ObjectOutputStream 中 有很多相同方法 不过更专注于操作对象)
构造方法
DataInputStream(InputStream in) DataOutputStream(OutputStream out) import java.io.*; class $4DataStream{ public static void main(String[] args) throws IOException{ dataRead();// dataWrite(); dReadUTF();// dWriteUTF(); yibanliu(); } public static void yibanliu() throws IOException{ OutputStreamWriter osw = //new OutputStreamWriter(new FileOutputStream("E:\\Demo\\utf.txt"),"utf-8"); new OutputStreamWriter(new FileOutputStream("E:\\Demo\\gbk.txt"),"gbk"); osw.write("你好"); osw.close(); //创建 tuf-8 和 GBK 编码,需要转换流才可以办到 //DataStream 可以修改版 utf-8 但是必须对应读取, //【a】 处读取 其他编码格式,报错 //修改版 utf-8 8个字节 // utf-8 6字节 // Gbk 4字节 } public static void dWriteUTF() throws IOException{ DataOutputStream dos = new DataOutputStream(new FileOutputStream("E:\\Demo\\utfdate.txt")); dos.writeUTF("你好"); dos.close(); } public static void dReadUTF() throws IOException{ DataInputStream dos = new DataInputStream(new FileInputStream("E:\\Demo\\utfdate.txt")); //new DataInputStream(new FileInputStream("E:\\Demo\\gbk.txt"));//【a】 String s = dos.readUTF(); System.out.println(s); dos.close(); } public static void dataWrite() throws IOException{ DataOutputStream dos = new DataOutputStream(new FileOutputStream("E:\\Demo\\987.txt")); dos.writeInt(223); dos.writeBoolean(true); dos.writeDouble(9293.234);//各种直接操作 基本数据类型 System.out.println("Is ok!~"); dos.close(); } public static void dataRead() throws IOException{ DataInputStream dos = new DataInputStream(new FileInputStream("E:\\Demo\\987.txt")); int i = dos.readInt(); boolean b = dos.readBoolean(); double d = dos.readDouble();//输出的时候, 也是直接操作即可。 System.out.println("int:"+i); System.out.println("bool:"+b); System.out.println("dou:"+d); dos.close(); } }能够直接对基本数据类型进行操作。很简便
【8】
管道流
PipendInputStram --PipendOutputStream
输入输出可以直接进行连接,通过结合线程使用。
、、、、、、、、、、、、、
定义2个线程,我们知道,他们运行的时候随机性非常强
谁都有可能先执行。
通过在写入前设定写入sleep(6000) 秒 ,多次运行
我们发现,不论是先执行读,还是写 都不重要,最后终究会先执行写,然后再打印
这就是 管道流的特点。
----------
1、创建两个线程,初始化连接管道流2、创建管道流,并进行连接。并传递给 线程3、启动线程。
//读取线程
class read implements Runnable // 多线程{ private PipedInputStream in; read(PipedInputStream in ){//3、 初始化连接到 输出管道流 this.in = in; } //1、实现 Runnable 成为多线程 2、覆盖 run 方法 public void run(){ //4、记住只能try 不能 throws try{ //、读取方法就不用在多说了,因为示例,数据短,就没用while byte [] by = new byte[1024]; int len = 0; System.out.println("读取前:"); len = in.read(by); //System.out.println("读取后:"); String s = new String(by,0,len); System.out.println(":"+s); in.close(); } catch (IOException e){ throw new RuntimeException("没有读取到信息"); } } }// 写入线程 --基本步奏同上。
class write implements Runnable{ private PipedOutputStream out; write(PipedOutputStream out){ this.out = out; } public void run(){ try{ System.out.println("6秒后开始写入:"); Thread.sleep(6000);//为了演示多态性让等待5秒后在写 out.write("wo yao fei de geng gao".getBytes()); out.close(); } catch (Exception e){ throw new RuntimeException("没有写入信息"); } } } class $2PipedStream { public static void main(String[] args) throws Exception{ PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(); in.connect(out);//管道连接 read r = new read(in); write w = new write(out); //启动线程 //全写方法: //Thread t1 =new Thread(r); //t1.start(); //Thread t2 = new Thread(w); //t2.start(); // 简写--内部类写法: new Thread(r).start(); new Thread(w).start(); } }
在IO中设计到集合的是;
SepenceInputStream
在IO中涉及到多线程的是: 管道流
【9】
字节数组流
用于操作字节数组的流对象:
ByteArrayInputStream 在构造时,需要接收数据源,而且数据源是一个字节数组
ByteArrayOutputStream 在构造时,不用定义数据目的,因为该对象中已经在内部封装
在IO中涉及到多线程的是: 管道流
【9】
字节数组流
用于操作字节数组的流对象:
ByteArrayInputStream 在构造时,需要接收数据源,而且数据源是一个字节数组
ByteArrayOutputStream 在构造时,不用定义数据目的,因为该对象中已经在内部封装
了可变长度的字节数组,这就是数据目的。
因为这两个流对象 都操作的是数组,并没有使用系统资源,
所以不用进行 close 关闭。
-------------------------
在流操作规律讲解时:
源设备:
所以不用进行 close 关闭。
-------------------------
在流操作规律讲解时:
源设备:
键盘 System.in硬盘 FileStream内存 ArrayStream
目的设备:
控制台 System.out硬盘 FileStream内存 ArrayStream
------------------------------------
发现:【操作【字节】数组】 、【操作【字符】数组】、【操作字符串】 都基本相同。
---------------------------------------------------------------------------------------------------
【字节】数组: ByteArrayInputStream--- ByteArrayOutputStream
---------------------------------------------------------------------------------------------------
发现:【操作【字节】数组】 、【操作【字符】数组】、【操作字符串】 都基本相同。
---------------------------------------------------------------------------------------------------
【字节】数组: ByteArrayInputStream--- ByteArrayOutputStream
---------------------------------------------------------------------------------------------------
【字符】数组:CharArrayReader ------ CharArrayWriter
---------------------------------------------------------------------------------------------------
【字符串】 : StringReader ---- StringWriter
---------------------------------------------------------------------------------------------------
【字符串】 : StringReader ---- StringWriter
---------------------------------------------------------------------------------------------------
import java.io.*; class $5ByteArrayStream { public static void main(String[] args) throws IOException{ byteArray(); charArray(); string(); } //【操作【字节】数组】 public static void byteArray() throws IOException{ ByteArrayInputStream bais = new ByteArrayInputStream("afdfgfdgdfgd".getBytes()); ByteArrayOutputStreambaos = new ByteArrayOutputStream(); int len = 0; while((len = bais.read())!=-1){ baos.write(len); } System.out.println(baos.size()); System.out.println(baos.toString()); } //【操作【字符】数组】 public static void charArray() throws IOException{ CharArrayReader car = new CharArrayReader("fdafergr".toCharArray()); CharArrayWriter caw = new CharArrayWriter(); int len = 0 ; while((len = car.read())!=-1){ caw.write(len); } System.out.println(caw.size()); System.out.println(caw.toString()); } //【操作字符串】 public static void string() throws IOException{ StringReader sr = new StringReader("ccccccccccccccccMMMM"); StringWriter sw = new StringWriter(); int len = 0 ; while((len = sr.read())!=-1){ sw.write(len); } System.out.println(sw.toString()); //可以读取一行。 //StringWriter sw2 = new StringWriter(); //char [] ch = new char [1024]; //while((len = sr.read(ch))!=-1){ // sw2.write(ch,0,len); //} //System.out.println("SW2:"+sw.toString()); } }【10】
操作流 、序列化
ObjectInputStream--ObjectOutputStream
Serializable
操作流 、序列化
(对象被产生后存在于堆里面,而一旦使用完之后,就会消失,如何将对象存储到硬盘中呢)ObjectInputStream--ObjectOutputStream 相互对应一个存,一个取void writeObject(Object obj)--Object readObject() 方法也是对应的。
注意:
1、被操作的对象必须实现 Serializable 接口
1、被操作的对象必须实现 Serializable 接口
这接口太爽了,只需要实现,其他什么也不用写
2、自定义序列号
static final long serialVersionUID = 42L; 42L为自定义序列号
3、静态成员变量不能被序列号
(静态在方法区,能被序列的都在堆内存中)
普通成员变量想要不被序列号必须加关键字:
这样该成员不被序列号,但存在与堆内存中。
结合 $1Person 完成 操作流 、序列化 的演示
比如,添加一个静态成员变量
(这个时候,在 $1Person 添加静态成员,并初始化到构造方法中 运行发现 是一个null )
为什么呢
因为 序列号是根据 成员变量生成的,是在堆内存中
而静态成员变量是在方法区中所以不可被序列化
那么,可不可以 让 普通成员变量也不被序列化呢?
java 提供了一个关键字: transizent
(给年纪 用该关键字修饰 发现 打印的年纪 为0 )
发现,当 $1Person 设定完成后,进行操作流生成文件并能阅读
而一旦, $1Person 发生变化时,该文件不可被读取了,
因为 Serializable 根据 $1Person 的成员变量,生成了一个 序列号
当 成员变量发生变化时候,序列号会随着变化。 所以不能被阅读
为了避免这种情况,可以给类设定一个固定序列号,以保证唯一性:
在 $1Person 设定静态成员变量
static final long serialVersionUID = 42L;
最后,一般文件都存为 .Object (因为文件无法阅读,都是乱码 )
import java.io.*; class ObjectStream { public static void main(String[] args) throws Exception{ //writrObj(); readerObj(); } public static void writrObj() throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\Demo\\obj\\Person.Object")); oos.writeObject(new Person("liuh",19,"ch")); oos.close(); } public static void readerObj() throws Exception{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\Demo\\obj\\Person.Object")); Person p =(Person) ois.readObject(); System.out.println(p); } } class Person implements Serializable{ String name="111"; transient nt age=22; //不序列化关键字 static String guo="bbq"; Person(String name, int age,String guo){ this.name = name; this.age = age; this.guo = guo; } public String toString(){ return name+">>"+age+":"+guo; } }【11】
字符编码表
1/
-----------------------------
字符流的出现为了方便操作字符
更重要的是加入了编码转换
通过子类转换流完成
InputStreamReaderOutoutStreamWriter
在两个对象进行构造时,可以加入字符集也就是编码表
----------------------------------------------------------
什么是编码表?
1、计算机只能识别二进制数据,早期由来是电信号
2、为了方便应用计算机,让它可以识别各个国家的文字
3、于是将各个国家的文字用数字来表示,并一一对应,形成一张表。
----------------------------------------------------------
什么是编码表?
1、计算机只能识别二进制数据,早期由来是电信号
2、为了方便应用计算机,让它可以识别各个国家的文字
3、于是将各个国家的文字用数字来表示,并一一对应,形成一张表。
这就是编码表。
----------------------------------------------------------
常见编码表:
ASCII 美国标准信息交换码
常见编码表:
ASCII 美国标准信息交换码
用一个字节的7位表示
ISO8859-1
拉丁码表。欧洲码表
用一个字节的8位表示
GB2312
中国的中文编码表
GBK 中国的文字编码表升级,融合了更多的中文文字符号
Unicode 国际标准码,融合了多种文字
GBK 中国的文字编码表升级,融合了更多的中文文字符号
Unicode 国际标准码,融合了多种文字
所有文字都是用两个字节表示Java语言使用的就是该编码表
UTF-8
最多用三个字节来表示一个字符
。。。。
----------------------------------------------------------
2/
编码: 字符串 变 字节数组。
解码: 字节数组 变 字符串。
String --> byte[] : str.getBytes(charsetName);
。。。。
----------------------------------------------------------
2/
编码: 字符串 变 字节数组。
解码: 字节数组 变 字符串。
String --> byte[] : str.getBytes(charsetName);
[charsetName 指定编码表(不指定用默认GBK编码表)]
byte --> String:
newString(byte[],charsetName);
-----------------------------------------------
遇到不知道什么编码的情况下
可以用“你好” 编码解码根据结果:
返回:?? 编码GBK ----> 解码UTF-8
返回:浣犲ソ 编码UTF-8----> 解码 GBK
------------
-----------------------------------------------
遇到不知道什么编码的情况下
可以用“你好” 编码解码根据结果:
返回:?? 编码GBK ----> 解码UTF-8
返回:浣犲ソ 编码UTF-8----> 解码 GBK
------------
class $7EncodeStream { public static void main(String[] args) throws Exception{ toEncode_1(); } public static void toEncode_1()throws Exception{ String s = "我去"; byte [] b1 = s.getBytes("GBK");//默认GBK编码表 System.out.println(Arrays.toString(b1));//记住数组变字符串的方法。 String ss = new String(b1,"UTF-8"); System.out.println("ss:"+ss); //出现解码错误的情况-进行UTF-8编码 byte [] b2 =ss.getBytes("UTF-8"); //进行GBK 解码 String s3 = new String(b2,"GBK"); System.out.println(Arrays.toString(b2)); System.out.println("ss:"+s3); } public static void toEncode()throws Exception{ String s = "你好"; byte [] b1 = s.getBytes("GBK");//默认GBK编码表 //byte [] b1 = s.getBytes("ISO8859-1");//【1】 编码错误的时候,就不要解码了。 System.out.println(Arrays.toString(b1));//记住数组变字符串的方法。 String ss =// new String(b,"GBK");//默认GBK编码表 new String(b1,"UTF-8"); System.out.println("ss:"+ss); //--------------- //出现解码错误的情况 String s2 = new String(b1,"ISO8859-1");//【2】解码错误的时候该如何处理: 再编码,在再解码一次: //对s2 进行ISO8859-1 编码 byte [] b2 =s2.getBytes("ISO8859-1"); //进行GBK 编码 String s3 = new String(b2,"GBK"); System.out.println("ss:"+s3); } }
对于 toEncode 中 出现ISO8859-1 解码错误
如果编码GBK 解码UTF-8 出现解码错误 根据前面的经验
进行 对UTF-8 进行编码 再用GBK 解码 会是正确结果吗?
-----发现错误,发现第一次编码的时候是4个字节,而再次编码的时候却是9个字节
他的把前面的三位?号有3个,所以对应是9个字节
为了验证,我们把“你好”更改为“哈哈”----发现?号变成了4个,对应变成了12个字节
----因为GBK和UTF-8 都识别中文,导致的错乱。
-----------------------------------------------
3/
联通
String --> byte[] : str.getBytes(charsetName);
byte --> String: newString(byte[],charsetName);
----------------------------------
联通:
-63 -86 -51-88
转换二进制,&255 取八位
-63--> 11000001
-86--> 10101010
-51--> 11001101
-88--> 10101000
这个时候,对这个二进制,解码的时候,
UTF-8 -- 最多3个字节,那么编译时如何知道是1个还是2 个3个字节?
1、 读到开头 0 把这个1字节 带去查表
2、 读到开头 110 会直接跳到下一行 读取10 然后把这2个字节 带去查表
3、 读到开头 1110 会跳过 读取 两行 10 10 然后把这3个字节 带去查表
----------------------------------
这个时候我们发现,
“联通”是 GBK 编码 但是 产生的二进制形式 居然和 UTF-8 一致
这就是为什么 会出现乱码了,因为识别的时候,为上列第2中
然后去查UTF-8码表。自然就错了。
如果编码GBK 解码UTF-8 出现解码错误 根据前面的经验
进行 对UTF-8 进行编码 再用GBK 解码 会是正确结果吗?
-----发现错误,发现第一次编码的时候是4个字节,而再次编码的时候却是9个字节
他的把前面的三位?号有3个,所以对应是9个字节
为了验证,我们把“你好”更改为“哈哈”----发现?号变成了4个,对应变成了12个字节
----因为GBK和UTF-8 都识别中文,导致的错乱。
-----------------------------------------------
3/
联通
String --> byte[] : str.getBytes(charsetName);
byte --> String: newString(byte[],charsetName);
----------------------------------
联通:
-63 -86 -51-88
转换二进制,&255 取八位
-63--> 11000001
-86--> 10101010
-51--> 11001101
-88--> 10101000
这个时候,对这个二进制,解码的时候,
UTF-8 -- 最多3个字节,那么编译时如何知道是1个还是2 个3个字节?
1、 读到开头 0 把这个1字节 带去查表
2、 读到开头 110 会直接跳到下一行 读取10 然后把这2个字节 带去查表
3、 读到开头 1110 会跳过 读取 两行 10 10 然后把这3个字节 带去查表
----------------------------------
这个时候我们发现,
“联通”是 GBK 编码 但是 产生的二进制形式 居然和 UTF-8 一致
这就是为什么 会出现乱码了,因为识别的时候,为上列第2中
然后去查UTF-8码表。自然就错了。
class $8EncodeStream{ public static void main(String[] args) throws IOException{ lianTong_1(); } public static void lianTong_1() throws IOException{ String s = "好号"; byte [] by = s.getBytes("GBK"); sop(Arrays.toString(by)); sop("--------"); for(byte b : by){ sop(b);// //sop(Integer.toBinaryString(b));//【记住,转换二进制】。但是太长,只想要后8位怎么办? sop(Integer.toBinaryString(b & 255));//【记住,& 255】 } sop("--------"); String s1 = new String(by,"UTF-8"); sop(s1); sop("--------"); String s2 = new String(by,"GBK"); sop(s2); sop("--------"); } public static void lianTong() throws IOException { String s = "联通"; byte [] by = s.getBytes("UTF-8"); sop(Arrays.toString(by)); String s1 = new String(by,"UTF-8"); sop(s1); sop("--------"); String s2 = new String(by,"GBK"); sop(s2); } public static void sop(Object obj){ System.out.println(obj); } }据说,编码表是 程序员心中永远的通。。哈哈,不过还体会不到啊。
---------------------------------------------------------------------------------------------------------------------------------------------
----------
android培训、
java培训、期待与您交流!----------
----------------------------------------------