1.7 Standard I/O(18.8)
1.什么是标准I/O?标准I/O的意义是什么?
答: 1)程序所使用的单一信息流,程序的所有输入都可来自标准输入,所有输出也可都发送到标准输出,所有错误信息发送到标准错误。
2)易于把程序串联起来,一个程序的标准输出可以成为另一程序的标准输入。
2.System.out和System.err都包装成了PrintStream,而System.in只是一个未包装的InputStream。我们使用System.in之前必须对其进行包装。
3.Java中标准I/O有那些?答:System.in、System.out和System.err。
4.如何从标准输入中读取?(如何封装System.in?) 并写出代码说明?
答:用readLine()一次一次地读取输入,我们将System.in包装成BufferedReader来使用,必须用InputStreamReader把System.in转换成Reader。
【说明代码如下:将直接回显你所输入的每一行】
import java.io.*;
public class Echo {
public static void main(String args){
BufferedReader stdin = new BufferedReader(
new InputStreamReader(System.in));
String s;
while((s = stdin.readLine())!=null && s.length()!= 0)
System.out.println(s);
} }
5.如何将System.out转换成PrintWriter?
答:System.out是一个PrintStream,而PrintStream是一个OutputStream。利用PrintWriter有一个可接受OutputStream作为参数的构造器把System.out转换成PrintWriter。
// true是开启自动清空功能,否则看不到输出。
PrintWriter out = new PrintWriter(System.out,true);
out.println("Hello,world")
6.什么是标准I/O重定向?主要用于解决什么问题?
答:Java的System类提供了一些静态方法调用,以允许我们对标准输入、输出和错误I/O流进行重定向:setIn(InputStream)、setOut(OutStream)、setErr(OutStream)。
主要解决用户输入序列的命令行滚动的问题。
import java.io.*;
public class Redirecting{
public static void main(String args){
PrintStream console = System.out;
BufferedInputStream in = new BufferedInputStream(
new FileInputStream("Redirecting.java"));
PrintStream out = new PrintStream(
new BufferedOutputStream(new FileOutStream("test.out"))
);
System.setIn(in);System.setOut(out);System.setErr(out);
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
String s;
while((s = br.readLine())!=null)
System.out.println(s);
out.close;
System.setOut(console);
}
}
这个程序将标准输入附接到文件上,并将标准输出和标准错误重定向到另一个文件。PS:它在程序开头处存储了对最初的System.out对象的引用,并且在结尾处将系统输出恢复到了该对象上了。
*I/O重定向操纵的是字节流,而不是字符流;因此,我们使用的是InputStream和OutputStream,而不是Reader和Writer。
7.I/O典型使用方式有那些?答:缓冲输入文件、从内存输入、格式化的内存输入、格式化的内存输入、基本的文件输出、存储和恢复数据、读写随机访问文件、管道流。
8.如何从缓冲输入文件?
若想要打开一个文件用于字符输入,可用以String或File对象作为文件名的FileInputReader。为了提高速度,要对那个文件进行缓冲,则将产生的引用传给一个BufferdReader构造器。由于BufferedReader也提供readLine()方法,当readLine()将返回null时,则达到文件末尾了。
// file ->FileReader ->BufferedReader ->StringBuilder(String)
import java.io.*;
public class BufferedInputFile{
public static String read(String filename) throws IOException{
// Reading input by lines;
BufferedReader in = new BufferedReader(new FileReader(filename));
String s;
StringBuilder sb = new StringBuilder();
while((s = in.readLine())!=null)
sb.append(s + "/n"); //必须添加换行符,readLine()已将它们删掉了。
in.close();
return sb.toString();
}
public static void main(String[] args) throws IOException{
System.out.println(read("BufferedInputFile.java"));
}
}
9.如何从内存输入?
答:从BufferedInputFile.read()读入的String结果被用来创建一个StringReader。然后调用read()每次读取一个字符,并把它发送到控制台。
import java.io.*;
public class MemoryInput {
public static void main(String args[]){
StringReader in = new StringReader(BufferedInputFile.read("MemoryInput.java"));
int c;
while((c=in.read())!=-1)
System.out.print((char)c);
}
}
ps:read()是以int形式返回下一字节,因此必须类型转换为char才能正确打印。
10.如何格式化的内存输入?并举例说明怎样一次一个字节地读取文件。
答:PrintWriter可以对数据进行格式化,以便人们的阅读。
要读取格式化数据,可以使用DataInputStream,它是一个面向字节的I/O类,因此我们必须使用InputStream类而不是Reader类。我们这里用的是字符串。我们可以用InputStream以字节的形式读取任何数据(例如一个文件)。
package io;
import java.io.*;
public class FormatedMemoryInput{
public static void main(String args[]) throws IOException{
try{
DataInputStream in = new DataInputStream( new ByteArrayInputStream(
BufferedInputFile.read("D://iotest//FormatedMemoryInput.java").getBytes()
));
// 从DataInputStream用readByte()一次一个字节地读取字符,那么任何字节值皆合法,
// 因此返回值不能用来检测输入是否结束,相反,我们可使用available()方法
// 查看还有多少可供存取的字符。
while(true)
System.out.print((char)in.readByte());
}catch(EOFException e){
System.err.println("End of stream");
}
}
}
【Example1: 演示了怎样一次一个字节地读取文件】:
import java.io.*;
public class TestEOF {
public static void main(String args[]) throws IOException{
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream("TestEOF.java")));
while(in.available()!=0)
System.out.print((char)in.readByte());
} }
11.完成基本的文件输出需要几个步骤?并代码说明。
答: FileWriter对象可以向文件写入数据。
方法步骤:
1)创建一个与指定文件连接的FileWriter。
2)用BufferedWriter将其包装起来用以缓冲输出(缓冲往往能显著地增加I/O操作的性能)
3)为了提供格式化机制,它被装饰成了PrintWriter。
4)按照这种方式创建的数据文件可作为普通文本文件读取。
package io;
import java.io.*;
public class BasicFileOutput {
static String file = "d://iotest//BasicFileOutput.out";
public static void main(String args[]) throws IOException{
// BufferedReader -> StringReader -> BufferedReader -> FileReader
// BufferedInputFile.read :BufferedReader -> FileReader("d://iotest//BasicFileOutput.java")
BufferedReader in = new BufferedReader(
new StringReader(
BufferedInputFile.read("d://iotest//BasicFileOutput.java")));
PrintWriter out = new PrintWriter(
new BufferedWriter(new FileWriter(file)));
// 此行改为则快捷方式
int lineCount = 1; // 当文本行被写入文件时,行号就会增加。
String s;
while( (s = in.readLine())!= null )
out.println(lineCount++ + ":" + s);
// 一旦读完输入数据流,readLine()就会返回null.
// 若不显式调用close()就会缓冲区内容不会被刷新清空
out.close();
// Show the stored file
System.out.println(BufferedInputFile.read(file));
}
}
*文本文件输出的快捷方式:JavaSE5在PrintWriter中添加了一个辅助构造器,免去了执行所有的装饰工作。
将PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));改为PrintWriter out = new PrintWriter(file);
12.如何存储和恢复数据?
答:PrintWriter可以对数据进行格式化,以便人们的阅读。但是要想存储与恢复“流”的数据,我们要用DataOutputStream写入数据,并用DataInputStream恢复数据。PS:DataOutputStream和DataInputStream都是面向字节的,因此要使用InputStream和OutputStream。
UTF方式是可靠的方式,
package io;
import java.io.*;
public class StoringAndRecoveringData {
public static void main(String args[]) throws IOException{
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("d://iotest/Data.txt")));
out.writeDouble(3.1415927);
out.writeUTF("That was pi");
out.writeDouble(1.41413);
out.writeUTF("Spuare root of 2");
out.close();
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream("d://iotest/Data.txt")));
System.out.println(in.readDouble());
System.out.println(in.readUTF());
System.out.println(in.readDouble());
System.out.println(in.readUTF());
}
}
13.如何读写随机访问文件:
1.RandomAccessFile和DataInputStream、DataOutputStream相似之处?
答:都实现了相同的接口:DataInput和DataOutput.
2.RandomAccessFile中可利用seek()可以在文件中到处移动,并修改文件中的某个值。使用RandomAccessFile时,必须知道文件排版,才能正确操作它。拥有读取基本类型和UTF-8字符串的各种具体方法。
3.RandomAccessFile不支持装饰,r(只读) rw(读写)
import java.io.*;
public class UsingRandomAccessFile {
static String file = "d://iotest//rtest.dat";
static void display() throws IOException {
// 获得RandomAccessFile对象,打开文件,并以double形式显示其中7个值
RandomAccessFile rf = new RandomAccessFile(file,"r");
for(int i=0;i<7;i++)
System.out.println("Value" + i + ": " + rf.readDouble());
System.out.println(rf.readUTF());
rf.close();
}
public static void main(String args[]) throws IOException{
RandomAccessFile rf = new RandomAccessFile(file,"rw");
for(int i=0;i<7;i++)
rf.writeDouble(i*1.414);
rf.writeUTF("The end of the file");
rf.close();
display();
rf = new RandomAccessFile(file,"rw");
// double是8字节长,所以为了用seek()查找第5个双精度值,只需用5*8来产生查找位置
rf.seek(5*8);
rf.writeDouble(47.0001);
rf.close();
display();
}
}
*XML是另一种方式,可以解决在不同的计算平台之间移动数据,而不依赖于所有平台都有JAVA这一问题。