6. Java输入输出
内容 I/O概述 I/O字节流 I/O字符流 随机访问文件 文件其它 模式 2017/9/12
1. I/O概述 大部分程序都需要输入/输出处理,比如从键盘读取数据、向屏幕中输出数据、从文件中读或者向文件中写数据、在一个网络连接上进行读写操作等。 在Java中,把这些不同类型的输入、输出抽象为流(Stream),而其中输入或输出的数据则称为数据流(Data Stream),用统一的接口来表示,从而使程序设计简单明了。 2017/9/12
流一般分为输入流(Input Stream)和输出流(Output Stream)两类,但这种划分并不是绝对的。比如一个文件,当向其中写数据时,它就是一个输出流;当从其中读取数据时,它就是一个输入流。当然,键盘只是一个输入流,而屏幕则只是一个输出流。 在Java开发环境中,主要是由包java.io中提供的一系列的类和接口来实现输入/输出处理。标准输入/输出处理则是由包java.lang中提供的类来处理的,但这些类又都是从包java.io中的类继承而来。 2017/9/12
在JDK1.1之前,java.io包中的流只有普通的字节流(以byte为基本处理单位的流),这种流对于以16位的Unicode码表示的字符流处理很不方便。 从JDK1.1开始, java.io包中加入了专门用于字符流处理的类(以Reader和Writer为基础派生的一系列类)。 另外,为了使对象的状态能够方便地永久保存下来, JDK1.1以后的java.io包中提供了以字节流为基础的用于对象的永久化保存状态的机制(通过实现ObjectInput和ObjectOutput接口)。 2017/9/12
I/O字节流 InputStream 2017/9/12 ByteArrayInputStream: 允许一个buffer作为输入流 StringBufferInputStream:将一个字符串转换成输入流 FileInputStream:从文件中读入内容 PipedInputStream:创建一个管道 SequenceInputStream:将两个或更多个输入流合并 FilterInputStream :抽象的类,定义了提供进一步功能 DataInputStream:从流中直接读入基本类型 BufferedInputStream:采用Buffer缓存 LineNumberInputStream:跟踪输入流的行数 PushbackInputStream:一般用于编译器 ObjectInputStream 2017/9/12
OutputStream ByteArrayOutputStream:创建一个Buffer,输出流数据将放入 FileOutputStream:发送信息到文件 PipedOutputStream:管道 FilterOutputStream: DataOutputStream PrintStream:输出 BufferedOutputStream ObjectOutputStream 2017/9/12
I/O字符流 2017/9/12 Reader Writer BufferedReader:通过缓冲输入提高性能 LineNumberReader CharArrayReader:是一个把字符数组作为源的输入流的实现。该类有两个构造函数,每一个都需要一个字符数组提供数据源 FilterReader PushbackReader InputStreamReader FileReader:创建了一个可以读取文件内容的Reader类 PipedReader StringReader Writer BufferedWriter CharArrayWriter PipedWriter StringWriter OutputStreamWriter FileWriter FilterWriter PrintWriter:PrintWriter本质上是PrintStream的字符形式的版本。它提供格式化的输出方法print( )和println( ) 2017/9/12
2. 字节流——InputStream read():从流中读入数据 skip():跳过流中若干字节数 available():返回流中可用字节数 mark():在流中标记一个位置 reset():返回标记过得位置 markSupport():是否支持标记和复位操作 close():关闭流 2017/9/12
int read(byte b[], int off, int len) 从输入流中读一个字节,形成一个0~255之间的整数返回(是一个抽象方法)。 int read(byte b[]) 读多个字节到数组中。 int read(byte b[], int off, int len) 从输入流中读取长度为len的数据,写入数组b中从索引off开始的位置,并返回读取得字节数。 对于这三个方法,若返回-1,表明流结束。 2017/9/12
OutputStream write(int b) write(byte b[]) 将一个整数输出到流中(只输出低位字节,抽象) write(byte b[]) 将字节数组中的数据输出到流中 write(byte b[], int off, int len) 将数组b中从off指定的位置开始,长度为len的数据输出到流中 flush():刷空输出流,并将缓冲区中的数据强制送出 close():关闭流 2017/9/12
例子 把输入流中的所有内容复制到输出流中 2017/9/12 public void copy(InputStream in, OutputStream out) throws IOException { byte[] buf = new byte[4096]; int len = in.read(buf); while (len != -1) { out.write(buf, 0, len); len = in.read(buf); } 2017/9/12
文件流 输出文件 输入文件 文件对象的建立 对文件操作要定义文件流 File fp=new File(“tempfile.txt”); FileInputStream类用来打开一个输入文件 FileOutputStream类用来打开一个输出文件 输出文件 输入文件 write read 2017/9/12
文件流的建立 例:文件拷贝(注意要捕获文件异常) file1.txt file2.txt FileInputStream in=new FileInputStream(fp); FileOutputStream out=new FileOutputStream(fp); 例:文件拷贝(注意要捕获文件异常) 输入流的参数是用于输入的文件名 输出流的参数是用于输出的文件名 file1.txt file2.txt 输入流 输出流 2017/9/12
2017/9/12 class filestream { public static void main(String args[]) import java.io.*; class filestream { public static void main(String args[]) { try{ File inFile=new File(”file1.txt"); File outFile=new File(”file2.txt"); FileInputStream fis=new FileInputStream(inFile); FileOutputStream fos=new FileOutputStream(outFile); int c; while((c=fis.read())!=-1) fos.write(c); fis.close(); fos.close(); }catch(FileNotFoundException e) { System.out.println("FileStreamsTest: "+e); }catch(IOException e) { System.err.println("FileStreamsTest: "+e); }}} 2017/9/12
过滤流 类FilterInputStream和FilterOutputStream分别对其他输入/输出流进行特殊处理,它们在读/写数据的同时可以对数据进行特殊处理。另外还提供了同步机制,使得某一时刻只有一个线程可以访问一个输入/输出流。 类FilterInputStream和FilterOutputStream分别重写了父类InputStream和OutputStream的所有方法,同时,它们的子类也应该重写它们的方法以满足特定的需要。 要使用过滤流,首先必须把它连接到某个输入/输出流上,通常在构造方法的参数中指定所要连接的流: FilterInputStream(InputStream in); FilterOutputStream(OutputStream out); 这两个类是抽象类,构造方法也是保护方法。 2017/9/12
过滤流:缓冲流 类BufferedInputStream和BufferedOutputStream实现了带缓冲的过滤流,它提供了缓冲机制,把任意的I/O流“捆绑”到缓冲流上,可以提高读写效率。 在初始化时,除了要指定所连接的I/O流之外,还可以指定缓冲区的大小。缺省大小的缓冲区适合于通常的情形;最优的缓冲区大小常依赖于主机操作系统、可使用的内存空间以及机器的配置等;一般缓冲区的大小为内存页或磁盘块等地整数倍,如8912字节或更小。 BufferedInputStream(InputStream in[, int size]) BufferedOutputStream(OutputStream out[, int size]) 2017/9/12
文件 文件流 缓冲区流 增加缓冲区流,减少访问硬盘的次数,提高效率 file1.txt 输入缓冲区 输出缓冲区 file2.txt 输入流 输出流 文件 文件流 缓冲区流 2017/9/12
BufferedInputStream和 BufferedOutputStream 将它们与文件流相接 缓冲区流: BufferedInputStream和 BufferedOutputStream 将它们与文件流相接 FileInputStream in=new FileInputStream(“file1.txt”); BufferedInputStream bin= new BufferedInputStream(in,256) int len; byte bArray[]=new byte[256]; len=bin.read(bArray); len中得到是长度, bArray中得到的是数据 2017/9/12
文件 只有缓冲区满时,才会将数据送到输出流. Java在输出数据流中,当对方尚未将数据取走时,程序就会被阻塞. 有时要人为地将尚未填满的缓冲区中的数据送出,使用flush()方法. 文件 2017/9/12
2017/9/12 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(); 2017/9/12
DataInput 2017/9/12 boolean readBoolean() byte readByte() short readShort() char readChar() int readInt() long readLong() double readDouble() float readFloat() int readUnsignedByte() int readUnsignedShort() 2017/9/12
2017/9/12 void readFully(byte[] b) 读满字节数组,不同于InputStream.read void readFully(byte[] b, int off, int len) 读满指定长度,不同于InputStream.read int skipBytes(int n) 与InputStream.skip等价 String readUTF() UTF-8形式从输入中读取字符串 String readLine() 按回车(\r)换行(\n)为分割符读取一行字符串 不完全支持UNICODE 2017/9/12
DataOutput 2017/9/12 void writeBoolean(boolean v) void writeByte(int v) void writeShort(int v) void writeChar(int v) void writeInt(int v) void writeLong(long v) void writeFloat(float v) void writeDouble(double v) 2017/9/12
2017/9/12 void write(byte[] b) void write(byte[] b, int off, int len) 与OutputStream.write同义 void write(byte[] b, int off, int len) void write(int b) void writeBytes(String s) 只输出每个字符的低8位;不完全支持UNICODE。 void writeChars(String s) 每个字符在输出中都占两个字节。 2017/9/12
过滤流:数据流 DataInputStream和DataOutputStream 在提供了字节流的读写手段的同时,以统一的通用的形式向输入流中写入boolean,int,long,double等基本数据类型,并可以再次把基本数据类型的值读取回来。 提供了字符串读写的手段。 分别实现了DataInput和DataOutput接口 2017/9/12
6.4 数据输入输出流 class datainput_output { public static void main(String args[]) throws IOException { FileOutputStream fos=new FileOutputStream(“a.txt”); DataOutputStream dos=new DataOutputStream (fos); try{ dos.writeBoolean(true); dos.writeByte((byte)123); dos.writeChar('J'); dos.writeDouble(3.141592654); dos.writeFloat(2.7182f); dos.writeInt(1234567890); dos.writeLong(998877665544332211L); dos.writeShort((short)11223); }finally{ dos.close(); } 6.4 数据输入输出流 2017/9/12
6.4 数据输入输出流 DataInputStream dis=new DataInputStream( new FileInputStream(”a.txt")); try{ System.out.println("\t "+dis.readBoolean()); System.out.println("\t "+dis.readByte()); System.out.println("\t "+dis.readChar()); System.out.println("\t "+dis.readDouble()); System.out.println("\t "+dis.readFloat()); System.out.println("\t "+dis.readInt()); System.out.println("\t "+dis.readLong()); System.out.println("\t "+dis.readShort()); }finally{dis.close();} }} 6.4 数据输入输出流 Stream\datainputandoutput--->f5.bat 2017/9/12
过滤流:其它 2017/9/12 LineNumberInputStream:主要用于对文本文件的处理,提供了行号控制功能。 已经被LineNumberReader取代 PushBackInputStream:它提供了一个方法将刚刚读入的一个或多个字节退回到输入流中去。 在编译程序的词法分析阶段,经常要超前读入一个字节以界定当前词的属性,然后再将该字节退回(因为下面的处理可能还会用到该字节)。 PrintStream:其作用是将Java语言中的不同类型的数据以字符表示形式输出到相应的输出流中去。 不产生异常。可自动flush。通过checkError()检查错误。 2017/9/12
标准流 2017/9/12 语言包java.lang中的System类管理标准输入/输出流和错误流。 System.in,从InputStream中继承而来,用于从标准输入设备中获取输入数据(通常是键盘)。 System.out,从PrintStream中继承而来,把输出送到缺省的显示设备(通常是显示器)。 System.err,也是从PrintStream中继承而来,把错误信息送到缺省的显示设备(通常是显示器)。 每当main方法被执行时,就自动生成上述三个对象。 2017/9/12
2017/9/12 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()); 2017/9/12
对象流 2017/9/12 对象的持续性(Persistence) 对象的串行化(Serialization) 对象流 能够纪录自己的状态以便将来再生的能力,叫对象的持续性。 对象的串行化(Serialization) 对象通过写出描述自己状态的的数值来记录自己的过程叫串行化。串行化的主要任务是写出对象实例变量的数值,如果变量是另一个对象的引用,则引用的对象也要串行化。这个过程是递归的。 对象流 能够输入输出对象的流称为对象流。 可以将对象串行化后通过对象输入输出流写入文件或传送到其它地方。 2017/9/12
在java中,允许可串行化的对象在通过对象流进行传输。只有实现Serializable接口的类才能被串行化, Serializable接口中没有任何方法,当一个类声明实现Serializable接口时,只是表明该类加入对象串行化协议。 public class Student implements Serializable { int id; String name; int age; String department; transient int number; // 第几个对象实例 static int count; // 创建对象实例的计数器 } 2017/9/12
要串行化一个对象,必须与一定的对象输出/输入流联系起来,通过对象输出流将对象状态保存下来(将对象保存到文件中,或者通过网络传送到其他地方) ,再通过对象输入流将对象状态恢复。 类ObjectOutputStream和ObjectInputStream分别继承了接口ObjectOutput和ObjectInput,将数据流功能扩展到可以读写对象,前者用writeObject()方法可以直接将对象保存到输出流中,而后者用readObject()方法可以直接从输入流中读取一个对象。 2017/9/12
例子 2017/9/12 public class Objectser { public static void main(String args[]) { Student stu=new Student(981036, “Li Ming”, 16, “CSD”); try { FileOutputStream fo = new FileOutputStream(“data.ser”); ObjectOutputStream so = new ObjectOutputStream(fo); so.writeObject(stu); so.close(); } catch(Exception e) { System.err.println(e); 2017/9/12
(续) 2017/9/12 public class ObjectRecov { public static void main(String args[]) { Student stu; try { FileInputStream fi = new FileInputStream(“data.ser”); ObjectInputStream si = new ObjectInputStream(fi); stu = (Student)si.readObject(); si.close(); } catch(Exception e) { System.out.println(e); } System.out.println(“ID: ”+stu.id+“name:”+ stu.name+“age:”+age+“dept.:”+stu.department); } } 2017/9/12
定制对象的串行化:在类定义中重写readObject()和WriteObject()方法。 private void writeObject(ObjectOutputStream out) throws IOException { out.writeInt(id); … // out.defaultWriteObject() } private void readObject(ObjectInputStream in) throws IOException { id = in.readInt(); … // out.defaultReadObject() 2017/9/12
Serializable Externalizable 2017/9/12 void readExternal(ObjectInput in) void writeExternal(ObjectOutput out) 2017/9/12
public class FooImpl implements java.io.Externalizable { private String message; public String getFoo() { return message; } public void setMessage(String message) { this.message = message; private Object writeReplace() throws ObjectStreamException { System.out.println("writeReplace invoked"); return this; private Object readResolve() throws ObjectStreamException { System.out.println("readResolve invoked"); public Object serialize() throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return ois.readObject(); public void readExternal(ObjectInput arg0) throws IOException, ClassNotFoundException { System.out.println("readExternal invoked"); Object obj = arg0.readObject(); } public void writeExternal(ObjectOutput arg0) throws IOException { System.out.println("writeExternal invoked"); arg0.writeObject("Hello world"); public static void main(String[] args) throws IOException, ClassNotFoundException { FooImpl fooimpl = new FooImpl(); fooimpl.serialize(); } writeReplace invoked writeExternal invoked readExternal invoked readResolve invoked 2017/9/12
管道流 管道用来把一个程序、线程和代码块的输出连接到另一个程序、线程和代码块的输入。java.io中提供了类PipedInputStream和PipedOutputStream作为管道的输入/输出流。 管道输入流作为一个通信管道的接收端,管道输出流则作为发送端。管道流必须是输入输出并用,即在使用管道前,两者必须进行连接。 输出流 输入流 2017/9/12
管道输入/输出流可以用两种方式进行连接: 在构造方法中进行连接 PipedInputStream(PipedOutputStream pos); PipedOutputStream(PipedInputStream pis); 通过各自的connect()方法连接 在类PipedInputStream中, connect(PipedOutputStream pos); 在类PipedOutputStream中, connect(PipedInputStream pis); 2017/9/12
内存流 2017/9/12 为了支持在内存上的I/O,java.io中提供了类 ByteArrayInputStream ByteArrayOutputStream StringBufferInputStream ByteArrayInputStream可以从指定的字节数组中读取数据 ByteArrayOutputStream中提供了缓冲区可以存放数据(缓冲区大小可以在构造方法中设定),可以用write()方法向其中写入数据,然后用toByteArray()方法将缓冲区中的有效字节写到字节数组中去。size()方法可以知道写入的字节数;reset()可以丢弃所有内容。 StringBufferInputStream与ByteArrayInputStream相类似,不同点在于它是从字符缓冲区StringBuffer中读取16位的Unicode数据,而不是8位的字节数据。 (已被StringReader取代) 2017/9/12
2017/9/12 ByteArrayInputStream ByteArrayOutputStream ByteArrayInputStream(byte[] buf) ByteArrayInputStream(byte[] buf, int offset, int length) ByteArrayOutputStream void reset() :重写内容 int size() :返回写入的字节数 byte[] toByteArray() :以新分配的字节数组形式返回写入的内容 String toString() :以缺省字符编码方式把内容编程字符串返回 String toString(String enc) :以指定字符编码方式返回字符串 void writeTo(OutputStream out) :把内容写到另一个输出流中 2017/9/12
顺序输入流 java.io中提供了类SequenceInputStream,使应用程序可以将几个输入流顺序连接起来,让程序员看起来就像是一个比较长的流一样。顺序输入流提供了将多个不同的输入流统一为一个输入流的功能,这使得程序可能变得更加简洁。如: FileInputStream f1 = new FileInputStream(“file1.txt”); FileInputStream f2 = new FileInputStream(“file2.txt”); SequenceInputStream fs = new SequenceInputStream(f1, f2); FileOutputStream f3 = new FileOutputStream(“file3.txt”); copy(fs, f3); f3.close(); fs.close(); 2017/9/12
3. 字符流
3.1 概述 在JDK1.1之前,java.io包中的流只有普通的字节流(以byte为基本处理单位的流),这种流对于以16位的Unicode码表示的字符流处理很不方便。从JDK1.1开始, java.io包中加入了专门用于字符流处理的类,它们是以Reader和Writer为基础派生的一系列类。 同类InputStream和OutputStream一样,Reader和Writer也是抽象类,只提供了一系列用于字符流处理的接口。它们的方法与类InputStream和OutputStream类似,只不过其中的参数换成字符或字符数组。 2017/9/12
3.2 字符标准 在unicode之前,对于每一种语言都存在独立的字符编码系统,每个系统都使用相同的数字(0-255)来表示这种语言的字符。一些语言(象俄语)对于如何表示相同的字符还有几种有冲突的标准;另一些语言(象日语)拥有太多的字符,需要多个字符集。 在系统之间进行文档交流是困难的,因为对于一台计算机来说,没有方法可以识别出文档的作者使用了哪种编码模式;计算机看到的只是数字,并且这些数字可以表示不同的东西 2017/9/12
为了解决这些问题,unicode用一个 2 字节数字表示每个字符,从 0 到 65535。每个 2 字节数字表示至少在一种世界语言中使用的一个唯一字符。(在多种语言中都使用的字符具有相同的数字码。)这样就确保每个字符一个数字,并且每个数字一个字符。Unicode数据永远不会模棱两可。 但是仍然还存在着所有那些遗留的编码系统的情况。例如,7位 ASCII,它可以将英文字符存诸为从0到127的数值。(65是大写字母“A”,97是小写字母“a”,等等。)英语有着非常简单的字母表,所以它可以完全用7位 ASCII 来表示。象法语、西班牙语和德语之类的西欧语言都使用叫做ISO-8859-1的编码系统(也叫做“latin-1”),它使用7位 ASCII 字符表示从0到127的数字,但接着扩展到了128-255的范围来表示象n上带有一个波浪线(241),和u上带有两个点(252)的字符。Unicode使用同7位 ASCII 码一样的字符表示0到127,同ISO-8859-1一样的字符表示128到255,接着使用剩余的数字,256到65535,扩展到表示其它语言的字符。 2017/9/12
3.3 字符流——与字节流连用 InputStreamReader和OutputStreamWriter是java.io包中用于处理字符流的最基本的类,用来在字节流和字符流之间作为中介。使用这两者进行字符处理时,在构造方法中应指定一定的平台规范,以便把以字节方式表示的流转换为特定平台上的字符表示。 InputStreamReader(InputStream in); //缺省规范 InputStreamReader(InputStream in, String enc); //指定规范enc OutputStreamWriter(OutputStream out); //缺省规范 OutputStreamWriter(OutputStream out, String enc); //指定规范enc 2017/9/12
3.2 Reader 2017/9/12 int read() int read(char[] cbuf) int read(char[] cbuf, int off, int len) void close():关闭该流,在关闭流之后,进一步调用 read()、ready()、mark() 或 reset() 将会抛出 IOException void mark(int readAheadLimit):标记流中的当前位置。对 reset() 的后续调用将尝试将该流重新定位到此点。并不是所有的字符输入流都支持 mark() 操作 boolean markSupported() boolean ready() :如果保证下一个 read() 不阻塞输入,则返回 True,否则返回 false void reset() long skip(long n) :跳过字符。在某个字符可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞 2017/9/12
3.3 Writer 2017/9/12 void close() void flush() void write(char[] cbuf) void write(char[] cbuf, int off, int len) void write(int c) void write(String str) void write(String str, int off, int len) 2017/9/12
3.4 编码 如果读取的字符流不是来自本地时(比如网上某处与本地编码方式不同的机器),那么在构造字符输入流时就不能简单地使用缺省编码规范,而应该指定一种统一的编码规范“ISO 8859_1”,这是一种映射到ASCII码的编码方式,能够在不同平台之间正确转换字符。 InputStreamReader ir = new InputStreamReader( is, “8859_1” ); FileReader & FileWriter 采用缺省编码读写字符文件 采用其它编码处理字符文件时,采用 new InputStreamReader(new FileInputStream(file), “编码名”); 2017/9/12
3.5 缓冲 为了提高字符流处理的效率,java.io中也提供了缓冲流BufferedReader和BufferedWriter。其构造方法与BufferedInputStream和BufferedOutputStream相类似。另外,除了read()和write()方法外,它还提供了整行字符处理方法: public String readLine(): BufferedReader的方法,从输入流中读取一行字符,行结束标志为‘\n’、‘\r’或两者一起。 public void newLine(): BufferedWriter的方法,向输出流中写入一个行结束标志,它不是简单的换行符‘\n’或‘\r’,而是系统定义的行隔离标志(line separator)。此概念由系统属性 line.separator 定义。并非所有平台都使用新行符 ('\n') 来终止各行。因此调用此方法来终止每个输出行要优于直接写入新行符。 2017/9/12
3. 字符流——其它 2017/9/12 CharArrayReader & CharArrayWriter 对字符数组进行处理 StringReader & StringWriter 对字符串进行处理 FilterReader & FilterWriter 过滤字符流 PipedReader & PipedWriter 管道字符流 LineNumberReader 行处理字符输入流 PrintWriter 打印字符输出流 2017/9/12
4. 随机访问文件 2017/9/12 File:以文件路径名的形式代表一个文件 FileDescriptor:代表一个打开文件的文件描述 FileFilter & FilenameFilter:用于列出满足条件的文件 File.list(FilenameFilter fnf) File.listFiles(FileFilter ff) FileDialog.setFilenameFilter(FilenameFilter fnf) FileInputStream & FileReader:顺序读文件 FileOutputStream & FileWriter:顺序写文件 RandomAccessFile:提供对文件的随机访问支持。 2017/9/12
类RandomAccessFile则允许对文件内容同时完成读和写操作,它直接继承Object,并且同时实现了接口DataInput和DataOutput,提供了支持随机文件操作的方法: readInt(), writeDouble()… int skipBytes(int n):将指针向下移动若干字节 length():返回文件长度 long getFilePointer():返回指针当前位置 void seek(long pos):将指针调到所需位置 void setLength(long newLength):设定文件长度 2017/9/12
2017/9/12 RandomAccessFile(File file, String mode) RandomAccessFile(String name, String mode) mode 的取值: “r” 只读. 任何写操作都将抛出IOException。 “rw” 读写. 文件不存在时会创建该文件,文件存在时,原文件内容不变,通过写操作改变文件内容。 “rws” 同步读写. 等同于读写,但是任何协操作的内容都被直接写入物理文件,包括文件内容和文件属性。 “rwd” 数据同步读写. 等同于读写,但任何内容写操作都直接写到物理文件,对文件属性内容的修改不是这样。 2017/9/12
例子 2017/9/12 public static void main(String args[]) { int data_arr[]={12,31,56,23,27,1,43,65,4,99}; try { RandomAccessFile randf =new RandomAccessFile(“temp.dat”, “rw”); for (int i=0; i>data_arr.length; i++) randf.writeInt(data_arr[i]); for (int i=data_arr.length-1; i>=0; i--) { randf.seek(i*4); System.out.println(randf.readInt()); } randf.close(); } catch (IOException e){ System.out.println(“File access error: “+e); } } 2017/9/12
5. 文件其它操作 2017/9/12 File(String pathname) File f=new File(“c:\data\temp.dat”); File f=new File(“data\ temp.dat”); File f=new File(“temp.dat”); File(String parent, String child) File f=new File(“c:\data” ,“temp.dat”); File f=new File(“data ” ,“ temp.dat”); File(File parent, String child) File f=new File(new File(“c:\data”) ,“temp.dat”); File f=new File(new File(“data ”) ,“ temp.dat”); 2017/9/12
2017/9/12 boolean canRead():测试应用程序是否可以读取此抽象路径名表示的文件 boolean canWrite() :测试应用程序是否可以修改此抽象路径名表示的文件 boolean setReadOnly():标记此抽象路径名指定的文件或目录,以便只可对其进行读操作 boolean exists():测试此抽象路径名表示的文件或目录是否存在 boolean isDirectory() boolean isFile() boolean isHidden() long lastModified() boolean setLastModified(long time) long length() 2017/9/12
2017/9/12 String[] list() :返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组 String[] list(FilenameFilter filter):返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的 File[] listFiles() File[] listFiles(FileFilter filter) File[] listFiles(FilenameFilter filter) static File[] listRoots() boolean mkdir():创建此抽象路径名指定的目录 boolean mkdirs():创建此抽象路径名指定的目录,包括创建必需但不存在的父目录 2017/9/12
4. 文件操作——File (3 of 4) 2017/9/12 boolean createNewFile() static File createTempFile(String prefix, String suffix) : 在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称 static File createTempFile(String prefix, String suffix, File directory) boolean delete() void deleteOnExit():在虚拟机终止时,请求删除此抽象路径名表示的文件或目录 boolean renameTo(File dest) (粉色的方法在JDK1.2之后才支持) 2017/9/12
4. 文件操作——File (4 of 4) 2017/9/12 String getName() String getParent() :返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null File getParentFile() String getPath() boolean isAbsolute() File getAbsoluteFile() String getAbsolutePath() File getCanonicalFile() :返回此抽象路径名的规范形式 String getCanonicalPath() 2017/9/12
FileDescriptor 2017/9/12 FileInputStream & FileOutputStream RandomAccessFile FileDescriptor getFD() 通过FileDescriptor构造输入输出流 FileInputStream(FileDescriptor fdObj) FileOutputStream(FileDescriptor fdObj) FileReader(FileDescriptor fd) FileWriter(FileDescriptor fd) 例如: FileInputStream fin = new FileInputStream(“file.txt”); FileReader fr = new FileReader(fin.getFD()); 2017/9/12
7.设计模式: Decorator
Decorator模式 动态给一个对象添加一些额外的职责,.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活. 我们通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的. 使用Decorator的理由是:这些功能需要由用户动态决定加入的方式和时机.Decorator提供了"即插即用"的方法,在运行期间决定何时增加何种功能. 2017/9/12
2017/9/12 public interface Work { public void insert(); } 现在有一个应用:需要在桩打入前,挖坑,在打入后,在桩上钉木板,这些额外的功能是动态,可能随意增加调整修改,比如,可能又需要在打桩之后钉架子(只是比喻). public class SquarePeg implements Work{ public void insert(){ System.out.println("方形桩插入"); } } 2017/9/12
public class Decorator implements Work{ private Work work; //额外增加的功能被打包在这个List中 private ArrayList others = new ArrayList(); //在构造器中使用组合new方式,引入Work对象; public Decorator(Work work) { this.work=work; others.add("挖坑"); others.add("钉木板"); } public void insert(){ newMethod(); } 在新方法中,我们在insert之前增加其他方法,这里次序先后是用户灵活指定的 public void newMethod() { otherMethod(); work.insert(); } public void otherMethod() { ListIterator listIterator = others.listIterator(); while (listIterator.hasNext()) { System.out.println(((String)(listIterator.next())) + " 正在进行"); }}} Work squarePeg = new SquarePeg(); Work decorator = new Decorator(squarePeg); decorator.insert(); 2017/9/12
实际上Java 的I/O API就是使用Decorator实现的,I/O变种很多,如果都采取继承方法,将会产生很多子类,显然相当繁琐. 上面调用类似我们读取文件时的调用: FileReader fr = new FileReader(filename); BufferedReader br = new BufferedReader(fr); 实际上Java 的I/O API就是使用Decorator实现的,I/O变种很多,如果都采取继承方法,将会产生很多子类,显然相当繁琐. 2017/9/12
小结 2017/9/12 在Java中有数据传输的地方都用到I/O流(通常是文件,网络,内存和标准输入输出等)。 InputStream 和OutputStream是所有字节流的祖先(只有RandomAccessFile类是一个例外),read和write是它们最基本的方法,读写单位是字节。 Reader 和Writer是所有字符流的祖先,read和write是它们最基本的方法,读写单位是字符。 在众多的流对象中,并不是每一种都单独使用,其中过滤流的子类在数据送出去之前做必要的处理。 2017/9/12
小结 File, File(Input/Output)Stream, RandomAccessFile是处理本地文件的类。 Data(Input/Output)Stream是一个过滤流的子类,借此可以读写各种基本数据,在文件和网络中经常使用。如: readByte, writeBoolean等。 Buffered(Input/Output)Stream的作用是在数据送到目的之前先缓存,达到一定数量时再送到目的,已减少阻塞次数。 Piped(Input/Output)Stream适合与一个处理的输出作为另一个处理的输入的情况。 2017/9/12