ByteArrayInputStream和ByteArrayOutputStream
之前所讲解的程序中,输出和输入都是从文件中来得,当然,也可以将输出的位置设置在内存之上,此时就要使用ByteArrayInputStream、ByteArrayOutputStream来完成输入输出功能了
ByteArrayInputStream的主要功能将内容输入到内存之中
ByteArrayOutputStream的主要功能是将内存中的数据输出
此时应该把内存作为操作点
ByteArrayInputStream类的定义:
public class ByteArrayInputStream extends InputStream
构造方法:
public ByteArrayInputStream(byte[] buf)
接受一个byte数组,实际上内存的输入就是在构造方法上将数据传入到内存中。
ByteArrayOutputStream:输出就是从内存中写出数据
public void write(int b)
以下是以内存操作流完成的一个大小写字母转换的程序:

1 import java.io.ByteArrayInputStream; 2 import java.io.ByteArrayOutputStream; 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 7 public class Test22 { 8 public static void main(String[] args) throws IOException { 9 String str="HELLO WORlD!!!"; 10 InputStream input=new ByteArrayInputStream(str.getBytes()); 11 OutputStream output=new ByteArrayOutputStream(); 12 int temp=0; 13 while((temp=input.read())!=-1){ 14 output.write(Character.toLowerCase(temp)); 15 } 16 input.close(); 17 output.close(); 18 System.out.println(output.toString()); 19 } 20 }
管道流(线程通信流)
管道流的主要作用是可以进行两个线程间的通讯,分为管道输出流(PipedOutputStream)、管道输入流(PipedInputStream),如果想要进行管道输出,则必须要把输出流连在输入流之上,在PipedOutputStream类上有如下的一个方法用于连接管道:
public void connect(PipedInputStream snk)throws IOException
例子:线程之间用管道流进行通讯

1 import java.io.IOException; 2 import java.io.PipedInputStream; 3 import java.io.PipedOutputStream; 4 5 class Send implements Runnable{ 6 7 private PipedOutputStream pos;//管道输出流 8 public Send(){ 9 pos=new PipedOutputStream(); 10 } 11 @Override 12 public void run() { 13 String str="Hello World!"; 14 try { 15 pos.write(str.getBytes()); 16 } catch (IOException e) { 17 e.printStackTrace(); 18 } 19 try { 20 pos.close(); 21 } catch (IOException e) { 22 e.printStackTrace(); 23 } 24 } 25 public PipedOutputStream getPos() { 26 return pos; 27 } 28 } 29 30 class Receive implements Runnable{ 31 32 private PipedInputStream pis;//管道输入流 33 public Receive(){ 34 pis=new PipedInputStream(); 35 } 36 @Override 37 public void run() { 38 byte[] b=new byte[1024]; 39 int len=0; 40 try { 41 len=pis.read(b); 42 } catch (IOException e) { 43 e.printStackTrace(); 44 } 45 try { 46 pis.close(); 47 } catch (IOException e) { 48 e.printStackTrace(); 49 } 50 System.out.println(new String(b,0,len)); 51 } 52 public PipedInputStream getPis() { 53 return pis; 54 } 55 } 56 57 public class Test23 { 58 public static void main(String[] args) { 59 Send send=new Send(); 60 Receive receive=new Receive(); 61 try { 62 send.getPos().connect(receive.getPis());//连接管道 63 } catch (IOException e) { 64 e.printStackTrace(); 65 } 66 new Thread(send).start();//启动线程 67 new Thread(receive).start();//启动线程 68 } 69 }

在整个IO包中,打印流是输出信息最方便的类,主要包含字节打印流(PrintStream)和字符打印流(PrintWrite)。打印流提供了非常方便的打印功能,可以打印任何的数据类型,例如:小数、整数、字符串等等。
看一下PrintStream的构造方法:
public PrintStream(OutputStream out)
在PrintStream中定义的构造方法中可以清楚的发现有一个构造方法可以直接接收OutputStream类的实例,这是因为与OutputStream相比起来,PrintStream可以更加方便的输出数据,这就好比将OutputStream类重新包装了一下,使之输出更加方便。
使用PrintStream输出信息:

1 import java.io.File; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 import java.io.PrintStream; 5 6 public class Test24 { 7 public static void main(String[] args) throws IOException { 8 File f = new File("d:" + File.separator+"test.txt"); 9 PrintStream output=new PrintStream(new FileOutputStream(f)); 10 output.println("Hello World!"); 11 output.print("1+1="+2); 12 output.close(); 13 } 14 }

也就是说此时,实际上是将FileOutputStream类的功能包装了一下,这样的设计在java中称为装饰设计。
但如果仅仅是上面的那些功能也未免太寒碜了吧,好吧,看绝招,大家学过C吧~:

1 import java.io.File; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 import java.io.PrintStream; 5 6 public class Test25 { 7 public static void main(String[] args) throws IOException { 8 File f = new File("d:" + File.separator+"test.txt"); 9 PrintStream output=new PrintStream(new FileOutputStream(f)); 10 String name="Jim"; 11 int age=20; 12 float score=90.5f; 13 char sex='M'; 14 output.printf("姓名:%s 年龄:%d 成绩:%f 性别:%c", name,age,score,sex); 15 output.close(); 16 } 17 }

哈哈,竟然有printf!~而且你要是觉得%s %d %f %c太麻烦,可以全用%s代替,比C的printf还好用
System类的常量
System表示系统类,此类也对IO给予了一定的支持。
- public static final PrintStream out 对应系统标准输出,一般是显示器
- public static final PrintStream err 错误信息输出
- public static final InputStream in 对应着标准输入,一般是键盘
System.out
使用System.out输出的时候就是将输出的位置定义在了显示器之中。
FileOutputStream是定位在文件里,而System.out是定位在屏幕上。
使用OutputStream完成屏幕上输出(PrintStream是OutputStream的子类)
1 import java.io.IOException; 2 import java.io.OutputStream; 3 4 public class Test26 { 5 public static void main(String[] args) throws IOException { 6 OutputStream out=System.out; 7 out.write("Hello World!".getBytes()); 8 out.close(); 9 } 10 }
System.err
System.err表示的错误的标准输出,如果程序中出现了错误的话,则直接使用System.err进行打印输出即可。

1 public class Test27 { 2 public static void main(String[] args) { 3 String str="Hello World"; 4 try{ 5 int a=Integer.parseInt(str); 6 }catch(Exception e){ 7 System.err.println(e); 8 } 9 } 10 }

但是有些人会问这跟System.out输出的结果完全一样的嘛,有什么区别啊?
System.out与System.err的区别
- System.out和System.err都是PrintStream的实例化对象,而且通过实例代码可以发现,两者都可以输出错误信息,但是一般来讲System.out是将信息显示给用户看,是正常的信息显示,而System.err的信息正好相反是不希望用户看到,会直接在后台打印,是专门显示错误的
- 一般来讲,如果要想输出错误信息的时候最好不要使用System.out而是直接使用System.err,这一点只能从其概念上划分。
System.in
System.in实际上是一个键盘的输入流,其本身是InputStream类型的对象。那么,此时就可以利用此方式完成从键盘读取数据的功能。
InputStream对应的是输入流,输入流的话肯定可以从指定位置上读取,之前使用的是FileInputStream是从文件中读取的

1 import java.io.IOException; 2 import java.io.InputStream; 3 4 public class Test28 { 5 public static void main(String[] args) throws IOException { 6 InputStream in=System.in; 7 byte[] b=new byte[1024]; 8 int len=in.read(b); 9 System.out.println(new String(b,0,len)); 10 } 11 }

如果不使用byte数组指定长度呢:

1 import java.io.IOException; 2 import java.io.InputStream; 3 4 public class Test29 { 5 public static void main(String[] args) throws IOException { 6 InputStream in=System.in; 7 StringBuilder buf=new StringBuilder(); 8 int temp=0; 9 while((temp=in.read())!=-1){ 10 char c=(char) temp; 11 if(c=='\n')break; 12 buf.append(c); 13 } 14 in.close(); 15 System.out.println(buf.toString()); 16 } 17 }

但以上代码还是有很大问题的,输入中文的话~,所以最好的方法还是一次性把数据都放在内存了,再一次性全部拿出来,要实现这个功能的话,要用到BufferedReader类,下回介绍~
输入输出重定向
System.out、System.err、System.in都有重定向功能,分别是setOut、setErr、setIn方法
System.out重定向

1 import java.io.File; 2 import java.io.FileNotFoundException; 3 import java.io.PrintStream; 4 5 public class Test30 { 6 public static void main(String[] args) throws FileNotFoundException { 7 File f = new File("d:" + File.separator+"test.txt"); 8 System.setOut(new PrintStream(f)); 9 String str="This is a test!"; 10 System.out.println(str); 11 } 12 }

System.err重定向

1 import java.io.ByteArrayOutputStream; 2 import java.io.PrintStream; 3 4 public class Test31 { 5 public static void main(String[] args) { 6 ByteArrayOutputStream out=new ByteArrayOutputStream(); 7 System.setErr(new PrintStream(out)); 8 System.err.println("Test---------------"); 9 System.out.println(out.toString()); 10 } 11 }

一般不建议修改err的重定向,因为这些信息都不太希望用户看到
System.in重定向

1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.IOException; 4 import java.io.InputStream; 5 6 public class Test32 { 7 public static void main(String[] args) throws IOException { 8 File f = new File("d:" + File.separator+"test.txt"); 9 System.setIn(new FileInputStream(f)); 10 InputStream in=System.in; 11 byte[] b=new byte[1024]; 12 int len=in.read(b); 13 in.close(); 14 System.out.println(new String(b,0,len)); 15 } 16 }

一般,使用最多的还是System.out的重定向~
如果想要接收任意长度的数据,而且避免乱码产生,就可以使用BufferedReader类
public class BufferedReader extends Reader
因为输入的数据有可能出现中文,所以,此处使用字符流完成。BufferedReader是从缓冲区之中读取内容,所有的输入的字节数据都将放在缓冲区之中。
System.in本身表示的是InputStream(字节流),现在要求接收的是一个字符流,需要将字节流变成字符流才可以,所以要用InputStreamReader

1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStreamReader; 4 5 public class Test33 { 6 public static void main(String[] args) throws IOException { 7 BufferedReader reader=new BufferedReader(new InputStreamReader(System.in)); 8 String str=reader.readLine(); 9 System.out.println(str); 10 } 11 }

在JDK1.5之后Java提供了专门的输入数据类,此类可以完成BufferedReader类的功能,也可以方便的对输入数据进行验证,此类存放在java.util包中
使用Scanner接收键盘的输入数据:

1 import java.util.Scanner; 2 3 public class Test34 { 4 public static void main(String[] args) { 5 Scanner s=new Scanner(System.in); 6 String str=s.next(); 7 System.out.println(str); 8 } 9 }

比直接使用BufferedReader更加方便,但是这个程序是有问题的,如果输入的字符串中存在空格,那么就会截止,如果我们要接收空格的下,将分隔符变成“\n”。

1 import java.util.Scanner; 2 3 public class Test34 { 4 public static void main(String[] args) { 5 Scanner s=new Scanner(System.in); 6 s.useDelimiter("\n");//使用分隔符 7 String str=s.next(); 8 System.out.println(str); 9 } 10 }
