IO流(对象的序列化)
1、一般要序列化的类:
a) 实现Serializable 以启用其序列化功能
b) 在该类中定义固定的序列号:
static final longserialVersionUID = 42L;
注意:序列号的作用就是给类一个标识
2、静态不能被序列化
被transient 修饰的变量也不能被序列化
3、ObjectInputStream和 ObjectOutputStream是成对使用的
4、操作对象:
ObjectInputStream和 ObjectOutputStream
被操作的对象需要实现Serializable接口,(标记接口)
5、一般保存之后文件名的后缀为.object
例子:
/**
调用序列化的类
*/
import java.io.*;
class Demo1
{
publicstatic void main(String[] args)throws Exception
{
readObj();
}
//存文件
publicstatic void writeObj()throws IOException
{
FileOutputStreamfos = new FileOutputStream("demo1.object");
ObjectOutputStreamoos = new ObjectOutputStream(fos);
oos.writeObject(newPerson("lili",20));
oos.close();
}
//读文件
publicstatic void readObj()throws Exception
{
FileInputStreamfis = new FileInputStream("demo1.object");
ObjectInputStreamois = new ObjectInputStream(fis);
Personp =(Person)ois.readObject();
System.out.println(p);
ois.close();
}
}
IO流(管道流)
1、PipedInputStream和 PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用。
2、注意:要先把管道接上,接上管道的方法有两种
l 构造函数:
PipedOutputStream(PipedInputStreamsnk)throws IOExcepiton
PipedInputStream(PipedOutputStreamsrc)throws IOException
public void connect(PipedInputStream snk)
l throws IOException
public void connect(PipedOutputStream src)
throws IOException
示例:
import java.io.*;
//描述一个写入类
class Write implements Runnable
{
//写入管道
private PipedOutputStreampos;
Write(PipedOutputStreampos)
{
this.pos=pos;
}
public void run() //记住这里的run方法不能够抛出异常,因为父类没有抛出
{
try
{
//写入
pos.write("xierulai le ".getBytes());
pos.flush();
pos.close();
}
catch (IOExceptione)
{
throw newRuntimeException("写入失败");
}
}
}
//描述一个读取类
class Read implements Runnable
{
//读取管道
private PipedInputStreampis;
Read(PipedInputStreampis)
{
this.pis=pis;
}
public void run()
{
try
{
//读取数据
byte[]buf=new byte[1024];
int len =pis.read(buf); //记住这个方法返回的是int型的
String s=new String(buf,0,len); //记住这个
System.out.println(s);
pis.close();
}
catch (IOExceptione)
{
throw newRuntimeException("读取失败");
}
}
}
class Demo2
{
public static voidmain(String[] args)throws Exception
{
PipedInputStreampis = new PipedInputStream();
PipedOutputStreampos =new PipedOutputStream();
//先要把流接上
pos.connect(pis);
Read read = newRead(pis);
Write write = newWrite(pos);
newThread(read).start();
newThread(write).start();
}
}
IO流(RandomAccessFile)
1、随机访问文件,自身具备读写的方法
通过skipBytes(int x) 或者seek(int x)来达到随即访问。
2、特点:
l 该类不算是IO体系中子类,而是直接集成Object。
l 但是他是IO包中成员,因为它具有读写的功能,内部封装了一个字节型数组,可以通过指针对数组中的元素进行操作。通过getFilePointer获取指针的位置;通过seek该指针的位置。
l 其实完成读写的原理就是内部封装了字节输入流和字节输出流
l 通过构造函数,可知,该类只能操文件,而且操作的文件还有模式:
只读:r 或者 读写:rw
如果模式为只读(r),不会创建文件,会读取一个已经存在的文件,如果文件不存在,则会出现异常
如果模式为读写(rw),如果文件存在,不会覆盖原文件,如果文件不存在,会创建文件。
3、用处:可以实现数据的多线程读写。
把要操作的数据分段,然后分别分装在不同的线程中,通过控制指针,实现同时分段的操作,而且这样的数据是连续的。
4、对操作的数据的要求:数据的格式是一致,例如:前两个字节存名字,后四个字节存姓名。(格式为:(2,4))
5、举例:
importjava.io.*;
class Demo3
{
publicstatic void main(String[] args)throws IOException
{
//wirteFile();
readFile();
}
//写
publicstatic void wirteFile()throws IOException
{
RandomAccessFileraf = new RandomAccessFile("ran.txt","rw");
raf.write("李四".getBytes());
raf.writeInt(97);
raf.write("王五".getBytes());
raf.writeInt(98);
raf.close();
}
//读
publicstatic void readFile()throws IOException
{
RandomAccessFileraf = new RandomAccessFile("ran.txt","r");
//改变指针位置
//raf.seek(8);
//raf.skipBytes(8*0);
byte[]buf =new byte[4];
raf.read(buf); //读取四个字节放在字节数组中
//将字节数组转换为字符串
Stringname = new String(buf);
intage=raf.readInt(); //接着读取4个字节
System.out.println(name+",....."+age);
}
}
IO流(操作基本数据类型的流对象)
1、操作基本数据类型:
DataInputStream和 DataOutputStream
3、如果使用了utf-8修改版编码写入的数据,只能够用对应的读取进行读取
4、示例:
import java.io.*;
class Demo4
{
public static voidmain(String[] args)throws IOException
{
//write();
//read();
//writeUTF8();
readUTF8();
}
//写
public static voidwrite()throws IOException
{
DataOutputStreamdis =
newDataOutputStream(new FileOutputStream("data.txt"));
dis.writeChar('a');
dis.writeInt(23);
dis.close();
}
//读
public static voidread()throws IOException
{
DataInputStreamdis =
newDataInputStream(new FileInputStream("data.txt"));
System.out.println(dis.readChar());
System.out.println(dis.readInt());
dis.close();
}
//utf-8修改版写,只是针对中文
public static voidwriteUTF8()throws IOException
{
DataOutputStreamdos =
newDataOutputStream(new FileOutputStream("data1.txt"));
dos.writeUTF("你好");
dos.close();
}
//utf-8修改版读,只是针对中文
public static voidreadUTF8()throws IOException
{
DataInputStream dis =
newDataInputStream(new FileInputStream("data1.txt"));
System.out.println(dis.readUTF());
dis.close();
}
}
IO流(ByteArrayStrea)
1、操作字节的数组:
ByteInputStream 和 ByteOutputStream
2、操作字符的数组:
CharReader 和 CharWriter
3、操作字符串的数组:
StringReader 和 StringWriter
4、用于操作字节数组的流对象:
l ByteArrayInputStream:在构造的时候需要源,而且源是一个字节数组
l ByteArrayOutputStream: 在构造的时候不需要定义目的,因为该对象的内部已经封装了可变长度的字节数组,而这个数组就是数据的目的。
l
注意:因为这两个流对象操作的都是数组,并没有使用系统的资源,所以不用关闭。
l 在流操作的讲解时:
² 源设备:
键盘(System.in)、硬盘(File)、内存(ArrayStream)
² 目的:
键盘(System.out)、硬盘(File)、内存(ArrayStream)
作用:可以用流操作的思想来操作数组
5、例子:
import java.io.*;
class Demo5
{
public static voidmain(String[] args)
{
ByteArrayMethod();
}
public static voidByteArrayMethod()
{
//源
ByteArrayInputStreambais =
newByteArrayInputStream("abdcdde".getBytes());
//目的
ByteArrayOutputStreambaos =
newByteArrayOutputStream();
int len =0;
while((len=bais.read())!=-1)
{
baos.write(len);
}
System.out.println(baos.size());
System.out.println(baos.toString());
}
}
IO流(转换流的字符编码)
1、字符流的出现是为了方便操作字符,更重要的是加入了编码转换。
2、字符流的编码转换:InputStreamReader和 OutputStreamWriter
3、在两个对象进行构造的时候,可以加入字符集
4、编码表:将各国的文字和数字一一对应,形成了一表,叫做编码表。
5.、各种编码表,其中常用的是gbk,utf-8,iso8859-1(服务器)
例子:
import java.io.*;
class Demo6
{
publicstatic void main(String[] args)throws IOException
{
//write();
read();
}
//写
publicstatic void write()throws IOException
{
OutputStreamWriterosw =
newOutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");
osw.write("你好");
osw.close();
}
//读
publicstatic void read()throws IOException
{
InputStreamReaderisr=
newInputStreamReader(new FileInputStream("gbk.txt"),"gbk");
char[]buf=new char[10];
intlen=isr.read(buf);
Stringstr =new String(buf,0,len);
System.out.println(str);
isr.close();
}
}
IO流(字符编码)
1、编码:将字符串变为字节数组
String----byte[] : str.getBytes(编码名);
2、解码:将自己数组编程了字符串
byte[]----String: new String(byte[],编码名);
3、在编码、解码的过程中,第一次编码编对了,但是在第一次解码的时候,解错了。这个时候,我们采取的措施就是,按照错误的解码,再对其进行一次编码,然后按照第一次编码中的编码表进行解码。这种现象常会使用在服务器上。
示例:
import java.io.*;
import java.util.*; //Arrays是util包中的
class Demo7
{
public static voidmain(String[] args)throws Exception
{
demo();
}
public static voiddemo()throws Exception
{
//字符串
String str ="你好";
//编码,正确
byte[] by1=str.getBytes("GBK");
//打印字节数组,查看
System.out.println(Arrays.toString(by1));
//第一次解码,错误
String str1= newString(by1,"ISO8859-1");
System.out.println(str1);
//对str1进行编码
byte[] by2 =str1.getBytes("iso8859-1");
System.out.println(Arrays.toString(by2));
//对by2进行解码
String str2 = newString(by2,"gbk");
System.out.println(str2);
}
}
IO流(字符编码—联通)
/**
一个有趣的现象:
当我们在记事本中顶头写“联通”保存之后,再次打开的时候,发生了乱码的现象
原因:
我们输入的时候,使用的是gbk,
但是由于“联通”这两个字的编码形式符合utf-8,
所以当我们再次使用记事本打开的时候,记事本会默认按照utf-8的读取形式进行读取。
代码模拟:
*/
class Demo8
{
public static void main(String[] args)throwsException
{
demo();
}
//模拟
public static voiddemo()throws Exception
{
String str ="联通";
//编码,按照gbk
byte[] by=str.getBytes("gbk");
for(byte b : by)
{
System.out.println(Integer.toBinaryString(b&255));
/*
11000001
10101010
11001101
10101000
这个格式符合utf-8的读取形式。
*/
}
}
}
1、在描述类的时候,要覆盖hashCode、public boolean equals(Object obj)、toString()