Java IO 输入和输出流
数据流是指一组有顺序的,有起点和终点的字节集合。
最初的版本中,java.io 包中的流只有普通的字节流,即以 byte 为基本处理单位的流。字节流用来读写 8 位的数据,由于不会对数据做任何转换,因此可以用来处理二进制的数据。在后来的版本中,java.io 包中又加入了专门用于字符流处理的类,这个以 reader 和 writer 为基础派生的一系列的类。
另外,为了使对象的状态能够方便地永久保存下来,java.io 包中又提供了以字节流为基础的用于对象的永久化保存状态的机制,通过实现 objectinput 和 objectoutput 接口来完成。
inputstream 和 outputstream 两个类都是抽象类,抽象类不能进行实例化。在实际应用中我们要用到一系列基本数据流类,都是他们的子类,在实现其父类方法的同时又都定义了其特有的功能。
-
输入数据流
-
-
输入数据流中提供的主要数据操作方法
- int read():从输入流中读取一个字节的二进制数据
- int read(byte[] b):将多个字节读到数组中,填满整个数组
- int read(byte[] b, int off, int len):从输入流中读取长度为len的数据,从数组 b 中下标为 off 的位置开始放置读入的数据,读毕返回读取的字节数
- 以上三个方法中,所读取的数据都默认为字节类型。当输入流读取结束时,会得到 -1,以标志数据流的结束。第一个 read() 方法将读取的一个字节作为低位,形成一个 0~255 的 int 类型的数值返回
- void close():关闭数据流
- long skip(long l):跳过数据流中指定数量的字节不读取,返回值表示实际跳过的字节数
- 对于数据流中的字节的读取通常是按从头到尾顺序进行的,如果需要以反方向读取,则需要使用回推(push back)操作,支持回推操作的数据流中常用的方法如下
- boolean marksupported():用于测试数据流是否支持回推操作,当一个数据流支持 mark() 和 reset() 方法时返回 true,否则返回 false
- void mark(int markarea):用于标记数据流的当前位置,并划出一个缓冲区,其大小至少为指定参数的大小
- void reset():将输入流重新定位到对此流最后调用 mark 方法时的位置
-
-
输出数据流
-
输出数据流中提供的主要数据操作方法
- void write(int i):将字节 i 写入到数据流中,它只输出所读入参数的最低 8 位
- void write(byte b[]):将数组 b[] 中的全部 b.length 个字节写入数据流
- void write(byte b[], int off, int len):将数组 b[] 中从下标 off 开始的 len 个字节写入数据流。元素 b[off] 是此操作写入的第一个字节, b[off + len - 1] 是此操作写入的最后一个字节
- void close():当结束对输出数据流的操作时应该将其关闭
- void flush():刷新此输出流并强制写出所有缓冲的输出字节
-
基本字节数据流类
-
文件数据流
-
文件数据流包括 fileinputstream 和 fileoutputstream,这两个类用来进行文件的i/o处理,其数据源或数据终点都应当是文件。通过所提供的方法可以对本机上的文件进行操作,但是不支持方法 mark() 和 reset()
-
示例(1)
-
fileinputstream fis = new fileinputstream("myfile.txt"); // 同样可以使用 fileoutputstream 向文件中输出字节 fileoutputstream out = new fileoutputstream("myfile.txt");
-
-
-
-
示例(2)
-
fileoutputstream out = new fileoutputstream("myfile.txt"); out.wirte('h'); out.wirte(69); out.wirte(76); out.wirte('l'); out.wirte('o'); out.close();
fileinputstream fis = new fileinputstream("myfile.txt"); while(fis.available() > 0){ system.out.print(fis.read() + " "); } fis.close();
-
-
-
过滤器数据流(直接继承与filterinputstream、filteroutputstream)
-
缓冲区数据流
-
一个过滤器数据流在创建时与一个已经存在的数据流相连,这样在从这样的数据流中读取数据时,它提供的是对一个原始输入数据流的内容进行了特定处理的数据。缓冲区数据流有bufferedinputstream 和 bufferedoutinputstream,它们是在数据流上增加了一个缓冲区,都属于过滤器数据流。当读写数据时,数据以块为单位先进入缓冲区(块大小可以进行设置),其后的读写操作则作用于缓冲区。采用这个办法可以降低不同硬件设备之间速度的差异,提高i/o操作的效率
-
示例(使用默认缓冲区大小)
-
fileinputstream fis = new fileinputstream("myfile.txt"); inputstream is = new bufferedinputstream(fis); fileoutputstream fos = new fileoutputstream("myfile.txt"); outputstream is = new bufferedoutputstream(fos);
-
示例(自定义设置缓冲区大小)
-
fileinputstream fis = new fileinputstream("myfile.txt"); inputstream is = new bufferedinputstream(fis, 1024); fileoutputstream fos = new fileoutputstream("myfile.txt"); outputstream is = new bufferedoutputstream(fos, 1024);
-
一般在关闭一个缓冲区输出流之前,应先使用 flush() 方法,强制输出剩余数据,以确保缓冲区内的所有数据全部写入输出流
-
-
数据数据流
-
前面提到的数据流中处理数据都是指字节或字节数组,这是进行数据传输时系统默认的数据类型。但实际上所处理的数据并非只有这两种类型,遇到这种情况时就要应用一种专门的数据流来处理。datainputstream和dataoutputstream就是这样的两个过滤器数据流,它们允许通过数据流来读写 java 基本类型
-
示例
-
datainputstream dis = new datainputstream(is); dataoutputstream ous = new dataoutputstream(os);
-
常用方法
-
// datainputstream 常用方法 byte readbyte() long readlong() doublue readdouble() boolean readboolean() string readutf() int readint() float readfloat() short readshort() char readchar() // dataoutputstream 常用方法 void writebyte(int abyte) void writelong(long along) void writedouble(double abouble) void writeboolean(boolean abool) void writeutf(string astring) void writeint(int aint) void writefloat(float afloat) void writeshort(short ashort) void rwritechar(char achar)
-
虽然这两个数据流定义了对字符串进行读写的方法,但是由于字符编码的原因,应该避免使用这些方法。reader 和 writer 重载了这两个方法,对字符进行操作时应当使用 reader 和 writer 两个系列类中的方法
-
-
对象流
-
能够输入/输出对象的流称为对象流。java 通过 java.io 包中的 objectinputstream 和 objectoutputstream 两个类实现把对象写入文件数据流或从文件数据流中读出的功能
-
示例
-
// 写对象数据流 date date = new date(); fileoutputstream fos = new fileoutputstream("date.ser"); objectoutputstream oos = new objectoutputstream(fos); oos.writeobject(date); oos.close(); // 读对象数据流 date date = null; fileinputstream fis = new fileinputstream("date.ser"); objectinputstream ois = new objectinputstream(fis); date = (date) ois.readobject(date); ois.close(); system.out.println("date serialized at " + date);
-
-
序列化
-
序列化的概念
- 能够记录自己的状态以便将来得到复原的能力,称为对象的持久性(persistence)。一个对象时可持久的,意味着它可以把这个对象存入内存或者磁盘等介质中,也就是把对象存为某种永久存储类型。对象通过数值来描述自己的状态,记录对象也就是记录下这些数值。把对象转换为字节序列的过程称为对象的序列化,把字节序列恢复为对象的过程称为对象的反序列化。序列化的主要任务是写出对象实例变量的数值。序列化是一种用来处理对象流的机制,所谓的对象流也就是将对象的内容进行流化。序列化是为了解决在对对象流进行读写操作时所引发的问题
-
serializable 接口中没有定义任何方法,只是作为一个标记来指示实现该接口的类可以进行序列化,只有实现 serializable 接口的类才能被序列化。当一个类实现 serializable 接口时,表明该类加入了对象序列化协议
-
序列化一个对象,必须与特定的对象输出/输入流联系起来,通过对象输出流/输入流将对象状态保存下来或者将对象状态恢复。通过 java.io 包中的 objectinputstream 和 objectoutputstream 两个类可以实现。writeobject() 和 readobject() 方法可以直接将对象保存到输出流中或者从输出流中读取一个对象
-
// 序列化 public class student implements serializable { int id; string name; int age; string department; public student(int id, string name, int age, string department) { this.id = id; this.name = name; this.age = age; this.department = department; } } // 对象的存储 student stu = new student(927103, "li ming", 16, "csd"); fileoutputstream fo = new fileoutputstream("data.ser"); objectoutputstream so = new objectoutputstream(fo); so.writeobject(stu); so.close(); // 对象的恢复 student stu; fileinputstream fi = new fileinputstream("data.ser"); objectinputstream si = new objectinputstream(fi); stu = (student)si.readobject(); si.close(); system.out.println("id:" + stu.id + ";name:" + stu.name);
-
对象结构表
- 序列化只能保存对象的非静态成员变量,而不能保存任何成员方法和静态成员变量,并且保存的只是变量的值,对于变量的任何修饰符都不能保存,访问权限(public, protected, private)对于数据域的序列化没有影响
- 有一些对象不具有可持久性,因为其数据的特性决定了它会经常变化,其状态只是瞬时的,这样的对象是无法保存起状态的,如 thread 对象。对于这样的成员变量,必须用 transient 关键字标明,否则编译器将报错。任何用 transient 关键字标明的成员变量都不会被保存
- 序列化可能涉及将对象存放到磁盘上或者再网络上发送数据,这时会产生安全问题。对于一些保密的数据,为了保证安全,不应保存在永久介质中,应在这些变量前加上 transient 关键字
- 当数据变量是一个对象时,该对象的数据成员也可以被持久化。对象的数据结构或结构树,包括其子对象树在内,构成了这个对象的结构表
- 序列化只能保存对象的非静态成员变量,而不能保存任何成员方法和静态成员变量,并且保存的只是变量的值,对于变量的任何修饰符都不能保存,访问权限(public, protected, private)对于数据域的序列化没有影响
-
示例
-
public class student implements serializable { public transient thread mythread; private transient string customerid; private int total; }
-
-
基本字符流
从 jdk1.1 开始,java.io 包中加入了专门用于字符流处理的类,它们是以 reader 和 writer 为基础派生的一系列类。
一、读者(reader)和写者(writer)
同其他语言使用 ascii 字符集不同,java 使用 unicode 字符集来表示和字符。ascii 字符集以一个字节(8bit)表示一个字符,可以认为一个字符就是一个字节(byte)。但是 java 使用的 unicode 是一种大字符集,用两个字节(16bit)来表示一个字符,这时字节与字符就不再相同。为实现与其他程序语言及不同平台的交互,java 提供一种新的数据流处理方案称作 reader 和 writer。在 java.io 包中有许多不同类对其进行支持,其中最重要的是 inputstreamreader 和 outputstreamwriter 类。这两个类是字节流和 reader 和 writer 的接口,用来在字节流和字符流之间作为中介。
在英语国家中,字节编码采用 iso8859_1 协议。iso8859_1 是 latin-1 编码系统映射到 ascii 标准,能够在不同平台之间正确转换字符。
// 构造映射到 ascii 码的标准的 inputstreamreader 的方法 inputstreamreader ir = new inputstreamreader(system.in, "8859_1"); // reader 提供的方法 void close(); void mark(int readaheadlimit); boolean marksupported(); int read(); int read(char[] cbuf); int read(char[] cbuf, int off, int len); boolean ready(); void reset(); long skip(long n); // writer 提供的方法 void close(); void flush(); void write(char[] cbuf); void write(char[] cbuf, int off, int len); void write(int c); void write(string str); void write(string str, int off, int len);
二、缓冲区读者和缓冲区写者
java.io 中提供流缓冲流 bufferedreader 和 bufferedwriter。其构造方法与 bufferedinputstream 和 bufferedoutputstream 类似。另外,除了 read() 和 write() 方法外,还提供了整行字符的处理方法
-
-
方法如下
- public string readline():bufferedreader 的方法,从输入流中读取一行字符,行结束标志为 '\n' 、'\r' 或者两者一起
- public void newline():bufferedwriter 的方法,向输出流中写入一个行结束标志
-
示例
-
fileinputstream fis = new fileinputstream("data.ser"); inputstreamreader dis = new inputstreamreader(fis); bufferedreader reader = new bufferedreader(dis); // bufferedreader reader = new bufferedreader(new filereader("data.ser")); string s; while((s = reader.readline()) != null) { system.out.println("read:" + s); }
dis.close();
-
-
当你写文件的时候,为了提高效率,写入的数据会先放入缓冲区,然后写入文件。因此有时候你需要主动调用 flush()方法
-
// filewriter filewriter fw = new filewriter("d:/test.txt"); string s = "hello world"; fw.write(s, 0, s.length()); fw.flush(); //flush将缓冲区内容写入到问题件 // outputstreamwriter outputstreamwriter osw = new outputstreamwriter(new fileoutputstream("d:/test1.txt")); osw.write(s, 0, s.length()); osw.flush(); // printwriter printwriter pw = new printwriter(new outputstreamwriter(new fileoutputstream("d:/test2.txt")), true); // printwriter pw = new printwriter(new filewriter("d:/test2.txt")); pw.println(s); // close allwriter fw.close(); osw.close(); pw.close();
-
- 文件拷贝
-
file file = new file("d:/test.txt"); file dest = new file("d:/new.txt"); try { bufferedreader reader = new bufferedreader(new filereader(file)); bufferedwriter writer = new bufferedwriter(new filewriter(dest)); string line = reader.readline(); while(line!=null){ writer.write(line); line = reader.readline(); } writer.flush(); reader.close(); writer.close(); } catch (filenotfoundexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); }
-
-