一.java.io.File类
- java.io.File类用于表示文件/目录
- File只用于表示文件的信息(名称,大小等),不能用于文件内容的访问
- RandomAccessFile java提供的对文件内容的访问(可以对文件进行读写),可以访问文件的任意位置
- 代码位置
java文件模型
在硬盘上的文件是byte btye btye存储的,是数据的集合
二.RandomAccessFile 类对于文件的读写
- 打开文件
有两种模式 "rw"(读写) "r"(只读)
RandomAccessFile raf = new RandomeAccessFile(file,"rw");
文件指针,打开文件时指针在开头 pointer = 0; - 写方法
raf.write(int) 只写一个字节(后8位) ,同时指针指向下一个位置,准备再次写入 - 读取文件
int b = raf.read(); 只读一个字节 - 文件读写后一定要关闭raf.close()
- 代码位置
IO流(输入流,输出流)
三.字节流
- InputStream 抽象了应用程序读取数据的方式
- OutputStream 抽象了应用程序写出数据的方式
- EOF = End 读到-1就到文件结尾
- 输入流基本方法
int b = in.read();读取一个字节无符号填充到int的低八位,前面补0, -1是EOF
in.read(byte[] buf) 读取数据填充到字节数组buf中
in.read(byte[] buf, int start, int size) 从输入流的start开始位置存放size长度的数据到buf数组中; - 输出流的基本方法
out.write(int b) 写出一个byte到流,b的低八位
out.write(byte[] buf) 将buf字节数组写入到流
out.write(btye[], int start ,int size) 字节数组buf从start开始位置写size长度的字节到流 -
FileInputStream 具体实现了在文件上读取数据
- FileOutputStream 实现了向文件中写出byte数据的方法
- 代码位置
四.对流功能的扩展,可以更加方便的读取int,long,z字符等类型的数据;
其实方式只是封装了FileInputStream和FileOutputStream的write和read方法,
注意写入文件的内容还是字节码
比如:DataOutputStream.writeInt() 实现方式调用FileOutputStream.write()四次写入四个字节而已
- DataOutputStream 写出数据
/**
* 对流功能的扩展写出数据(DataOutputStream)
* @throws IOException
*/
public static void dataOut(File file) throws IOException
{
DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
//写入一个整型10
out.writeInt(10);
//写入一个整型20
out.writeInt(20);
//写入一个长整型10
out.writeLong(10l);
//写入一个布尔true
out.writeBoolean(true);
//写入一个双浮点
out.writeDouble(10.5);
//写入一个UTF-8编码的字符
out.writeUTF("中国我爱你");
out.close();
}
- DataInputStream 读取数据
/**
* 对流功能的扩展读取数据(DataInputStream)
* 注意写入文件的内容还是字节码
* @throws IOException
*/
public static void dataInput(File file) throws IOException
{
DataInputStream in = new DataInputStream(new FileInputStream(file));
//读取一个整形数据
int int1 = in.readInt();
//读取一个整形数据
int int2 = in.readInt();
//读取一个长整型数据
long int3 = in.readLong();
//读取一个boolean数据
boolean b = in.readBoolean();
//读取一个Double类型数据
Double d = in.readDouble();
//读取一个utf8编码的数据
String str1 = in.readUTF();
//以下数据结果:10, 20, 10, true, 10.5, 中国我爱你
System.out.println(int1 + ", " + int2 + ", " + int3 + ", " + b + ", " + d + ", " + str1);
in.close();
}
测试:
File file = new File("/home/lxf/test/test.php");
IOUtil.dataOut(file);
IOUtil.dataInput(file);//输出:10, 20, 10, true, 10.5, 中国我爱你
五.字节流缓冲
BufferedInputStream & BufferedOutputStream
这两个字节流未IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时候,都会加上缓冲,这种模式提高了IO的性能;
从应用程序中把输入放入文件,相当于将一缸水导入另一个缸中;
- FileOutputStream.write()方法相当与一滴一滴的把水"转移"过去
- DataOutputStream.writeXxx()方法会方便一些,一瓢一瓢的把水"转移"
- BufferedOutStream.write()方法更方便一些,先将水,一瓢一瓢的放入桶中,然后在从桶中"转移"到另一个容器中;
- 三种方式copy文件,速度比较:字节批量读取 > 带缓冲方式 > 单个字节方式
FileIutputStream.read(buf,0,buf.length) > BufferedOutStream.read() > FileIutputStream.read()
五.字符流
java中的文本(char) : 是16位的无符号整数,是字符的unicode编码( 双字节编码 )
文件: 是byte byte btye....的数据序列
文本文件是文本(char)序列按着某种编码方案(UTF-8, UTF-16be,gbk等)序列化为byte的存储结果
两个抽象类(Reader, Writer)操作的是文本文件;
字符的处理是一次处理一个字符
字符的底层仍然是基本的字节序列
-
两个实现类
InputStreamReader 完成byte流解析为char流, 按着编码解析//原文件读取 FileInputStream in = new FileInputStream(srcFile); InputStreamReader isr = new InputStreamReader(in, "utf-8");
OutStreamWriter 提供char流到byte流, 按着编码处理
//目标文件写入 FileOutputStream out = new FileOutputStream(destFile); OutputStreamWriter osw = new OutputStreamWriter(out,"utf-8");
FileReader 和 FileWriter 两个类以对文件直接读写
FileReader reader = new FileReader(srcFile);
FileWriter writer = new FileWriter(destFile);
五.字符流的过滤器
- BufferedReader 一次读一行
//对文件进行读取操作
FileInputStream in = new FileInputStream(srcFile);
InputStreamReader isr = new InputStreamReader(in, "utf-8");
//FileReader isr = new FileReader(srcFile);
BufferedReader br = new BufferedReader(isr);
- BufferedWriter/PrintWriter 一次写一行
//对文件进行写入操作
FileOutputStream out = new FileOutputStream(destFile);
OutputStreamWriter isr1 = new OutputStreamWriter(out, "utf-8");
BufferedWriter bw = new BufferedWriter(isr1);
或
PrintWriter pw = new PrintWriter(destFile);
六.序列化的基本操作
- 对象的序列化 : 就是将Object转换成byte序列, 反之叫对象的反序列化;
- 序列化流 ( ObjectOutputStream )
- 反序列化流 ( ObjectInputStream )
- 序列化接口 ( Serializable )
对象必须实现序列化接口,才能进行序列化 - 代码位置
七. transient关键字
- transient 关键字标识的实体类属性不会进行jvm的默认序列化
- 也可以自己完成该元素的序列化
/**
* Students学生实体类, 实现了Serializable接口,可以被序列化
* @author lxf
*
*/
public class Students implements Serializable {
private int id;
private String uname;
//transient关键字,表明pass属性不会进行jvm的默认序列化, 也可以自己完成该元素的序列化
private transient String pass;
/*
* 自己完成被transient关键字修饰的属性序列化
*/
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException
{
//把jvm能默认序列化的元素进行序列化操作
s.defaultWriteObject();
//自己完成pass的序列化
s.writeObject(pass);
}
/*
* 自己完成被transient关键字修饰的属性反序列化
*/
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException
{
s.defaultReadObject();
this.pass = (String) s.readObject();
}
八.序列化中子类和父类构造函数的调用问题
- 一个类实现了序列化接口,那么其子类都可以进行序列化
- 对于类对象进行反序列化操作时,如果其父类没有实现序列化接口,而子类自己实现了序列化接口,那么其父类的构造函数会被调用,
- 对于类对象进行反序列化操作时,如果其父类实现序列化接口,二子类没有实现了序列化接口,那么其父类的构造函数不会被调用,
class Foo {
public Foo(){
System.out.println("Foo...");
}
}
class Foo1 extends Foo implements Serializable{
public Foo1(){
System.out.println("Foo1...");
}
}
class Foo2 extends Foo1 implements Serializable{
public Foo2(){
System.out.println("Foo2...");
}
}
File file = new File("/home/lxf/test/Foo2");
Foo2 f = new Foo2();
/*
* 将Foo2对象序列化存储到/home/lxf/test/Foo2
* 控制台依次输出:
* Foo...
Foo1...
Foo2...
*/
SerializeDemo.ObjSaveToFile(file, f);
/*
* 将/home/lxf/test/Foo2中的序列化后的内容反序列化读出为对象
* 控制台依次输出:
* Foo...
com.lxf.IOStream.Foo2@732768bb
说明:
对于类对象进行反序列化操作时,如果其父类没有实现序列化接口,而子类自己实现了序列化接口,那么其父类的构造函数会被调用
对于类对象进行反序列化操作时,如果其父类实现序列化接口,而子类没有实现了序列化接口,那么其父类的构造函数不会被调用
*/
SerializeDemo.seriFileToObj(file);