第十章 输入 / 输出处理
DESCRIPTION
第十章 输入 / 输出处理. 输入输出概述. 输入 / 输出处理: 从键盘读取数据; 向屏幕中输出数据; 从文件中读或者向文件中写数据 在一个网络连接上进行读写操作等。 在 Java 中,把这些不同类型的输入、输出抽象为 流 ( Stream ) ,用统一的接口来表示,从而使程序设计简单明了。. 输入流和输出流. 流是程序和外界进行数据交换的通道 输入流 (InputStream) 程序通过输入流从数据源读取数据 输出流 (OutputStream) 通过输出流向目的地写数据。. java.io 包. - PowerPoint PPT PresentationTRANSCRIPT
1
第十章 输入 / 输出处理
2
输入输出概述 输入 / 输出处理:
从键盘读取数据; 向屏幕中输出数据; 从文件中读或者向文件中写数据 在一个网络连接上进行读写操作等。
在 Java 中,把这些不同类型的输入、输出抽象为流( Stream ),用统一的接口来表示,从而使程序设计简单明了。
3
输入流和输出流 流是程序和外界进行数据交换的通道
输入流 (InputStream) 程序通过输入流从数据源读取数据
输出流 (OutputStream) 通过输出流向目的地写数据。
4
java.io 包
在 Java 开发环境中,主要是由包 java.io 中提供的一系列的类和接口来实现输入 / 输出处理。
标准输入 / 输出 (System.out 和 System.in)处理则是由包 java.lang 中提供的类来处理的,但这些类又都是从包 java.io 中的类继承而来。
5
字节流和字符流
输入输出流的类型 字节输入 / 输出流:以字节为读写单位 字符输入 / 输出流:以字符为读写单位
6
字节流
InputStream ByteArrayInputStream FileInputStream FilterInputStream
BufferedInputStream DataInputStream PushbackInputStream
ObjectInputStream PipedInputStream SequenceInputStream
OutputStream ByteArrayOutputStream FileOutputStream FilterOutputStream
BufferedOutputStream DataOutputStream PrintStream
ObjectOutputStream PipedOutputStream
InputStream 类是所有字节输入流的父类 OutputStream 类是所有字节输出流的父类
7
InputStream 类的方法 (1) InputStream 是一个抽象类,不能被实例化。它提供了一系列
和读取数据有关的方法。 int read() // 从数据源读入一个字节的数据,当读到流的末尾时,返回 -1 int read(byte[ ] b)
// 从输入流中读取若干个字节到字节数组 b ,返回值为实际读取的字节数,当读到流的末尾时,返回 -1
int read(byte[ ] b,int off, int len)// 从输入流中读取长度为 len 的数据,写入数组 b 中从索引 off 开始的位置,并返回读取得字节数。当读到流的末尾时,返回 -1
void close()// 当完成读操作后,应该关闭输入流。
8
InputStream 类的方法 (2) skip() :跳过流中若干字节数
available() :返回流中可用字节数
mark() :在流中标记一个位置
reset() :返回标记过得位置
markSupport() :是否支持标记和复位操作
9
OutputStream 类的方法 OutputStream 类是所有字节输出流的父类,它是一个抽象类,不能被实例化。
它提供了一系列和写数据有关的方法。
void write(int), // 向输出流写一个字节数据。 void write(byte[] b) // 向输出流写一个字节数组的数据
void close() // 当完成写操作后,应该关闭输出流。
void flush() OutputStream 类本身的 flush() 方法不执行任何操作,它的一些带有缓冲区的子
类(比如 BufferedOutputStream 和 PrintStream 类)覆盖了 flush() 方法。通过带缓冲区的输出流写数据时,数据先保存在缓冲区中,积累到一定程度才会真正写到输出流中。缓冲区通常用字节数组实现,实际上是指一块内存空间。 flush() 方法强制把缓冲区内的数据写到输出流中。
10
InputStream 和 OutputStream 示例 把输入流中的所有内容复制到输出流中
public void copy(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[4096]; int len = in.read(buf); //read 方法可能抛出 IOException while (len != -1) { out.write(buf, 0, len); //write 方法可能抛出 IOException len = in.read(buf); }}
11
字节流——文件流 FileInputStream 类:
用来打开一个输入文件,若要打开的文件不存在,则会产生 FileNotFoundException 异常,这是一个已检查异常,必须捕获或抛出;
FileOutputStream 类: 用来打开一个输出文件,若要打开的文件不存在,则会创建
一个新的文件,否则原文件的内容会被新写入的内容所覆盖。
在进行文件的读 / 写操作时,可能会产生已检查异常 IOException ,必须捕获或抛出(其它的输入 / 输出流处理时也同样需要进行输入 / 输出异常处理)。
12
文件字节流的构造方法 文件流的构造方法:
FileInputStream(String name) 打开一个文件路径名为 name 的文件作为输入。
FileOutputStream(String name) 创建一个文件路径名为 name 的文件作为输出,文件如果
已经存在,则其内容被清空。
FileOutputStream(String name, boolean append)
创建一个文件路径名为 name 的文件作为输出,文件如果已经存在,则在该输出流上输出的内容被接到原有内容之后还是覆盖取决于 append 的值。
13
文件流示例 1 把一个文件的内容加到另一个文件后public void cat(String fsrc, String fdest) { try { InputStream in = new FileInputStream(fsrc); OutputStream out =
new FileOutputStream(fdest, true); copy(in, out); out.close(); in.close(); } catch (IOException ex) { System.err.println(ex); }}
14
文件流示例 2功能:将文件中的内容显示在控制台。
import java.io.*;
class FileReaderSample { public static void main(String agrs[])throws IOException{ FileInputStream in=new FileInputStream(“e:\\in.txt"); int data; while((data=in.read())!=-1) System.out.print(data +“ ”); // 以 ASCII 码的形式显示文件中的内容 in.close(); }} 演示 FileReaderSample.java
15
文件流示例 3功能:将字符串写入文件
import java.io.*;
public class FileWriterSample{
public static void main(String args[]) { try { FileOutputStream fileOut = new FileOutputStream(“E:\\out.tx
t"); fileOut.write(“ 你好” .getBytes()); // 调用 String.getByte() 方法返回字符串数组 fileOut.close(); } catch(FileNotFoundException e) { } catch(IOException e) { } }}
演示 FileWriterSample.java
16
字节流—过滤流 FilterInputStream 和 FilterOutputStre
am: 用于扩展字节输入 / 输出流功能的装饰器,它有好几个子类,分别用来扩展字节输入 / 输出流的某一种功能
要使用过滤流,首先必须把它连接到某个输入 / 输出流上,通常在构造方法的参数中指定所要连接的流:
FilterInputStream(InputStream in); FilterOutputStream(OutputStream out);
17
过滤流子类: DataInputStream 类 DataInputStream : 用于读取基本类型数据,如 int 、 float 、 long 、 double 和 boolean 等,
以及采用 UTF-8编码的字符串。 DataInputStream 类的所有读方法都都以“ read”开头,比如:
byte readByte() :从输入流中读取 1 个字节,把它转换为 byte 类型的数据。
long readLong() :从输入流中读取 8 个字节,把它转换为 long 类型的数据。
float readFloat() :从输入流中读取 4 个字节,把它转换为 float 类型的数据。
String readUTF() :从输入流中读取 1 到 3 个字节,把它转换为采用 UTF-8编码的字符串。
18
过滤流子类: DataOutputStream 类 DataOutputStream :用于写入基本类型数据,如 int 、
float 、 long 、 double 和 boolean 等和 UTF编码的字符串
writeByte() :写入 1 个字节到输出流。
writeLong() :写一个 long 类型的数据到输出流。
writeFloat() :写一个 long 类型的数据到输出流。
writeUTF() :写入一个用 UTF-8编码的字符串。
19
DataInputStream 和 DataOutputStream示例
FileOutputStream out1=new FileOutputStream("D:\\test.txt"); BufferedOutputStream out2=new BufferedOutputStream(out1); //装饰文件输出流 DataOutputStream out=new DataOutputStream(out2); //装饰带缓冲输出流 out.writeByte(-12); out.writeLong(12); out.writeChar('1'); out.writeUTF(" 好 "); out.close();
InputStream in1=new FileInputStream("D:\\test.txt"); BufferedInputStream in2=new BufferedInputStream(in1); //装饰文件输入流 DataInputStream in=new DataInputStream(in2); //装饰缓冲输入流 System.out.print(in.readByte()+" "); System.out.print(in.readLong()+" "); System.out.print(in.readChar()+" "); System.out.print(in.readUTF()+" "); in.close();
演示 FormatDataIO.java
20
过滤流子类:缓冲流 类 BufferedInputStream 和 BufferedOutputStream
实现了带缓冲的过滤流,它提供了缓冲机制,把任意的 I/O 流“捆绑”到缓冲流上,可以提高读写效率。
在初始化时,除了要指定所连接的输入输出流之外,还可以指定缓冲区的大小。
BufferedInputStream(InputStream in[, int size]) BufferedOutputStream(OutputStream out[, int size])
21
过滤流子类:缓冲流示例
public void copy(InputStream in, OutputStream out)
throws IOException { out = new BufferedOutputStream(out, 4096); byte[] buf = new byte[4096]; int len = in.read(buf); while (len != -1) { out.write(buf, 0, len); len = in.read(buf); } out.flush(); // 强制将尚未填满的缓冲区中的数据送出。}
22
过滤流:其它
PushBackInputStream :它提供了一个方法将刚刚读入的一个或多个字节退回到输入流中去。
PrintStream :其作用是将 Java语言中的不同类型的数据以字符表示形式输出到相应的输出流中去。
23
字节流——标准流语言包 java.lang 中的 System 类管理标准输入 / 输出流
和错误流。
System.in 继承 InputStream , 用于从标准输入设备中获取输入数据 ( 通常是键盘 ) 。
System.out , 继承 PrintStream ,把输出送到缺省的显示设备 ( 通常是控制台 ) 。
System.err , 继承 PrintStream ,把错误信息送到缺省的显示设备 ( 通常是控制台 ) 。
每当 main 方法被执行时,就自动生成上述三个对象。
24
标准输入输出示例public static void main(String args[]) { try { byte bArray[]=new byte[128]; String str; System.out.println(“Please enter something:"); System.in.read(bArray); str = new String(bArray); System.out.print("You entered:"); System.out.println(str); } catch(IOException ioe) { System.err.println(ioe.toString()); }}
见 SysIOSample.java
25
URL 输入流( java.net.URL ) InputStream is = null; try { URL url= new URL("http://www.javathinker.org/weiqin/sole.ht
m"); is = url.openStream(); byte buffer[] = new byte[2048]; is.read(buffer,0,buffer.length); System.out.println(new String(buffer)); } catch (IOException e){}
演示 URLTest.java
26
字符输入输出流 在 JDK1.1之前, java.io 包中的流只有普通的字节流
(以 byte 为基本处理单位的流),这种流对于以 16位的 Unicode码表示的字符流处理很不方便。从 JDK1.1 开始, java.io 包中加入了专门用于字符流处理的类,它们是以 Reader 和Writer 为基础派生的一系列类。
同 InputStream 和 OutputStream 一样, Reader 和Writer也是抽象类,只提供了一系列用于字符流处理的接口。它们的方法与类 InputStream 和 OutputStream 类似,只不过其中的参数换成字符或字符数组。
27
Reader 和Writer 类
Reader BufferedReader
LineNumberReader CharArrayReader FilterReader
PushbackReader InputStreamReader
FileReader PipedReader StringReader
Writer BufferedWriter
CharArrayWriter FilterWriter
OutputStreamWriter FileWriter
PipedWriter StringWriter PrintWriter
Reader :是所有字符输入流的父类 Writer : 是所有字符输出流的父类。
28
输入输出字符流的构造 默认情况下,如果你构造了一个连接到字符流的 Reader 和Writer ,那么转换规则会对本地平台默认的字符编码和 Unicode 进行转换。
在构造 InputStreamReader 类和 OutputStreamWriter 类的实例时,你可以指定输出流或输入流的字符编码。
InputStreamReader reader=new InputStreamReader(new FileInputStream("D:\\test.txt"), "UTF-8" );char c=(char)reader.read();
29
关于字符编码 系统属性file.encoding 表示本地平台的字符编码, ,
中文系统一般是 GBK (参见 propertyTester.java )
字符串的相关方法 String(byte[] bytes, String enc) //按指定的字符编码 enc构造字符串
byte[] getBytes(String enc) // 获得按指定的字符编码的字节数组
30
Properties p=System.getProperties(); //Properties 类封装了与 java运行环境相关的系统属性集,在 java.util 包中 Enumeration k=p.keys(); Enumeration e=p.elements();
String userName= (String)p.get("user.name"); while(k.hasMoreElements()){ System.out.println(k.nextElement()+ " :"+ e.nextElement()); }
(参见 propertyTester.java )
如何获得本地平台的编码类型
31
字符流——与字节流连用 InputStreamReader OutputStreamWriter
用于处理字符流的最基本的类,用来在字节流和字符流之间作为中介。使用这两者进行字符处理时,在构造方法中应指定一定的平台规范,以便把以字节方式表示的流转换为特定平台上的字符表示。
InputStreamReader(InputStream in); //缺省规范 InputStreamReader(InputStream in, String enc); // 指定规范 enc OutputStreamWriter(OutputStream out); //缺省规范 OutputStreamWriter(OutputStream out, String enc); // 指定规范 e
nc
32
字节流与字符流连用示例import java.util.*;import java.io.*;
public class ReadFile{
public static void main(String args[]) throws Exception{ MyReaderWriter rw=new MyReaderWriter(); rw.copyfile(“E:\\hello.txt”,“E:\\hello1.txt"); }
public void copyfile(String from, String to)throws Exception{ char[] cbuf=new char[2064]; FileInputStream fin=new FileInputStream(from); InputStreamReader ir=new InputStreamReader(fin);
FileOutputStream fo=new FileOutputStream(to); OutputStreamWriter ow=new OutputStreamWriter(fo,"MS950");
int length=0; while((length=ir.read(cbuf, 0, 2064))!=-1){ System.out.println(cbuf); } ir.close(); ow.close(); }
演示 ReadFile.java
33
BuffereReader和 PrintWriter
BfferedReader
PrintWriter
34
BufferedReader
BufferedReader
带有缓冲区,可以先把一批数据读到缓冲区内,接下来的读操作都是从缓冲区内获取数据,避免每次都从数据源读取数据并进行字符编码转换,从而提高读操作的效率。
可采用 BufferedReader 来装饰其他Reader ,以提高效率。 构造方法:
BufferedReader(Reader in) :参数 in 指定被装饰的 Reader 类。 BufferedReader(Reader in, int sz) :参数 in 指定被装饰的 Reader
类,参数 sz指定缓冲区的大小,以字符为单位。 提供了整行字符处理方法:
public String readLine() : BufferedReader 的方法,从输入流中读取一行字符,行结束标志为‘ \n’、‘ \r’或两者一起。
35
PrintWriter
PrintWriter 能输出格式化的数据, PrintWriter 的写数据的方法都以 print 开头,比如:
print(int i) :向输出流写入一个 int 类型的数据。 print(long l): 向输出流写入一个 long 类型的数据。 print(float f): 向输出流写入一个 float 类型的数据。 print(String s): 向输出流写入一个 String 类型的数据。 println(int i): 向输出流写入一个 int 类型的数据和换行符。 println(long l): 向输出流写入一个 long 类型的数据和换行符。 println(float f): 向输出流写入一个 float 类型的数据和换行符。 println(String s): 向输出流写入一个 String 类型的数据和换行符
println(“hello”);等价于:print(“hello”)print(“\n”)
36
字符流——其它 CharArrayReader & CharArrayWriter
对字符数组进行处理
StringReader & StringWriter 对字符串进行处理
FilterReader & FilterWriter 过滤字符流
PipedReader & PipedWriter 管道字符流
LineNumberReader 行处理字符输入流
37
文件类 File :以文件路径名的形式代表一个文件或目录 FileDescriptor :代表一个打开文件的文件描述 FileFilter & FilenameFilter :用于列出满足条件的文
件 File.list(FilenameFilter fnf) File.listFiles(FileFilter ff) FileDialog.setFilenameFilter(FilenameFilter fnf)
FileInputStream & FileReader :顺序读文件 FileOutputStream & FileWriter :顺序写文件 RandomAccessFile :提供对文件的随机访问支持。
38
File 类 File 类(在 java.io 包中)提供了若干创建文
和处理文件、目录和获取它们基本信息的方法。
File 类的构造方法:1. File(String pathname)
//pathname 为文件或目录的路径
2. File(String parent, String child)
3. File(File parent, String child)
39
File 类的方法 查看文件属性: boolean canRead() boolean isFile() long lastModified() : // 可强制转化为 Date 类型 创建或删除目录: mkdir(), delete() // 若为目录,必须为空目录,才可以删除 列出目录下的所有文件: String[] list() 判断文件是否存在: boolean exists()
重新命名文件: renameTo()
40
File 类的方法 创建新文件: createNewFile()
返回文件名或最后一级目录名 String getName()
返回文件所在目录的路径或本目录的上级目录路径 String getParent()
System.out.println("getParent="+new File ("E:\\Dir1\\Dir2\\test.txt").getParent());System.out.println("getName="+new File ("E:\\Dir1\\Dir2\\test.txt").getName());
结果:E:\Dir1\Dir2test.txt
41
File dir1=new File("D:\\dir1");if(!dir1.exists())dir1.mkdir();
File dir2=new File(dir1,"dir2");if(!dir2.exists())dir2.mkdirs();
File dir3=new File(dir1,"dir3");if(!dir3.exists())dir3.mkdirs();
File dir4=new File(dir1,"dir3\\dir4");if(!dir4.exists())dir4.mkdirs();
File file=new File(dir2,"test.txt");
if(!file.exists())file.createNewFile();
创建文件系统
创建目录和文件示例
见 UseFile.java
42
打印目录和文件示例public static void listDir(File dir){ File[ ] lists=dir.listFiles(); // 打印当前目录下包含的所有子目录和文件的名字 String info=" 目录 :"+dir.getName()+"("; for(int i=0;i<lists.length;i++) info+=lists[i].getName()+" "; info+=")"; System.out.println(info); }
见UseFile.java
43
/** 删除目录或文件,如果参数 file代表目录,会删除当前目录以及目录下的所有内容 */ public static void deleteDir(File file){ // 如果file代表文件,就删除该文件 if(file.isFile()){ file.delete(); return; } // 如果file代表目录,先删除目录下的所有子目录和文件 File[] lists=file.listFiles(); for(int i=0;i<lists.length;i++) deleteDir(lists[i]); //递归删除当前目录下的所有子目录和文件 //最后删除当前目录 file.delete(); }
删除目录或文件示例
见UseFile.java
44
RandomAccessFile 类
RandomAccessFile 类: 用来随机读取和写入文件 (即可以写入文件中任何一个地方 )
实现了 DataInput 和 DataOutput 接口 readBoolean(), readByte(), readChar(), readLine()… writeBoolean(), writeByte(), writeChar(), writeLine()…
提供了定位文件的方法
45
RandomAccessFile(File file, String mode)
RandomAccessFile(String name, String mode)
mode 的取值: “r” 只读 . 任何写操作都将抛出 IOException 。 “rw” 读写 . 文件不存在时会创建该文件,文件存在时,原
文件内容不变,通过写操作改变文件内容。 “rws” 同步读写 . 等同于读写,但是任何协操作的内容都
被直接写入物理文件,包括文件内容和文件属性。 “rwd” 数据同步读写 . 等同于读写,但任何内容写操作都直接写到物理文件。
RandomAccessFile 类的构造方法
46
DataInput 和 DataOutput 中的方法 readInt(), writeDouble()…
int skipBytes(int n) :将指针向下移动若干字节
length() :返回文件长度
long getFilePointer() :返回指针当前位置
void seek(long pos) :将指针调到所需位置
void setLength(long newLength) :设定文件长度
RandomAccessFile 类的方法
47
import java.io.*;
public class RandomTester { public static void main(String args[])throws IOException{ RandomAccessFile rf=new RandomAccessFile("D:\\test.dat","rw"); for(int i=0;i<10;i++) rf.writeLong(i*1000);
rf.seek(5*8); // 从文件开头开始,跳过第 5 个 long 数据,接下来写第 6 个 long 数据
rf.writeLong(1234);
rf.seek(0); // 把读写指针定位到文件开头 for(int i=0;i<10;i++) System.out.println("Value"+i+":"+rf.readLong());
rf.close(); }
Value0:0Value1:1000Value2:2000Value3:3000Value4:4000Value5:1234Value6:6000Value7:7000Value8:8000Value9:9000
RandomTester.java