操作对象的流
ObjectOutputStream
- 被操作的对象需要实现Serializable(标记接口),该类可以将Java对象的基本数据类型和图形写入OutputStream,可以使用ObjectInputStream读取对象,通过在流中使用文件可以实现对象的持久存储;
- 构造函数:ObjectOutputStream(OutputStream out);
- 常用方法:
write×××(××× obj);
×××:基本数据类型或Object; - 注意:
write(int val)与writeInt(int val)的区别:前者仅读一个int的最低8位,后者写入一个32位的int值;
ObjectInputStream
ObjectInputStream对以前使用ObjectOutputStream写入的基本数据和对象进行反序列化;
1. 构造函数:
ObjectInpuStream(InputStream in)
2. 常用方法:
××× read×××();×××基本数据类型或Object;
3. 注意:static修饰的成员变量不能被序列化;
4. transient关键字;对于非static修饰的成员如果不想被序列化可用该关键字修饰;
import java.io.*;
class ObjectStreamDemo {
public static void main(String[] args) throws Exception{
//writeObj();
readObj();
}
public static void readObj()throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
public static void writeObj()throws IOException{
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi0",399,"kr"));
oos.close();
}
}
import java.io.*;
class Person implements Serializable{
public static final long serialVersionUID = 42L;//自定义序列号ID
private String name;
transient int age;//非静态成员如果不想被序列化,可以用关键字transient修饰;
static String country = "cn";//静态成员不能被序列化。
Person(String name,int age,String country){
this.name = name;
this.age = age;
this.country = country;
}
public String toString(){
return name+":"+age+":"+country;
}
}
管道流
输入输出可以之间进行连接,通过结合线程使用;
PipedOutputStream
- 构造函数:
- PipedOutputStream();可以将PipedOutputStream连接到PipedInputStream来创建通信管道。PipedOutputStream作为发送端;
- PipedOutputStream(PipedInputStream snk);参数中需传入一个管道输入流;
- 若是空参数的构造函数则需要通过connect()方法来获取一个管道输入流,用法:
connect(PipedInputStream snk);
PipedInputStream
- 概述:管道输入流应连接到管道输出流,管道输入流提供要写入管道输出流的所有数据字节,通常数据由某个线程从PipedInpuStream对象读取,并由其他线程将其写入到相应的PipedOutputStream,若为单线程容易死锁线程;
- 构造函数:
- PipedInpuStream(PipedOutputStream src);构造函数无参可用connect(PipedOutputStream src)使此管道输入流连接到管道输出流
import java.io.*;
class Read implements Runnable{
private PipedInputStream in;
Read(PipedInputStream in){
this.in = in;
}
public void run(){
try{
byte[] buf = new byte[1024];
System.out.println("读取前。。没有数据阻塞");
int len = in.read(buf);
System.out.println("读到数据。。阻塞结束");
String s= new String(buf,0,len);
System.out.println(s);
in.close();
}catch (IOException e){
throw new RuntimeException("管道读取流失败");
}
}
}
class Write implements Runnable{
private PipedOutputStream out;
Write(PipedOutputStream out){
this.out = out;
}
public void run(){
try{
System.out.println("开始写入数据,等待6秒后。");
Thread.sleep(6000);
out.write("piped lai la".getBytes());
out.close();
}catch (Exception e){
throw new RuntimeException("管道输出流失败");
}
}
}
class PipedStreamDemo{
public static void main(String[] args) throws IOException{
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);
Read r = new Read(in);
Write w = new Write(out);
new Thread(r).start();
new Thread(w).start();
}
}
RandomAccessFile
- 随机访问文件,自身具备读写的方法;
通过skipBytes(int x);seek(int x);来达到随机访问;
此类的实例支持对随机访问文件的读取和写入; 特点:
- 该类不算是IO体系中的子类而是直接继承Object;但他是IO包中的成员,因为它具备读和写的功能,内部封装了一个数组,而且通过指针对数组的元素进行操作,可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置;
- 其实完成读写的原理就是内部封装了字节输入流和输出流,通过构造函数可以看出,该类只能操作文件,而且操作文件还有模式:只读(r);读写(rw)等;
- 如果模式为只读r,不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常;
- 如果模式为只读rw,操作的文件不存在,会自动创建,如果存在则不会覆盖;
构造方法:
- RandomAccessFile(File file,String mode);
- RandomAccessFile(String name,String mode);
file-指定文件;
name-系统文件名;
mode-访问模式;
该类常用方法:
- gerFilePointer();返回此文件的当前偏移量;
- length();返回此文件的长度;
- read();该功能与InputStream一样;
- read×××;×××-基本数据类型;
- readLine();读一行;
- seek(long pos);设置指针偏移量;
- setLength(long newLength);设置文件长度;
- write(byte[] b)/(byte[] b,int off,int len)/(int b)该方法与OutputStream方法一样;
- write×××(××× ~);×××基本数据类型;
- skipBytes(int n);跳过指定的字节数;
注:该类的常用方式:通过seek()偏移指针,结合多线程实现分段数据同时读写,实际应用:迅雷下载;
class RandomAccessFileDemo {
public static void main(String[] args) throws IOException{
//writeFile_2();
//readFile();
//System.out.println(Integer.toBinaryString(258));
}
public static void readFile()throws IOException{
RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
//调整对象中指针。
//raf.seek(8*1);
//跳过指定的字节数
raf.skipBytes(8);
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println("name="+name);
System.out.println("age="+age);
raf.close();
}
public static void writeFile_2()throws IOException{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.seek(8*0);
raf.write("周期".getBytes());
raf.writeInt(103);
raf.close();
}
public static void writeFile()throws IOException{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("李四".getBytes());
raf.writeInt(97);
raf.write("王五".getBytes());
raf.writeInt(99);
raf.close();
}
}
操作基本数据类型流
DataInputStream
- 构造函数:
- DataInputStream(InputStream in)使用指定的底层输入流,创建一个DataInputStream;
- 常用方法:
- read(byte[] b)/(byte[] b,int off,int len)
- read×××();×××基本数据类型;
- skipBytes(int n);
- readUTF();读取一个有UTF-8修改版格式编码的字符串;
- readUTF(DataInput in);从in中读取由writeUTF写入的数据;
DataOutputStream
- 构造方法:
- DataOutputStream(OutputStream out);创建一个新的数据输出流,将数据写入指定基础输出流;
- 常用方法:
- write(byte[] b,int off,int len);
- write(int b);
- write×××(×××~);×××-基本数据类型;
- writeChars(String s);将字符串按字符顺序写入基础输出流;
- flush();
- size();返回到目前为止写入此数据输出流的字节数;
- writeUTF(String str);以与机器无关方式使UTF-8修改版编码将一个字符串写入基础输出流。
注:writeUTF();写的数据,只能用readUTF()方法读;
注:写入的不同的类型的数据时,读取也要按该顺序读取,否则会出现乱码,因为不同的数据类型的长度不同;
import java.io.*;
class DataStreamDemo {
public static void main(String[] args) throws IOException{
//writeData();
//readData();
//writeUTFDemo();
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");
// osw.write("你好");
// osw.close();
// readUTFDemo();
}
public static void readUTFDemo()throws IOException{
DataInputStream dis = new DataInputStream(new FileInputStream("utf.txt"));
String s = dis.readUTF();
System.out.println(s);
dis.close();
}
public static void writeUTFDemo()throws IOException{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdate.txt"));
dos.writeUTF("你好");
dos.close();
}
public static void readData()throws IOException{
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println("num="+num);
System.out.println("b="+b);
System.out.println("d="+d);
dis.close();
}
public static void writeData()throws IOException{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(9887.543);
dos.close();
ObjectOutputStream oos = null;
oos.writeObject(new O());
}
}
操作字节数组
ByteArrayInputStream
- 构造函数:
- ByteArrayInputStream(byte[] buf);
- ByteArrayInputStream(byte[] buf,int offset,int length);创建ByteArrayInputStream,使用buf作为其缓冲区数组;
- 常用方法:
- available();返回可从输入流读取的剩余字节数;
- read();
- read(byte[] b,int off,int len);
ByteArrayOutputStream
- 构造函数:
- ByteArrayOutputStream();创建一个新的byte数组输出流;
- ByteArrayOutputStream(int size);创建一个新的byte数组输出流,它具有指定大小的缓冲区容量(内部封装缓冲数组);
- 常用方法:
- size();返回缓冲区的当前大小;
- toByteArray();创建一个新分配的byte数组;
- toString();使用平台默认字符集,将缓冲区内容转换为字符串;
- write(int b);
- write(byte[] b,int off,int len);
- writeTo(OutputStream out);将此byte数组输出流的全部内容写入到指定的输出流参数中;
import java.io.*;
class ByteArrayStream {
public static void main(String[] args) {
//数据源。
ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes());
//数据目的
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int by = 0;
while((by=bis.read())!=-1){
bos.write(by);
}
System.out.println(bos.size());
System.out.println(bos.toString());
// bos.writeTo(new FileOutputStream("a.txt"));
}
}
操作字符数组
如果操作的数据都是字符则使用字符数组的流;该流使用方式与操作字节数组一样;
CharArrayReader
- 构造函数:
- CharArrayReader(char[] buf);
- CharArrayReader(char[] buf,int offset,int length);
- 常用方法:
- read();读取单个字符;
- read(char[] b,int off,int len);将字符读入数组的某一部分;
CharArrayWriter
- 构造函数:
- CharArrayWriter();创建一个新的CharArrayWriter;
- CharArrayWriter(int initialSize);创建一个指定大小的CharArrayWriter;
- 常用方法:
- append(char c);将指定字符添加到此writer;
- flush();刷新流到缓冲区;
- size();返回缓冲区的当前大小;
- toCharArray();返回输入数据的副本;
- toString();将输入数据转换为你字符串;
- write(char[] c,int off,int len);将字符写入缓冲区;
- write(int c);将一个字符写入缓冲区;
- write(String str,int off,int len);将字符串某一部分写入缓冲区;
- writeTo(Write out);将缓冲区的内容写入另一个字符流;
操作字符串
StringReader
- 构造函数:
- StringReader(String s);其源为一个字符串的字符流,创建一个新字符串,reader;
- 常用方法:
- read();读取单个字符;
- read(char[] cbuf,int off,int len);将字符读入数组的某一个部分;
StringWrite
构造函数:
- StringWrite();使用默认初始化字符串缓冲区大小创建一个新的字符串writer;
- StringWrite(int initialSize);使用指定初始字符串缓冲区大小创建一个新字符串 writer;
常用方法:
- append(char c)/(CharSequence csq);将指定字符(或字符序列)添加到此 writer
- flush();刷新该流的缓冲;
- getBuffer();返回该字符串缓冲区本身;
- toString();以字符串的形式返回该缓冲区的当前值;
- write(char[] cbuf,int off,int len);写入字符数组的某一部分;
- write(int c);写入单个字符;
- write(String str);写入一个字符串;
- write(String str,int off,int len);写入字符串的某一部分;
编码表
- 可以指定编码的流:转换流,打印流;
- 最常用:
- InputStreamReader
- OutputStreamWriter
- 只能打印,不能读取:
- PrintStream
- PrintWriter
常见编码表
- ASCII:美国标准信息交换码,用一个字节的7位可以表示;
- ISO8859-1:拉丁码表,欧洲码表,用一个字节的8位表示;
- GB2312:中文编码表;
- GBK:中文编码表升级;
- Unicode:国际标准码;
- UTF-8:最多三个字节表示一个字符;
编码
字符串变成字符数组
String——byte[]:str.getBytes(String charsetName);字符串String方法;charsetName-指定编码表的字符串名称;
解码
byte[]——String:new String(byte[],charsetName);
注:如果中文字符串用“GBK”编码,用“ISO8859-1”解码,会出现乱码(因为不识别),将解码后的乱码再用“ISO8859-1”编码回去,则与“GBK”编码相同(因为不识别,编码未被改变,再用“GBK”解码,则结果为原中文字符串,如果该字符用“UTF-8”去解码,再编码,则编码将发生变化与原“GBK”编码不同,用“GBK”去解码时,结果不是原中文字符串,因为“UTF-8”页识别中文,用“UTF-8”解码再编码后,将按照“UTF-8”编码表中的字符对原解出的乱码进行编码,则结果发生变化,所以只有不识别中文的编码表才能进行解码再编码后,结果不变);
import java.util.*;
class EncodeDemo{
public static void main(String[] args)throws Exception {
String s = "哈哈";
byte[] b1 = s.getBytes("GBK");
System.out.println(Arrays.toString(b1));
String s1 = new String(b1,"utf-8");
System.out.println("s1="+s1);
//对s1进行iso8859-1编码。
byte[] b2 = s1.getBytes("utf-8");
System.out.println(Arrays.toString(b2));
String s2 = new String(b2,"gbk");
System.out.println("s2="+s2);
}
}
import java.io.*;
class EncodeStream {
public static void main(String[] args) throws IOException {
//writeText();
readText();
}
public static void readText()throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("utf.txt"),"gbk");
char[] buf = new char[10];
int len = isr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
isr.close();
}
public static void writeText()throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"UTF-8");
osw.write("你好");
osw.close();
}
}