字节流与字符流
字节输出流OutputStream
-
这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。public abstract class OutputStream extends Object implements Closeable, Flushable
需要定义
OutputStream
子类的应用OutputStream
必须至少提供一个写入一个字节输出的方法。
初始化:
File file = new File("文件路径");
OutputStream out = null;
out = new FileOutputStream(file);
// out = new FileOutputStream(file, true); // 追加新内容的初始化
字节输入流InputStream:
-
这个抽象类是表示输入字节流的所有类的超类。public abstract class InputStream extends Object implements Closeable
需要定义
InputStream
子类的应用InputStream
必须始终提供一种返回输入的下一个字节的方法。
初始化字节输入流:
File file = new File("文件路径");
InputStream input = null;
input = new FileInputStream(file);
字符流:
字符输出流Writer:
-
public abstract class Writer extends Object implements Appendable, Closeable, Flushable
用于写入字符流的抽象类。 子类必须实现的唯一方法是write(char [],int,int),flush()和close()。 然而,大多数子类将覆盖这里定义的一些方法,以便提供更高的效率,附加的功能或两者。
字符输出流初始化:
File file = new File("文件路径");
Writer out = null;
out = new FileWriter(file);
// out = new FileWriter(file, true); // 追加内容
字符输入流Reader:
-
public abstract class Reader extends Object implements Readable, Closeable
用于读取字符流的抽象类。 子类必须实现的唯一方法是read(char [],int,int)和close()。 然而,大多数子类将覆盖这里定义的一些方法,以便提供更高的效率,附加的功能或两者。
字符输入流初始化
File file = new File("文件路径");
Reader input = null;
input = new FileReader(file);
字节转换流:OutputStreamWriter将字节转变为字符流
-
OutputStreamWriter是字符的桥梁流以字节流:向其写入的字符编码成使用指定的字节public class OutputStreamWriter extends Writer
charset
。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。每次调用write()方法都会使编码转换器在给定字符上被调用。 所得到的字节在写入底层输出流之前累积在缓冲区中。 可以指定此缓冲区的大小,但是默认情况下它大部分用于大多数目的。 请注意,传递给write()方法的字符不会缓冲。
为了最大的效率,请考虑在BufferedWriter中包装一个OutputStreamWriter,以避免频繁的转换器调用。 例如:
Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
初始化:
File file = new File("文件路径");
Writer out = null;
out = new OutputStreamWriter(new FileOutputStream(file));
InputStreamWriter
-
InputStreamReader是从字节流到字符流的桥:它读取字节,并使用指定的public class InputStreamReader extends Reader
charset
将其解码为字符 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。每个调用InputStreamReader的read()方法之一可能会导致从底层字节输入流读取一个或多个字节。 为了使字节有效地转换为字符,可以从底层流读取比满足当前读取操作所需的更多字节。
为了最大的效率,请考虑在BufferedReader中包装一个InputStreamReader。 例如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
初始化:
File file = new File("文件路径");
Reader input = null;
input = new InputStreamReader(new FileInputStream(file));
不管是字节流还是字符流,实际上最终都是以字节的形式操作输入/输出流的
内存操作流:ByteArrayInputStream、ByteArrayOutputStream
ByteArrayInputStream
-
Apublic class ByteArrayInputStream extends InputStream
ByteArrayInputStream
包含一个内部缓冲区,其中包含可以从流中读取的字节。 内部计数器跟踪read
方法要提供的下一个字节。关闭ByteArrayInputStream没有任何效果。 在关闭流之后,可以调用此类中的方法,而不生成IOException 。
ByteArrayOutputStream
-
该类实现了将数据写入字节数组的输出流。 当数据写入缓冲区时,缓冲区会自动增长。 数据可以使用public class ByteArrayOutputStream extends OutputStream
toByteArray()
和toString()
。关闭ByteArrayOutputStream没有任何效果。 该流中的方法可以在流关闭后调用,而不生成IOException 。
管道流:实现两个线程之间的通信
PipedInputStream
-
public class PipedInputStream extends InputStream
管道输入流应连接到管道输出流; 管道输入流然后提供写入管道输出流的任何数据字节。
构造方法:
基本方法:
PipedOutputStream
-
public class PipedOutputStream extends OutputStream
管道输出流可以连接到管道输入流以创建通信管道。 管道输出流是管道的发送端。
构造方法:
基本方法:
import java.io.PipedOutputStream;
class Send implements Runnable {
private PipedOutputStream pos = null;
public Send() {
this.pos = new PipedOutputStream();
}
public void run() {
String str = "We would love to fritter away our days";
try {
this.pos.write(str.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
try {
this.pos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public PipedOutputStream getPos() {
return this.pos;
}
}
import java.io.PipedInputStream;
public class Receive implements Runnable {
private PipedInputStream pis = null;
public Receive() {
this.pis = new PipedInputStream();
}
public void run() {
byte b[] = new byte[1024];
int len = 0;
try {
len = this.pis.read(b);
} catch (Exception e) {
e.printStackTrace();
}
try {
this.pis.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("接收内容:" + new String(b, 0, len));
}
public PipedInputStream getPis() {
return this.pis;
}
}
public class Test {
public static void main(String[] args) {
Send send = new Send();
Receive receive = new Receive();
try {
send.getPos().connect(receive.getPis()); // 连接管道
} catch (Exception e) {
e.printStackTrace();
}
new Thread(send).start();
new Thread(receive).start();
}
}
压缩流
import java.io.*;
import java.util.zip.*;
class ZipCompress {
public static void main(String[] args) {
ZipCompress zipCom = new ZipCompress("C:\\Users\\fuchen\\Desktop\\新建文件夹.zip", "E:\\成长ing\\文档\\文档");
try {
zipCom.zip();
} catch (Exception e) {
e.printStackTrace();
}
}
private String zipFileName; // 目的地Zip文件
private String sourceFileName; // 源文件(带压缩的文件或文件夹)
public ZipCompress(String zipFileName, String sourceFileName) {
this.zipFileName = zipFileName;
this.sourceFileName = sourceFileName;
}
public void zip() throws Exception {
// File zipFile = new File(zipFileName);
System.out.println("开始压缩:");
// 创建zip输出流
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
// 创建缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(out);
File sourceFile = new File(sourceFileName);
// 调用函数
compress(out, bos, sourceFile, sourceFile.getName());
bos.close();
out.close();
System.out.println("压缩完成");
}
public void compress(ZipOutputStream out, BufferedOutputStream bos, File sourceFile, String base) throws Exception {
// 如果路径为目录(文件夹)
if (sourceFile.isDirectory()) {
// 取出文件夹中的文件(或子文件夹)
File[] flist = sourceFile.listFiles();
if (flist.length == 0)// 如果文件夹为空,则只需在目的地zip文件中写入一个目录进入点
{
System.out.println(base + File.separator);
out.putNextEntry(new ZipEntry(base + File.separator));
} else { // 如果文件夹不为空,则递归调用compress,文件夹中的每一个文件(或文件夹)进行压缩
for (int i = 0; i < flist.length; i++) {
compress(out, bos, flist[i], base + File.separator + flist[i].getName());
}
}
} else { // 如果不是目录(文件夹),即为文件,则先写入目录进入点,之后将文件写入zip文件中
out.putNextEntry(new ZipEntry(base));
FileInputStream fos = new FileInputStream(sourceFile);
BufferedInputStream bis = new BufferedInputStream(fos);
int tag;
// System.out.println(base + " source " + sourceFile);
System.out.println(base);
// 将源文件写入到zip文件中
while ((tag = bis.read()) != -1) {
bos.write(tag);
}
bis.close();
fos.close();
}
}
}
对象序列化:
Serializable接口定义(当前该接口中暂无任何的方法,只对需要序列化的类实现该接口,避免以后该接口扩展导致需要大量的修改),序列化还需要依靠对象输入输出流来完成
public interface Serializable{}
对象输出流:ObjectPutputStream定义格式
public class ObjectOutputStream extends OutputStream
implement ObjectOutput, ObjetStreamConstants
两个常用的方法:
public ObjectOutputStream(OutputStream out) throws IOException // 构造方法,传入输出的对象
public final void writeObject(Object obj) throws IOException //普通方法,输出对象
对象输入流:ObjectInputStream定义格式
public class ObjectInputStream extends InputStream
implements ObjectInput, ObjectStreamConstants
两个常用方法:
public ObjectInputStream(InputStream in) throws IOException //构造方法,构造输入对象
public final Object readObject() throws IOException, ClassNotFoundException //普通方法,从指定位置读取对象
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
public class IoStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
File file = new File("E:" + File.separator + "test.txt");
ObjectOutputStream oos = null;
OutputStream out = new FileOutputStream(file);
oos = new ObjectOutputStream(out);
oos.writeObject(new Person("浮沉"));
oos.close();
ObjectInputStream ois = null;
InputStream input = new FileInputStream(file);
ois = new ObjectInputStream(input);
Object obj = ois.readObject();
ois.close();
System.out.println(obj);
}
static class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public Person() {
}
public Person(String name) {
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "姓名:" + this.name;
}
}
}
Externalizable接口定义:
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
被Serializable接口声明的类的对象都就将被序列化,(Externalizable接口可以实现指定序列化内容)
writeExternal(ObjectOutput out):此方法中指定要保存的属性的信息,对象序列化时调用
readExternal(ObjectInput in):在此方法中读取被保存的信息,对象反序列化时调用
(这里留作补上调用的代码)
关键字:transient,设置某个属性不被序列化
序列化一组对象
在Java对象输出时只提供了一个对象的输出操作(writeObject (Object obj)),并没有提供多个对象的输出,同时序列化多个对象,需使用对象数组进行操作(因为数组属于引用类型,可以直接使用Object类型接收)
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class z {
public static void ser(Object obj[]) throws IOException {
File file = new File("E:" + File.separator + "test.txt");
ObjectOutputStream oos = null; // 声明对象输出流
OutputStream out = new FileOutputStream(file); // 文件输出流
oos = new ObjectOutputStream(out);
oos.writeObject(obj);
oos.close();
}
public static Object[] dser() throws ClassNotFoundException, IOException {
File file = new File("E:" + File.separator + "test.txt");
ObjectInputStream ois = null; // 声明对象输入流
InputStream input = new FileInputStream(file); // 文件输入流
ois = new ObjectInputStream(input); // 实例化对象输入流
Object obj[] = (Object[])ois.readObject(); // 读取对象
ois.close();
return obj;
}
}
新增的I/O
使用buffer(缓冲区)
Buffer是一个抽象类,可以在底层字节数组上进行get/set操作,除了boolean外,其他的基本类型都有相应的Buffer类
static XxxBuffer allocate(int capacity) // 创建一个容量为capacity的XxxBuffer对象
Buffer中有三个概念:
1、容量(capacity):缓冲区的容量表示该Buffer的最大数据容量,即最多可以存储多少数据
2、界限(limit):第一个不应该被读出或者写入的缓冲区位置索引。(位于limit后的数据不可以被读写)
3、位置(position):用于指明下一个被读写的缓冲区位置索引(类似于I/O流的指针)
Buffer中还可以有一个mark,mark的作用是允许程序直接将poition定位到mark处。
以上四者满足:0 <= mark <= position <= limit <= capacity
Buffer常用方法:
int capacity() // 返回Buffer的capacity大小
boolean hasRemaining() // 判断当前位置和界限之间是否还有元素可供处理
int limit() // 放回Buffer的界限位置
Buffer limit(int newLimit) // 重新设置界限的值,并放回一个行的limit的缓冲区对象
Buffer mark() // 设置Buffer的mark位置,它只能在0和位置(position)之间做mark
int position() // 返回Buffer中的当前位置
Buffer position(int newPs) // 设置Buffer的新位置,并放回一个具有改变position后的Buffer对象
int remaining() // 返回当前位置和界限之间的元素个数
Buffer reset() // 将位置转到mark所在的位置
Buffer rewind() // 将位置设置为0,取消设置的mark
Channel:
Java的Channel类类似于传统的流对象,但与传统的流相比,主要有两点区别:
(1)Channel可以直接将指定文件的部分或全部直接映射成Buffer
(2)程序不能直接访问Channel中的数据,Channel只能与Buffer进行交互
Channel中常用的三类方法是map、read、write,其中map()方法用于将Channel对应的部分或全部数据映射到ByteBuffer,而read()和write()方法都有一系列重载形式,map方法签名
// 第一个参数执行映射时的模式,分别只只读和读写等模式,第二、第三个参数用于控制那些数据映射成ByteBuffer
MappedByteBuffer map(FileChannel.MapMode mode, long position, long size)