470 likes | 612 Views
第十章 输入 / 输出处理. 输入输出概述. 输入 / 输出处理: 从键盘读取数据; 向屏幕中输出数据; 从文件中读或者向文件中写数据 在一个网络连接上进行读写操作等。 在 Java 中,把这些不同类型的输入、输出抽象为 流 ( Stream ) ,用统一的接口来表示,从而使程序设计简单明了。. 输入流和输出流. 流是程序和外界进行数据交换的通道 输入流 (InputStream) 程序通过输入流从数据源读取数据 输出流 (OutputStream) 通过输出流向目的地写数据。. java.io 包.
E N D
输入输出概述 • 输入/输出处理: • 从键盘读取数据; • 向屏幕中输出数据; • 从文件中读或者向文件中写数据 • 在一个网络连接上进行读写操作等。 • 在Java中,把这些不同类型的输入、输出抽象为流(Stream),用统一的接口来表示,从而使程序设计简单明了。
输入流和输出流 • 流是程序和外界进行数据交换的通道 • 输入流(InputStream) • 程序通过输入流从数据源读取数据 • 输出流(OutputStream) • 通过输出流向目的地写数据。
java.io包 • 在Java开发环境中,主要是由包java.io中提供的一系列的类和接口来实现输入/输出处理。 • 标准输入/输出(System.out和System.in)处理则是由包java.lang中提供的类来处理的,但这些类又都是从包java.io中的类继承而来。
字节流和字符流 • 输入输出流的类型 • 字节输入/输出流:以字节为读写单位 • 字符输入/输出流:以字符为读写单位
InputStream ByteArrayInputStream FileInputStream FilterInputStream BufferedInputStream DataInputStream PushbackInputStream ObjectInputStream PipedInputStream SequenceInputStream OutputStream ByteArrayOutputStream FileOutputStream FilterOutputStream BufferedOutputStream DataOutputStream PrintStream ObjectOutputStream PipedOutputStream 字节流 • InputStream类是所有字节输入流的父类 • OutputStream类是所有字节输出流的父类
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() //当完成读操作后,应该关闭输入流。
InputStream类的方法(2) • skip():跳过流中若干字节数 • available():返回流中可用字节数 • mark():在流中标记一个位置 • reset():返回标记过得位置 • markSupport():是否支持标记和复位操作
OutputStream类的方法 • OutputStream类是所有字节输出流的父类,它是一个抽象类,不能被实例化。它提供了一系列和写数据有关的方法。 void write(int), //向输出流写一个字节数据。 void write(byte[] b) //向输出流写一个字节数组的数据 void close() //当完成写操作后,应该关闭输出流。 void flush() OutputStream类本身的flush()方法不执行任何操作,它的一些带有缓冲区的子类(比如BufferedOutputStream和PrintStream类)覆盖了flush()方法。通过带缓冲区的输出流写数据时,数据先保存在缓冲区中,积累到一定程度才会真正写到输出流中。缓冲区通常用字节数组实现,实际上是指一块内存空间。flush()方法强制把缓冲区内的数据写到输出流中。
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); } }
字节流——文件流 • FileInputStream类: • 用来打开一个输入文件,若要打开的文件不存在,则会产生FileNotFoundException异常,这是一个已检查异常,必须捕获或抛出; • FileOutputStream类: • 用来打开一个输出文件,若要打开的文件不存在,则会创建一个新的文件,否则原文件的内容会被新写入的内容所覆盖。 • 在进行文件的读/写操作时,可能会产生已检查异常IOException,必须捕获或抛出(其它的输入/输出流处理时也同样需要进行输入/输出异常处理)。
文件字节流的构造方法 • 文件流的构造方法: • FileInputStream(String name) • 打开一个文件路径名为name的文件作为输入。 • FileOutputStream(String name) • 创建一个文件路径名为name的文件作为输出,文件如果已经存在,则其内容被清空。 • FileOutputStream(String name, boolean append) • 创建一个文件路径名为name的文件作为输出,文件如果已经存在,则在该输出流上输出的内容被接到原有内容之后还是覆盖取决于append的值。
文件流示例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); } }
文件流示例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
文件流示例3 功能:将字符串写入文件 import java.io.*; public class FileWriterSample{ public static void main(String args[]) { try { FileOutputStream fileOut = new FileOutputStream(“E:\\out.txt"); fileOut.write(“你好”.getBytes()); //调用String.getByte()方法返回字符串数组 fileOut.close(); } catch(FileNotFoundException e) { } catch(IOException e) { } } } 演示FileWriterSample.java
字节流—过滤流 • FilterInputStream和FilterOutputStream: • 用于扩展字节输入/输出流功能的装饰器,它有好几个子类,分别用来扩展字节输入/输出流的某一种功能 • 要使用过滤流,首先必须把它连接到某个输入/输出流上,通常在构造方法的参数中指定所要连接的流: • FilterInputStream(InputStream in); • FilterOutputStream(OutputStream out);
过滤流子类: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编码的字符串。
过滤流子类:DataOutputStream类 • DataOutputStream:用于写入基本类型数据,如int、float、long、double和boolean等和UTF编码的字符串 • writeByte():写入1个字节到输出流。 • writeLong():写一个long类型的数据到输出流。 • writeFloat():写一个long类型的数据到输出流。 • writeUTF():写入一个用UTF-8编码的字符串。
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
过滤流子类:缓冲流 • 类BufferedInputStream和BufferedOutputStream实现了带缓冲的过滤流,它提供了缓冲机制,把任意的I/O流“捆绑”到缓冲流上,可以提高读写效率。 • 在初始化时,除了要指定所连接的输入输出流之外,还可以指定缓冲区的大小。 • BufferedInputStream(InputStream in[, int size]) • BufferedOutputStream(OutputStream out[, int size])
过滤流子类:缓冲流示例 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(); //强制将尚未填满的缓冲区中的数据送出。 }
过滤流:其它 • PushBackInputStream:它提供了一个方法将刚刚读入的一个或多个字节退回到输入流中去。 • PrintStream:其作用是将Java语言中的不同类型的数据以字符表示形式输出到相应的输出流中去。
字节流——标准流 语言包java.lang中的System类管理标准输入/输出流和错误流。 • System.in • 继承InputStream, • 用于从标准输入设备中获取输入数据(通常是键盘)。 • System.out, • 继承PrintStream,把输出送到缺省的显示设备(通常是控制台)。 • System.err, • 继承PrintStream,把错误信息送到缺省的显示设备(通常是控制台)。 • 每当main方法被执行时,就自动生成上述三个对象。
标准输入输出示例 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
URL输入流(java.net.URL) InputStream is = null; try { URL url= new URL("http://www.javathinker.org/weiqin/sole.htm"); 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
字符输入输出流 • 在JDK1.1之前,java.io包中的流只有普通的字节流(以byte为基本处理单位的流),这种流对于以16位的Unicode码表示的字符流处理很不方便。从JDK1.1开始, java.io包中加入了专门用于字符流处理的类,它们是以Reader和Writer为基础派生的一系列类。 • 同InputStream和OutputStream一样,Reader和Writer也是抽象类,只提供了一系列用于字符流处理的接口。它们的方法与类InputStream和OutputStream类似,只不过其中的参数换成字符或字符数组。
Reader BufferedReader LineNumberReader CharArrayReader FilterReader PushbackReader InputStreamReader FileReader PipedReader StringReader Writer BufferedWriter CharArrayWriter FilterWriter OutputStreamWriter FileWriter PipedWriter StringWriter PrintWriter Reader和Writer类 • Reader:是所有字符输入流的父类 • Writer: 是所有字符输出流的父类。
输入输出字符流的构造 • 默认情况下,如果你构造了一个连接到字符流的Reader和Writer,那么转换规则会对本地平台默认的字符编码和Unicode进行转换。 • 在构造InputStreamReader类和OutputStreamWriter类的实例时,你可以指定输出流或输入流的字符编码。 InputStreamReader reader=new InputStreamReader(new FileInputStream("D:\\test.txt"), "UTF-8" ); char c=(char)reader.read();
关于字符编码 • 系统属性file.encoding表示本地平台的字符编码,,中文系统一般是GBK (参见propertyTester.java) • 字符串的相关方法 String(byte[] bytes, String enc) //按指定的字符编码enc构造字符串 byte[] getBytes(String enc) //获得按指定的字符编码的字节数组
如何获得本地平台的编码类型 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)
字符流——与字节流连用 • InputStreamReader OutputStreamWriter • 用于处理字符流的最基本的类,用来在字节流和字符流之间作为中介。使用这两者进行字符处理时,在构造方法中应指定一定的平台规范,以便把以字节方式表示的流转换为特定平台上的字符表示。 • InputStreamReader(InputStream in); //缺省规范 • InputStreamReader(InputStream in, String enc); //指定规范enc • OutputStreamWriter(OutputStream out); //缺省规范 • OutputStreamWriter(OutputStream out, String enc); //指定规范enc
字节流与字符流连用示例 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
BuffereReader和PrintWriter • BfferedReader • PrintWriter
BufferedReader • BufferedReader • 带有缓冲区,可以先把一批数据读到缓冲区内,接下来的读操作都是从缓冲区内获取数据,避免每次都从数据源读取数据并进行字符编码转换,从而提高读操作的效率。 • 可采用BufferedReader来装饰其他Reader,以提高效率。 • 构造方法: • BufferedReader(Reader in) :参数in指定被装饰的Reader类。 • BufferedReader(Reader in, int sz) :参数in指定被装饰的Reader类,参数sz指定缓冲区的大小,以字符为单位。 • 提供了整行字符处理方法: • public String readLine(): BufferedReader的方法,从输入流中读取一行字符,行结束标志为‘\n’、‘\r’或两者一起。
println(“hello”); 等价于: print(“hello”) print(“\n”) 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类型的数据和换行符
字符流——其它 • CharArrayReader & CharArrayWriter • 对字符数组进行处理 • StringReader & StringWriter • 对字符串进行处理 • FilterReader & FilterWriter • 过滤字符流 • PipedReader & PipedWriter • 管道字符流 • LineNumberReader • 行处理字符输入流
文件类 • File:以文件路径名的形式代表一个文件或目录 • FileDescriptor:代表一个打开文件的文件描述 • FileFilter & FilenameFilter:用于列出满足条件的文件 • File.list(FilenameFilter fnf) • File.listFiles(FileFilter ff) • FileDialog.setFilenameFilter(FilenameFilter fnf) • FileInputStream & FileReader:顺序读文件 • FileOutputStream & FileWriter:顺序写文件 • RandomAccessFile:提供对文件的随机访问支持。
File类 • File类(在java.io包中)提供了若干创建文和处理文件、目录和获取它们基本信息的方法。 • File 类的构造方法: 1. File(String pathname) //pathname为文件或目录的路径 2. File(String parent, String child) 3. File(File parent, String child)
File类的方法 • 查看文件属性: boolean canRead() boolean isFile() long lastModified(): //可强制转化为Date类型 • 创建或删除目录: mkdir(), delete() //若为目录,必须为空目录,才可以删除 • 列出目录下的所有文件: String[] list() • 判断文件是否存在: boolean exists() • 重新命名文件: renameTo()
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\Dir2 test.txt
创建目录和文件示例 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
打印目录和文件示例 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
删除目录或文件示例 /** 删除目录或文件,如果参数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
RandomAccessFile类 • RandomAccessFile类: • 用来随机读取和写入文件 (即可以写入文件中任何一个地方) • 实现了DataInput和DataOutput 接口 • readBoolean(), readByte(), readChar(), readLine()… • writeBoolean(), writeByte(), writeChar(), writeLine()… • 提供了定位文件的方法
RandomAccessFile类的构造方法 • RandomAccessFile(File file, String mode) RandomAccessFile(String name, String mode) • mode 的取值: • “r”只读. 任何写操作都将抛出IOException。 • “rw”读写. 文件不存在时会创建该文件,文件存在时,原文件内容不变,通过写操作改变文件内容。 • “rws”同步读写. 等同于读写,但是任何协操作的内容都被直接写入物理文件,包括文件内容和文件属性。 • “rwd”数据同步读写. 等同于读写,但任何内容写操作都直接写到物理文件。
RandomAccessFile类的方法 • DataInput和DataOutput中的方法 • readInt(), writeDouble()… • int skipBytes(int n):将指针向下移动若干字节 • length():返回文件长度 • long getFilePointer():返回指针当前位置 • void seek(long pos):将指针调到所需位置 • void setLength(long newLength):设定文件长度
RandomTester.java 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:0 Value1:1000 Value2:2000 Value3:3000 Value4:4000 Value5:1234 Value6:6000 Value7:7000 Value8:8000 Value9:9000