java io 简介
惯例先祭出一张图
[1]输入字节流InputStream:InputStream 是所有的输入字节流的父类,它是一个抽象类;ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据;PipedInputStream 是从与其它线程共用的管道中读取数据;ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。
[2]输出字节流OutputStream:OutputStream 是所有的输出字节流的父类,它是一个抽象类。
ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。
[3]字符输入流Reader:Reader 是所有的输入字符流的父类,它是一个抽象类;CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据;PipedReader 是从与其它线程共用的管道中读取数据;BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象;FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号;InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。
[4]字符输出流Writer:Writer 是所有的输出字符流的父类,它是一个抽象类;CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据,BufferedWriter 是一个装饰器为Writer 提供缓冲功能;PrintWriter 和PrintStream 极其类似,功能和使用也非常相似;
简述: IO流简单来说就是Input和Output流,IO流主要是用来处理设备之间的数据传输,Java对于数据的操作都是通过流实现,而java用于操作流的对象都在IO包中。使用流对象要抛出IO异常,IO异常为checked异常
分类:
按操作数据分为:字节流和字符流。 如:Reader和InpurStream,只要是以stream结尾的都是字节流
按流向分:输入流和输出流。如:InputStream和OutputStream,输入则为input或reader,输出则为output或writer,应用中主要将外来的数据流(文件来的,或者网络传输流等)首先通过输入流输入到内存,处理之后通过输出流输出
按功能分:节点流和过滤流
节点流: 用于直接操作目标设备的流
过滤流: 是对一个已存在的流的链接和封装,通过对数据进行处理为程序提供功能强大、灵活的读写功能。
可以把我们的程序想象成一个容器(内存),把要处理的数据流通过输入流(input,reader)输入,处理后,通过输出流(output ,writer)输出
字符流
- 字符流简介
*字符流中的对象融合了编码表,也就是系统默认的编码表。我们的系统一般都是GBK编码
- 字符流只用来处理文本数据
- 字符流在处理输出流时必须flush(刷新)才能将数据输出
实例一:在硬盘创建一个文件,写入一些文本信息
package com.oldbig.io;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
//创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定目录下。如果该目录有同名文件,那么该文件将被覆盖。
//若在后面加入参数true,则不覆盖文件,在文件后面添加文本,例如:FileWriter("D:\\ioTest\\1.txt",true);
FileWriter fw = new FileWriter("D:\\ioTest\\1.txt");
//调用write的方法将字符串写到流中
fw.write("hello word");
//刷新流对象缓冲中的数据,将数据刷到目的地中
fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部缓冲中的数据。当我们结束输入时候,必须close();
fw.write("test");
fw.close();
//flush和close的区别:flush刷新后可以继续输入,close刷新后不能继续输入。
}
}
实例二:使用FileReader对文件进行读取
private static void singleRead() throws IOException {
FileReader fr = null;
try{
//创建一个文件读取流对象,和指定名称的文件关联。
//要保证文件已经存在,否则会发生异常:FileNotFoundException
fr = new FileReader("D:\\ioTest\\1.txt");
//将文件流包装成缓冲流,读取更方便,若直接用FileReader的read方法读取的是int数据不是文本数据
BufferedReader br = new BufferedReader(fr);
String ch = null;
while((ch=br.readLine()) != null){
System.out.println(ch);
}
}catch(IOException e){
e.printStackTrace();
}finally{
fr.close();
}
}
实例:复制文本–>另一文本
private static void singleRead() throws IOException {
FileReader fr = null;
try{
//创建一个文件读取流对象,和指定名称的文件关联。
//要保证文件已经存在,否则会发生异常:FileNotFoundException
fr = new FileReader("D:\\ioTest\\1.txt");
//将文件流包装成缓冲流,读取更方便
BufferedReader br = new BufferedReader(fr);
String ch = null;
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\ioTest\\2.txt"));
while((ch=br.readLine()) != null){
System.out.println(ch);
bw.write(ch);
bw.newLine(); //换行
bw.flush(); //清空缓冲区
}
}catch(IOException e){
e.printStackTrace();
}finally{
fr.close();
}
}
刚刚用到缓冲区:字符流的缓冲区:BufferedReader和BufferedWriter
缓冲区的出现时为了提高流的操作效率而出现的.
需要被提高效率的流作为参数传递给缓冲区的构造函数
在缓冲区中封装了一个数组,存入数据后一次取出
readline()只返回回车符前面的字符,不返回回车符。如果是复制的话,必须加入newLine(),写入回车符
字节流
简述:
1、字节流和字符流的基本操作是相同的,但是要想操作媒体流就需要用到字节流。(媒体文件也是以字节存储的)
2、读写字节流:InputStream 输入流(读)和OutputStream 输出流(写)
3、字节流操作可以不用刷新流操作。
4、InputStream特有方法:
int available();//返回文件中的字节个数
实例:复制一张图片
package com.oldbig.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyStream {
public static void main(String[] args) {
// TODO Auto-generated method stub
copyJpg();
System.out.println("复制完成");
}
private static void copyJpg() {
// TODO Auto-generated method stub
FileInputStream fis = null;
FileOutputStream fos = null;
try{
fis = new FileInputStream("D://ioTest//1.jpg");
fos = new FileOutputStream("D://ioTest//2.jpg");
byte[] info = new byte[1024];
int len = 0;
while((len = fis.read(info)) != -1 ){
fos.write(info, 0, len);
}
}catch(IOException e){
e.printStackTrace();
throw new RuntimeException("复制文件异常");
}finally{
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
流操作规律
System.out: 对应的标准输出设备:控制台 //它是PrintStream对象,(PrintStream:打印流。OutputStream的子类)
System.in: 对应的标准输入设备:键盘 //它是InputStream对象
示例:从键盘录入流,打印到控制台上
package com.oldbig.io;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class SystemInOutDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
BufferedReader br = null;
BufferedWriter bw = null;
try{
InputStream is = System.in;
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
//InputSteamReader:读取字节并将其解码为字符
br = new BufferedReader(isr);
//OutputStreamWriter:要写入流中的字符编码成字节
bw = new BufferedWriter(new OutputStreamWriter(System.out));
String info = null;
while((info = br.readLine()) != null){
bw.write(info);
bw.newLine();
bw.flush();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
java 管道通信
Java提供管道功能,实现管道通信的类有两组:PipedInputStream和PipedOutputStream或者是PipedReader和PipedWriter。管道通信主要用于不同线程间的通信。
一个PipedInputStream实例对象必须和一个PipedOutputStream实例对象进行连接而产生一个通信管道。PipedOutputStream向管道中写入数据,PipedIntputStream读取PipedOutputStream向管道中写入的数据。一个线程的PipedInputStream对象能够从另外一个线程的PipedOutputStream对象中读取数据。
实例:两个线程之间建立通信管道
package com.oldbig.io;
import java.io.IOException;
import java.io.PipedOutputStream;
public class PipedSend extends Thread{
private PipedOutputStream out = new PipedOutputStream();
public PipedOutputStream getOut() {
return out;
}
public void run(){
String info = "hello ,receiver";
try{
out.write(info.getBytes()); //写入数据
out.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
package com.oldbig.io;
import java.io.IOException;
import java.io.PipedInputStream;
public class PipedReader extends Thread{
private PipedInputStream in = new PipedInputStream();
public PipedInputStream getIn() {
return in;
}
@Override
public void run() {
// TODO Auto-generated method stub
byte[] info = new byte[1024];
try{
int len = in.read(info);
System.out.println("receive from send :" + new String(info,0,len));
in.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
public class PipedTest {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
PipedSend send = new PipedSend();
PipedReader reader = new PipedReader();
PipedOutputStream out = send.getOut();
PipedInputStream in = reader.getIn();
in.connect(out);//或者也可以用out.connect(in);
send.start();
reader.start();
}
}
总结
*字节流和字符流的区别:
字节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,而字符流只有在调用close()方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,则需要手动调用flush()方法。
· 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
· 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
结论:只要是处理纯文本数据,就优先考虑使用字符流。除此之外都使用字节流
*什么是java序列化,如何实现java序列化?
我们有时候将一个java对象变成字节流的形式传出去或者从一个字节流中恢复成一个java对象,例如,要将java对象存储到硬盘或者传送给网络上的其他计算机,这个过程我们可以自己写代码去把一个java对象变成某个格式的字节流再传输,但是,jre本身就提供了这种支持,我们可以调用OutputStream的writeObject方法来做,如果要让java 帮我们做,要被传输的对象必须实现serializable接口,这样,javac编译时就会进行特殊处理,编译的类才可以被writeObject方法操作,这就是所谓的序列化。需要被序列化的类必须实现Serializable接口,该接口是一个mini接口,其中没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的。
例如,在web开发中,如果对象被保存在了Session中,tomcat在重启时要把Session对象序列化到硬盘,这个对象就必须实现Serializable接口。如果对象要经过分布式系统进行网络传输或通过rmi等远程调用,这就需要在网络上传输对象,被传输的对象就必须实现Serializable接口。
参考:https://www.cnblogs.com/xll1025/p/6418766.html
http://blog.csdn.net/liufeng_king/article/details/12978101