请多参考JDK文档:
http://www.matools.com/api/java8
https://docs.oracle.com/javase/8/docs/api/
1、转换流——OutputStreamWriter类和InputStreamReader类
字节与字符的转换流:
- OutputStreamWriter:是Writer类的子类,将输出的字符流变为字节流。
- InputStreamReader:是Reader类的子类,将输入的字节流变为字符流。
如果以文件操作为例,则内存的字符数据需要变为字节数据才能保存到文件中,反之亦然。如下图所示。
- 将字符输出流变为字节输出流
OutputStreamWriter(OutputStream out)
创建一个使用默认字符编码的OutputStreamWriter。
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String path="F:"+File.separator+"IO"+File.separator+"test.txt";
File file=new File(path);
OutputStream out=new FileOutputStream(file);
//将字符流变为字节流
Writer writer=new OutputStreamWriter(out);
//使用字符流输出
writer.write("Hello OutputStreamWriter");
writer.close();
}
- 将字节输入流变为字符输入流
InputStreamReader(InputStream in)
创建一个使用默认字符集的InputStreamReader。
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String path="F:"+File.separator+"IO"+File.separator+"test.txt";
File file=new File(path);
InputStream in=new FileInputStream(file);
char[] c=new char[(int) file.length()];
//将字节流变为字符流
Reader reader=new InputStreamReader(in);
//将字符流数据内容读取到字符数组中,同时返回读入的个数
int len=reader.read(c);
reader.close();
System.out.println(new String(c,0,len));
}
2、内存操作流
在生成一些临时信息时,就需要将内容保存至内存中而非文件中,这时就可以将输入输出的位置设置在内存中。
-
ByteArrayInputStream:主要将内容写入内存中。
ByteArrayInputStream(byte[] buf)
创建一个 ByteArrayInputStream ,使其使用 buf作为其缓冲区数组。
ByteArrayInputStream(byte[] buf, int offset, int length)
将指定范围的内容写入内存中。 -
ByteArrayOutputStream:主要将内存的数据取出来。
ByteArrayOutputStream()
创建一个新的字节数组输出流。
write(int b)
将指定的字节写入此字节数组输出流。使用内存操作流将大写字母变为小写字母:
public static void main(String[] args) {
// TODO Auto-generated method stub
String str="HelloBYTEARRAY";
//1、将内容写如内存中
ByteArrayInputStream bis=new ByteArrayInputStream(str.getBytes());
//2、准备从ByteArrayInputStream中读取数据
ByteArrayOutputStream bos=new ByteArrayOutputStream();
int temp=0;//接收读取的每一个内容
//3、将每次的读取内容给temp变量
while((temp=bis.read())!=-1) {
//4、将读取的内容变为字符——toLowerCase()需要
//public static char toLowerCase(char ch) {}
char c=(char)temp;
//将字符变为小写字母
//5、write()将内容从内存中输出
bos.write(Character.toLowerCase(c));
}
String newStr=bos.toString();
try {
bis.close();
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(newStr);
}
3、管道流
线程之间进行通信,需要使用管道流。进行管道输出,必须将输出流连接在输入流上面。
- PipedOutputStream:管道输出流。
- PipedInputStream:管道输入流。
在PipedOutputStream类上面有连接管道的方法:
public void connect(PipedInputStream snk)
throws IOException
将此管道输出流连接到接收器。 如果此对象已连接到其他管道输入流,则抛出IOException 。
验证管道流:
public class PipedDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Send send=new Send();
Receive receive=new Receive();
try {
send.pos.connect(receive.getPis());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(send).start();
new Thread(receive).start();
}
}
class Send implements Runnable{
//管道输出流
PipedOutputStream pos=null;
public Send() {
//实例化输出流
this.pos=new PipedOutputStream();
}
@Override
public void run() {
// TODO Auto-generated method stub
String str="Hello 管道流";
try {
this.pos.write(str.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//关闭输出流
try {
this.pos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//通过线程类得到输出流
public PipedOutputStream getPos() {
return pos;
}
}
class Receive implements Runnable{
//声明输入流
PipedInputStream pis=null;
public Receive() {
this.pis=new PipedInputStream();
}
@Override
public void run() {
// TODO Auto-generated method stub
byte[] b=new byte[666];
int len=0;
try {
len=this.pis.read(b);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
this.pis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("接收的内容为:"+new String(b,0,len));
}
public PipedInputStream getPis() {
return pis;
}
}
结果:
接收的内容为:Hello 管道流
定义了两个线程对象,在发送的线程类中定义了管道输出流,在接收的线程类中定义了管道的输入流,,通过PipedOutputStream类中的connect()方法将线程连接起来,线程启动后会自动进行管道的输入输出操作。
4、打印流
在IO包中,打印流是输出信息最方便的类,主要包含了字节打印流(PrintStream)和字符打印流(PrintWriter)。
通过查看JDK文档,可以发现字节打印流和字符打印流很多方法类似,此处分析字节打印流类 。
在JDK文档中可以看见有趣的构造方法:
PrintStream(OutputStream out),创建一个新的打印流。
这个方法可以直接接收OutputStream类的实例,这是因为与OutputStream相比,PrintStream类可以更方便输出数据就像将OutputStream重新包装了一下,使之输出更方便。这就是“装饰设计模式”的应用。
- 使用PrintStream输出
File file=new File(path);
OutputStream out = null;
PrintStream ps = null;
try {
out = new FileOutputStream(file);
ps=new PrintStream(out);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//直接通过print()向文件中输出数据
ps.print("Hello PrintStream");
ps.close();
- 使用打印流进行格式化
格式化输出 | |
---|---|
字符 | 描述 |
%s | 表示内容为字符串 |
%d | 表示内容为整数 |
%f | 表示内容为小数 |
%c | 表示内容为字符 |
File file=new File(path);
OutputStream out = null;
PrintStream ps = null;
try {
out = new FileOutputStream(file);
ps=new PrintStream(out);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String name="张三";
int age=18;
//直接通过print()向文件中输出数据
ps.printf("姓名:%s,年龄:%d",name,age);
ps.close();
5、System类对IO的支持
System类对IO操纵的常用变量
System类的常量 | 描述 |
---|---|
public final static PrintStream out | 对于系统标准输出,一般是显示器 |
public final static PrintStream err | 错误信息打印 |
public final static PrintStream in | 对于着标准输入,一般是键盘 |
System类中这三个常量未大小写是历史遗留的问题
-
System.out
System.out是PrintStream的对象,而PrintStream又是OutputStream的子类,所有可以直接使用System.out直接实例化OutputStream类的对象- 使用OutputStream向屏幕输出
public static void main(String[] args) {
// TODO Auto-generated method stub
//此时输出流是向屏幕输出
OutputStream out=System.out;
try {
//向屏幕输出
out.write("Hello System".getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
- System.err
System.err表示将错误信息输出
System.out与System.err输出的结果感觉一样,但System.out是将信息展示给用户看,是正常的信息显示。而System.err的信息正好相反,是不希望用户看到的,会直接在后台打印,是专门显示错误的。
public static void main(String[] args) {
// TODO Auto-generated method stub
String str="Hello System";
//制造错误
try {
//parseInt()是将字符串转int型
System.out.println(Integer.parseInt(str));
} catch (Exception e) {
// TODO: handle exception
System.err.println(e);
}
}
- System.in
System.in是一个键盘输入流,其本身是一个InputStream类型的对象。
public static void main(String[] args) {
// TODO Auto-generated method stub
InputStream in=System.in;
System.out.println("请输入内容:");
byte[] b=new byte[20];
int len=0;
try {
len=in.read(b);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("输入的内容:"+new String(b,0,len));
}
当byte[]长度为奇数时,输出的数据不完整
byte[] b=new byte[5];
int len=0;
try {
len=in.read(b);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("输入的内容:"+new String(b,0,len));
结果:
请输入内容:
测试中
输入的内容:测试?
一个中文==两个字符,如果数组是奇数并且输入的内容大于数组就会出现“?”的情况。
指定数组大小输入的数据又会被限制,如果不指定数据的大小又会因一个字节一个字节的读取使中文全部变为乱码。因此在使用System.in输入数据时最好采用将数据全部存放在内存中,再从内存中一次性取出的方式解决。
而需要完成上面要求就需要采用重定向处理
6、输入输出重定向
输入输出重定向最简单的理解就是,重新指定输入输出的方向或位置。
System提供的重定向方法 | ||
---|---|---|
方法 | 类型 | 描述 |
public static void setOut(PrintStream out) | 普通 | 重定向“标准”输出流 |
public static void setErr(PrintStream err) | 普通 | 重定向“错误”输出流 |
public static void setIn(PrintStream in) | 普通 | 重定向“标准输入流” |
- 为System.out输出重定向
String str="F:"+File.separator+"IO"+File.separator+"System.txt";
File file=new File(str);
OutputStream out=null;
try {
out=new FileOutputStream(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
PrintStream ps=new PrintStream(out);
System.setOut(ps);
System.out.println("System.setOut()重定向“标准”输出流");
- 为System.err输出重定向
PrintStream ps=new PrintStream(out);
System.setErr(ps);
System.err.println("System.setErr()重定向“标准”错误输出流");
- 为System.in输出重定向
InputStream in=new FileInputStream(file);
System.setIn(in);
InputStream input=System.in;
byte[] b=new byte[66];
int len=input.read(b);
System.out.println(new String(b,0,len));
in.close();
input.close();
上面代码,将System.in的输入位置设置到了从文件读取,所有读取时会将文件中的内容读取出来。
实际开发中不要修稿System.err和System.in的重定向。
7、BufferedReader类
BufferedReader类用于从缓冲区里面读取内容,所有的输入字节数据都放在缓冲区。
BufferedReader类的常用方法 | |
---|---|
方法 | 描述 |
public BufferedReader(Reader in) | 接收一个Reader类的实例 |
public String readLine() throws IOException | 一次性从缓冲区中将内容读取出来 |
BufferedReader类的构造方法已经说明只接收字节数据,因此在从键盘上面输入数据时应该使用InputStreamReader将字节输入流变为字符流。
//输入的内容会自动放在缓冲区中
BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入内容:");
//从缓冲区中读取内容
String str = null;
try {
str=bf.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("输入的内容为:"+str);
}