流与文件
流可以分为字节流以及字符流,字节流以抽象类InputStream以及OutputStream构成其主框架,字符流以抽象类Reader以及Writer构成其主体框架.
1. 抽象类InputStream和OutputStream构成了输入/输出(I/O)类层次结构,主要处理字节流(单个字节或者是字节数组)。字节流的子类DataInputStream和DataOutputStream可以读写字符串和数字,其是以二进制格式读写所有基本的java类型。
2. 抽象类Reader和Writer专门用于处理字符流。
Read和write方法在执行时都将阻塞,直至字节确实被读入或者写入。换句话说,如果留不能被立即访问,那么当前的线程将会被阻塞。这使得在这两个方法等待指定的流变为可用的的这段时间里,其他的线程将会有机会去执行其他工作。当读写工作完成后应该调用close方法关闭它,这样就可以释放掉有限的系统资源。同时,还会冲刷用于该输出流的缓冲区:所有被临时置于缓冲区中,以便使用更大的包的形式传递的字符在 关闭输出流时将被送出。特别是,如果不关闭文件,那么写出字节的最后一个包可能永远也得不到传递。
3. 对象序列化指把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输)。这个过程称为序列化。通俗来说就是将数据结构或对象转换成二进制串的过程
package test;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.PushbackInputStream;
import java.io.Serializable;
import java.util.Scanner;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* 流与文件、对象序列化
* @author houst
*/
public class Test {
public static void main(String[] args) {
new Test().Stream();
}
public void Stream(){
try {
//获取当前路径
String userDir= System.getProperty("user.dir");
System.out.println(userDir);
String filePath = userDir + "\\text.txt";
String zipPath = userDir + "\\text.zip";
/*流*/
/*
* FileInputStream()和FileOutputStream
* 可以提供附着在一个磁盘文件上的输入流和输出流。
*
*/
File f = new File(zipPath);
f.createNewFile();
FileInputStream fin = new FileInputStream(filePath);
//读取字节以及字节数组
int finInt = fin.read();
/*
* 字节流的子类DataInputStream和DataOutputStream
* 可以读写字符串和数字,其是以二进制格式读写所有基本的java类型。
*/
DataInputStream din = new DataInputStream(fin);
// din.readInt();
/*
* BufferedInputStream()
* 创建一个带缓冲区的流。带缓冲区的输入流从流中读取字符时,不会每次都对设备进行访问。
* 当缓冲区为空时,会向缓冲区读入一个新的数据块。
*
* 流在默认情况下是不被缓冲去还存的,每个对read的调用都会请求系统再次分发一个字节,
* 此机制效率低下。如果请求一个数据块,并且将其置于缓冲区中,这样会更加的高效。
* DataInputStream放在最后是因为要使用readByte()方法。
*/
DataInputStream dinBufferFin = new DataInputStream(new BufferedInputStream(fin));
/* dinBufferFin.readByte();*/
/*
* PushbackInputStream()
* 构建一个可以预览一个字节或者具有指定长度的回推缓冲区的流
*
* 当多个流连接在一起的时候,你需要跟踪各个中介流。例如,当读入输入时,经常需要浏览下一个字节
* 以了解其是否自己想要的值。Java 提供了用于此目的的PushbackInputStream.
*
*/
PushbackInputStream pbin = new PushbackInputStream(
new BufferedInputStream(
new FileInputStream(filePath)));
//预读下一个字节
int nextByte = pbin.read();
//下一个字节不是想要的就将其回推到流中。
if (nextByte != 2) {
pbin.unread(nextByte);
}
/*
* 经过DataInputStream,PushbackInputStream封装以后,
* 则该流就即使一个回推流,有是一个数据流。
*
*/
DataInputStream dPBFin = new DataInputStream(
pbin = new PushbackInputStream(
new BufferedInputStream(
new FileInputStream(filePath))));
/* int nextByte2 = dPBFin.readInt();*/
/*
* 从zip压缩文件中读取数据
* 然后在dataInputStream流中读取数字
*/
ZipInputStream zin = new ZipInputStream(new FileInputStream("text.zip"));
DataInputStream dzin = new DataInputStream(zin);
/*文本的输入与输出 */
//从控制台读取键盘的信息
InputStreamReader in = new InputStreamReader(System.in);
//以指定的编码格式读取文件
InputStreamReader in2 = new InputStreamReader(
new FileInputStream(filePath), "MS932");
//文本的输出
PrintWriter out = new PrintWriter(filePath);
String temp = "test";
out.write(temp);
//文本的输入
BufferedReader bin = new BufferedReader(
new InputStreamReader(
new FileInputStream(filePath)));
bin.readLine();
/*zip文档 */
/*
* ZipInputStream来读入ZIP文档。
* 如果需要浏览文档中每个单独的项,getNextEntry方法会返回一个描述这些
* ZipEntry类型的对象。ZipInputSteam中的read方法被修改为碰到当前
* 项的结尾时返回-1,所以必须closeEntry来读入下一项
*
* 注:读取单个zip流时,不要将其关闭,也不要将其传递给可能会关闭它的流。否则
* 后续的内容将无法读取到
*/
ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipPath));
ZipEntry zipEntry= zipIn.getNextEntry();
while (zipEntry != null ) {
//关闭当前项,进入下一项
zipIn.closeEntry();
break;
}
zipIn.close();
//读取zip的单个文件内容时,可以使用以下循环
Scanner sin = new Scanner(zipIn);
while (sin.hasNextLine()) {
//do things
sin.nextLine();
break;
}
/*
* 要写到zip文件,使用ZipOutPutStream。对于放入到zip文件的每一项,都应该创建
* ZipEntry对象,并将文件名传递给ZipEntry的构造器,它将设置文件日期以及解压缩
* 方法等参数。然后需要调用putNextEntry方法写新文件,并将文件数据发送到zip流中。
* 并且,完成时时,需要调用closeEntry。并且对所有的文件重复这个过程
*
*/
FileOutputStream fout2 = new FileOutputStream(zipPath);
ZipOutputStream zout = new ZipOutputStream(fout2);
byte[] b = {2};
//对每一个文件创建ZipEntry对象,并写入新文件
for (int i = 0; i < 3; i++) {
String fileName = userDir + "\\text" + i + ".txt";
File f2 = new File(fileName);
f2.createNewFile();
ZipEntry ze = new ZipEntry(fileName);
zout.putNextEntry(ze);
//写入数据
zout.write(b);
zout.closeEntry();
}
zout.close();
/*对象序列化*/
/*
* 序列化:指把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给
* 其他网络节点(在网络上传输)。这个过程称为序列化。
* 通俗来说就是将数据结构或对象转换成二进制串的过程
*
* 反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。
* 也就是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程
*
*
* 整个过程都是 Java 虚拟机(JVM)独立的,也就是说,
* 在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象。
*
* transient修饰的成员属性是不会被序列话的
*
* ①、需要做序列化的对象的类,必须实现序列化接口:Java.lang.Serializable 接口
* (这是一个标志接口,没有任何抽象方法)
* ②、底层会判断,如果当前对象是 Serializable 的实例,才允许做序列化。
* ③、在 Java 中使用对象流来完成序列化和反序列化
* ObjectOutputStream:通过 writeObject()方法做序列化操作
* ObjectInputStream:通过 readObject() 方法做反序列化操作
*
*/
//对象序列化,可以将任何一种对象写出到流中,并且在之后将其读回。
ObjectOutputStream oout = new ObjectOutputStream(
new FileOutputStream(filePath));
Employee e1 = new Employee("e1",21);
Employee e2 = new Employee("e2",22);
//写入对象
oout.writeObject(e1);
oout.writeObject(e2);
//用ObjectInputStream按照对象写入的顺序将对象读入。
ObjectInputStream oin = new ObjectInputStream(
new FileInputStream(filePath));
//读入对象
Employee e1in = (Employee) oin .readObject();
Employee e2in = (Employee) oin.readObject();
/*
* 当一个对象被多个对象共有时,每个对象都必须进行序列化。
* 如以下程序所示,harr,分别在m1以及m2中存在。
* 当harr对象被加载之后是唯一的,当对象被恢复以后,可以看见
* m1/m2中的harr是一样的。
*
*/
Employee harry = new Employee("har", 20);
Manager m1 = new Manager("m1", 31, "123", harry);
Manager m2 = new Manager("m2", 32, "123", harry);
Employee[] ms = {m1, harry, m2};
oout.writeObject(ms);
oout.flush();
Employee[] es = (Employee[]) oin.readObject();
es[1].setName(es[1].getName() + "test");
for (Employee e: es) {
System.out.println(e);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Employee implements Serializable{
/**
*
*/
private static final long serialVersionUID = 2366794297976962105L;
private String name;
private transient int age;
public Employee() {
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return this.name + "," + this.age;
}
}
class Manager extends Employee implements Serializable{
/**
*
*/
private static final long serialVersionUID = -8440361406957871256L;
private String moneny = "";
private Employee e;
private int temp ;
public Manager(String name, int age, String moneny, Employee e) {
super(name, age);
this.moneny = moneny;
this.e = e;
}
public Manager(String name, int age, String moneny, Employee e, int temp) {
super(name, age);
this.moneny = moneny;
this.e = e;
this.temp = temp;
}
public int getTemp() {
return temp;
}
public void setTemp(int temp) {
this.temp = temp;
}
public Manager() {
}
public Employee getE() {
return e;
}
public void setE(Employee e) {
this.e = e;
}
public String getMoneny() {
return moneny;
}
public void setMoneny(String moneny) {
this.moneny = moneny;
}
@Override
public String toString() {
return super.getName() + "," + super.getAge();
}
}