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培训、期待与您交流!----------
----------------------------------------------