java IO

来源:互联网 发布:冒险岛2mac 编辑:程序博客网 时间:2024/06/14 21:57

流(stream)

本章内容

Java流式输入/输出原理

Java流类的分类

流入/流出流类

常见的节点流和处理流

文件流

缓冲流

数据流

转换流

Print流

Object流

 

 

 

流的原理:读写数据

真正的文件在硬盘里数据,读数据都是0和1,文件想像成一个桶,文件里取数据,管道就是流,和水流的原理一样。

流就是2根管道,一个向里一个向外,无论向里还是向外都是对我们写的程序来说的

clip_image002

 

包在外面是处理流,一根不够包2根处理流管道,直接套在节点流或者处理流上面

在java程序中,对于数据的输入/输出操作以“流”方式进行,J2SDK提供了各种各样的“流”类,用以获取不通种类的数据,程序中通过标准的方法输入和输出数据

通常我们指的流就是:io包里的类,java.io包中定义了多个流类型(类或抽象类)来事先输入/输出功能:可以从不桶的调度对其进行分类:

按数据流的方向不同可以分为输入流 和 输出流

按处理数据单位不同可以分为字节流 和 字符流

按照功能不同可以分为节点流 和 处理流

(注释):

输入流:程序的角度读数据

输出流:往外写

字节流:0和1

字符流:一个字符一个字符(2个字节)

节点流:管道直接接到数据源上

处理流:套在其他管道上的流,处理流是“连接”在已存在的流(节点流或处理流)之上,

              通过对数据的处理为程序提供更为强大的读写功能。


J2SDK所提供的所有刘类型位于包java.io内都分别继承自以下四种抽象流类型

 

字节流

字符流

输入流

InuputStream

Reader往里读

输出流

OutputStream

Writer字符形式往外写

4根管道:一端接着程序一端接着数据源


InputStream:

继承自InputStream的流都是用于向程序中输入数据,且单位为字节(8bit)

 

clip_image004

深色:节点流 浅色:处理流

InputStream的基本方法:

abstract  int

read() throws IOException

read一下读一个字节

读取一个字节并以正数的形式返回(0-255) 如果返回-1已到输入流的末尾

int

read(byte[] b) throws IOException
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

返回实际读取的字节数,如果读取前已到输入流的末尾返回-1

(Eg.p2p毁硬盘是硬盘访问的频繁的原因,可以在内存中分配个空间,读一次装满,写:在内存里写好了,一次性写到硬盘里去)

int

read(byte[] b, int off, int len) throws IOException
将输入流中最多 len 个数据字节读入 byte 数组。从len的位置开始返回实际读取的字节数,如果读取前以到输入流的末尾返回-1

long

skip(long n) throws IOException
跳过和丢弃此输入流中数据的 n 个字节。

void

close()throws IOException
关闭此输入流并释放与该流关联的所有系统资源。

 

OutputStream:

继承自OutputStream的流是用于程序中输出数据,且数据的单位为字节(8bit),此抽象类是表示输出字节流的所有类的超类。

下图中深色为节点流,浅色为处理流

clip_image006

OutputStream的基本方法:

abstract  void

write(int b) throws IOException  

将指定的字节写入此输出流。该字节数据为参数b的低8位

void

close() throws IOException

关闭此输出流并释放与此流有关的所有系统资源。

void

flush()throws IOException 刷新此输出流并强制写出所有缓冲的输出字节。

void

write(byte[] b) throws IOException

将 b.length 个字节从指定的 byte 数组写入此输出流。

void

write(byte[] b, int off, int len) throws IOException 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

close()之前调用flush()把缓冲区中的剩余数据写入硬盘

 

Reader

继承自Reader的流都是用于向程序中输入数据,且数据的单位为字符(16bit)

(2个字节2个字节地往外读)

下图中深色为节点流,浅色为处理流

clip_image008

 

Writer

继承自Writer的流都是用于程序中输出数据,且数据的单位为字符(16bit);下图中深色为节点流,浅色为处理流

clip_image010

 

abstract         void

close() 关闭此流,但要先刷新它。

abstract void

flush() 刷新该流的缓冲。

void

write(char[] cbuf) 写入字符数组。

abstract void

write(char[] cbuf, int off, int len)  写入字符数组的某一部分。

void

write(int c)写入单个字符。

void

write(String str)写入字符串。

void

write(String str, int off, int len)
写入字符串的某一部分。

 

 

节点流类型:

类型

字符流

字节流

File(文件)

FileReader

FileWriter

FileInputStream

FileOutputStream

Memory Array

CharArrayReader

CharArrayWriter

ByteArrayInputStream

ByteArrayOutputStream

Memory String

StringReader

StringWriter

 

Pipe(管道)

PipedReader

PipedWriter

PipedInputStream

PipedOutputStream

 

(Stream结尾的都是字节,Writer和Read结尾的都是字符)

FileInputStream(File file)通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。

FileInputStream(String name)通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。

FileOutputStream(File file)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

FileOutputStream(File file, boolean append)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的输出文件流。

FileInputStream和FileOutputStream类支持父类InputStream和OutputStream提供的数据读写方法

 

 

处理流类型

处理类型

字符流

字节流

Buffering

BufferedReader

BufferedWriter

BufferedInputStream

BufferedOutputStream

Filtering

FilterReader

FilterWriter

FilterInputStream

FilterOutputStream

Converting between bytes and character

InputStreamReader

OutputStreamWriter

 

Object Serialization

 

ObjectInputStream

ObjectOutputStream

Data conversion

 

DataInputStream

DataOutputStream

Counting

LineNumberReader

LineNumberInputStream

Peeking ahead

PushackReader

PushhackInputStream

Printing

PrintWriter

PrintStream

 

(1)缓冲流:

缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,增加了一些新的方法

J2SDK提供了4种缓冲流:

BufferedReader

BufferedWriter

BufferedInputStream

BufferedOutputStream

构造方法:

BufferedReader(Reader in)
创建一个使用默认大小输入缓冲区的缓冲字符输入流。

BufferedReader(Reader in, int sz) //sz为自定义缓冲区大小
创建一个使用指定大小输入缓冲区的缓冲字符输入流。

BufferedWriter(Writer out)
创建一个使用默认大小输出缓冲区的缓冲字符输出流。

BufferedWriter(Writer out, int sz)
创建一个使用指定大小输出缓冲区的新缓冲字符输出流。

BufferedInputStream(InputStream in)
创建 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

BufferedInputStream(InputStream in, int size)
创建具有指定缓冲区大小的 BufferedInputStream,并保存其参数,即输入流 in,以便将来使用。

BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的基础输出流。

BufferedOutputStream(OutputStream out, int size)
创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的基础输出流。

 

缓冲输入量支持其父类(java.io.FilterInputStream)的mark和reset方法

BufferedReader提供了readLine方法用于读取一行字符串(以\r或\n分割)

BufferedWriter提供了newLine用于写入一个行分隔符

对于输出缓冲流,写出的数据会先在内存中缓存,使用flush方法会使内存中的数据立即写出。

 

举例(1)

// BufferedInputStream

import java.io.*;

public class TestBufferStream1 {

public static void main(String[] args) {

try {

FileInputStream fis = new FileInputStream("D:/java/TestR.java");

BufferedInputStream bis = new BufferedInputStream(fis);//套接在节点流上

int c = 0;

System.out.println(bis.read());//112

System.out.println(bis.read());//117

bis.mark(100);//标记标到100,从第100个字符开始往外读

for(int i=0;i<=10 && (c=bis.read())!=-1;i++){

System.out.print((char)c+" ");

}

System.out.println();

bis.reset();//又回到刚才标记的第100个字符的点

for(int i=0;i<=10 && (c=bis.read())!=-1;i++){

System.out.print((char)c+" ");

//char强制转化成字符,注意这有个里ASCII码 回车:13换行:10,可以去掉char看到

}

bis.close();

} catch (IOException e) {e.printStackTrace();}

}

}

 

举例(2)

//BufferedWriter BufferedReader

import java.io.*;

public class TestBufferStream2 {

public static void main(String[] args) {

try {

BufferedWriter bw = new BufferedWriter(new FileWriter("d:/java/bw.txt"));

//管道是writer类型,在这个文件夹内写进100行数据,每一行是一个随机数

BufferedReader br = new BufferedReader(new FileReader("d:/java/br.txt"));//管道是reader类型txt:事先写了一些中文字符

String s = null;

for(int i=1;i<=100;i++){

s = String.valueOf(Math.random());

bw.write(s);

bw.newLine(); //以"行"输入

}

bw.flush(); //close()之前调用flush()把缓冲区中的剩余数据写入硬盘

while((s=br.readLine())!=null){ //readLine方法值得使得在其他管道上套上Buffered**

System.out.println(s);

}

bw.close();

br.close();

} catch (IOException e) {e.printStackTrace();}

}

}

 

(2)转换流

InputStreamReader和OutputSteamWriter用于字节数据到字符数据之间的转换

InputStreamReader需要和InputStream”套接”

OutputStreamWriter需要和OutputStream”套接”

转换流在构造时可以指定其编码集合

InputStream isr = new InputStreamReader(System.in,”ISO8859_1”)

InputStream转换成Reader

编码:

ISO8859_1是个比较特殊的字符集,它是一个8位的编码,这就让他成为一个非常好的中介机构,会忠实的将每个字节的数据记录下来而不改变,估计这是web传输和jdbc传输使用它为字符集的原因吧

它包含所有西欧语言,还有个名字叫latin-1(latin-1~latin-9基本把西方所有国家文字统一)

东方人: GBK、gb2312(国标码)

全球统一:Unicode

(jsp的时候再说这个问题)

 

实例(1)

import java.io.*;

public class TestTransForm1 {

public static void main(String[] args) {

try {

OutputStreamWriter osw = new OutputStreamWriter(

new FileOutputStream("d:\\bak\\char.txt"));

osw.write("mircosoftibmsunapplehp");//而FileOutputStream是没有这个接口直接写字符串的

System.out.println(osw.getEncoding());//当前程序默认的编码是GBK

osw.close();

osw = new OutputStreamWriter(

new FileOutputStream("d:\\bak\\char.txt", true),"ISO8859_1");

//原来的文件内容基础上添加,去掉true就覆盖了//按照指定的字符编码写

osw.write("mircosoftibmsunapplehp");

System.out.println(osw.getEncoding());

osw.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

实例(2)

import java.io.*;

public class TestTransForm2 {

public static void main(String args[]) {

InputStreamReader isr =

new InputStreamReader(System.in);

//System.out是dos界面,System.in键盘输入

//注意:System.in本身就是个inputStream,就是根管道

BufferedReader br = new BufferedReader(isr);//为了读"一行"的数据,又包了一层

String s = null;

try {

s = br.readLine();

while(s!=null){

if(s.equalsIgnoreCase("exit")) break;

System.out.println(s.toUpperCase());

s = br.readLine();

}

br.close();

} catch (IOException e) {

e.printStackTrace();

}

}

} //标准输入的等待阻塞,同步(线程会讲)


(3)数据流

Eg.把一个long类型的数写到文件里,long类型的数很长,不断地转换成字符串,再转换成字节数组,内存占用大

但一个long类型的数组占8个字节,转换出来要80个字节

我们可以直接把8个字节写到一个文件里去

DataInputStream和DataOutputStream分别继承自InputStream和OutputStream,它属于处理流,需要分别”套接”在InputStream和OutputStream类型的节点流上

DataInputStream和DataOutputStream提供了可以存取与机器无关的java原始类型数据(如:int,double等)的方法

DataInputStream和DataOutStream的构造方法:

DataInputStream(InputStream in)
使用指定的底层 InputStream 创建一个 DataInputStream。

DataOutputStream(OutputStream out)
创建一个新的数据输出流,将数据写入指定基础输出流。

方法查看api文档

实例

import java.io.*;

public class TestDataStream {

public static void main(String[] args) {

ByteArrayOutputStream baos = new ByteArrayOutputStream();

//(1)分配了一个字节数组(2)管道堆在了内存里的这块字节数组上

DataOutputStream dos = new DataOutputStream(baos);//套接

try {

dos.writeDouble(Math.random());//一下把8个字节(double型)写进去

dos.writeBoolean(true);//布尔(1个字节)

ByteArrayInputStream bais =

new ByteArrayInputStream(baos.toByteArray());

//toByteArray(转换成字节数组byte[]

System.out.println(bais.available());//有多少个字节

DataInputStream dis = new DataInputStream(bais);//dis套到bais上(字节数组)上去了

System.out.println(dis.readDouble());//注意!先进先出(队列)

System.out.println(dis.readBoolean());

dos.close();

dis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

Print流:

PrintWriter和PrintStream都属于输出流,分别针对与字符和字节(属于成对)

PrintWriter和PrintStream提供了重载的print

Println方法用于多种数据类型的输出

PrintWriter和PrintStream的输出操作不会抛出异常,用户通过检测错误状态获取错误信息

PrintWriter和PrintStream有自动flush功能

问: 怎么没有调用close方法

(在jsp的时候,try catch太多了很累,那么用Print比较省力)

PrintWriter(Writer out) 
创建不带自动行刷新的新 PrintWriter。

PrintWriter(Writer out, boolean autoFlush) 
创建新 PrintWriter。

PrintWriter(OutputStream out)
根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。

PrintWriter(OutputStream out, boolean autoFlush)
通过现有的 OutputStream 创建新的 PrintWriter。

PrintStream(OutputStream out)
创建新的打印流。

PrintStream(OutputStream out, boolean autoFlush)
创建新的打印流。

 

实例(1)

import java.io.*;

public class TestPrintStream1 {

public static void main(String[] args) {

PrintStream ps = null;

try {

FileOutputStream fos =

new FileOutputStream("d:\\bak\\log.dat");

ps = new PrintStream(fos);

} catch (IOException e) {

e.printStackTrace();

}

if(ps != null){

System.setOut(ps);// 重新设置输出到ps管道

}

int ln = 0;

for(char c = 0; c <= 60000; c++){

System.out.print(c+ " ");

if(ln++ >=100){

System.out.println();

ln = 0;

}

}

}

}

 

实例(2)

import java.io.*;

public class TestPrintStream2 {

public static void main(String[] args) {

String filename = args[0];//命令行参数

if(filename!=null){

list(filename,System.out);//把filename当成参数传到list方法内

}

}

public static void list(String f,PrintStream fs){//fs->System.out

//把本来传到dos界面的文字传到fs

try {

BufferedReader br =

new BufferedReader(new FileReader(f));

String s = null;

while((s=br.readLine())!=null){

fs.println(s);

}

br.close();

} catch (IOException e) {

fs.println("无法读取文件");

}

}

}

//运行:java TestPrintStream2 Hello.java(绝对路径或者当前目录下有的文件)

 

实例(3)

import java.util.*;

import java.io.*;

public class TestPrintStream3 {

public static void main(String[] args) {

String s = null;

BufferedReader br = new BufferedReader(

new InputStreamReader(System.in));

try {

FileWriter fw = new FileWriter

("d:\\bak\\logfile.log", true); //java日志开发包Log4J

PrintWriter log = new PrintWriter(fw);

while ((s = br.readLine())!=null) {//阻塞,必须键盘输入

if(s.equalsIgnoreCase("exit")) break;

System.out.println(s.toUpperCase());

log.println("-----");//log文档里输入

log.println(s.toUpperCase()); //log文档里输入大写

log.flush();//保险写写无所谓

}

log.println("==="+new Date()+"==="); //当前的时间

log.flush();

log.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

Object流:

直接将Object写入或读出,

transient关键字

serlalizable接口

externalizable接口:标记是否可以序列化(但不可以控制), 不过它自己可以控制自己的序列化过程,serlalizable接口的子接口, 尽量不要控制,

把整个Object写到硬盘上

序列化和反序列化

import java.io.*;

public class TestObjectIO {

public static void main(String args[]) throws Exception {

T t = new T();

t.k = 8;

FileOutputStream fos = new FileOutputStream("d:/share/java/io/testobjectio.dat");

ObjectOutputStream oos = new ObjectOutputStream(fos);

oos.writeObject(t);

oos.flush();

oos.close();

FileInputStream fis = new FileInputStream("d:/share/java/io/testobjectio.dat");

ObjectInputStream ois = new ObjectInputStream(fis);

T tReaded = (T)ois.readObject();

System.out.println(tReaded.i + " " + tReaded.j + " " + tReaded.d + " " + tReaded.k);

}

}

class T

implements Serializable

//(可以被序列化的,序列化成字节流(写到网络上或硬盘上)),必须实现这接口

{

int i = 10;

int j = 9;

double d = 2.3;

transient int k = 15;

//transient透明:可以用来修饰成员变量,在序列化的时候不予考虑,不写入硬盘,默认值0

}

ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。

ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。

具体看api

 

 

 

总结

InputStream/OutputStream

Reader/Writer

FileInputStream/FileOutputStream

FileReader/FileWriter

BufferedInputStream/Output

BufferedReader/BufferedWriter

ByteArrayInputStream/Output

InputStreamReader/Output

DataInputReader/OutputStreamWriter

PrintStream/PrintWriter

ObjectInputStream/Out

原创粉丝点击