Java语言程序设计 第九部分 输入/输出
输入/输出 第一讲 文件和流的概念
文件 文件是用来存储计算机数据的,是计算机软件的重要组成部分。文件可以存放在多种介质中,例如硬盘、U盘和光盘,而且还可以通过网络传输。 内存也可以存储计算机数据,但与存储在硬盘上的文件数据相比,存储在内存中 的数据在计算机关机或掉电时一般就会消失。因此,文件是使在计算机上的工 作得以延续的一种重要媒介。 另外,计算机程序在执行时,要求被处理的数据 必须先加载到内存中。因此,一方面需要将位于内存中的数据保存到文件中, 以便长期使用;另一方面又需要将在文件中的数据加载到内存中,以便计算机 处理。
文件 文件中的数据只是一连串的字节或字符,并没有明显的结构。文件数据的内部结构需要由程序自己定义处理。 文件的逻辑结构 文件的存取方法 流式文件 记录式文件 文件的存取方法 顺序存取 随机存取
流 流是按一定顺序排列的数据的集合。 输入数据时,一个程序打开数据源上的一个流(文件或内存等),然后按顺序输入这个流中的数据,这样的流称为输入流。 输出数据时,一个程序可以打开一个目的地的流,然后按顺序从程序向这个目的地输出数据,这样的流称为输出流。 输入和输出的方向是以程序为基准的,向程序输入数据的流定义为输入流,从程序输出数据的流定义为输出流。通常,将从输入流获取数据称为读数据(read),从程序中将数据输出到输出流中称为写数据(write)。
数据流 流的方向性和读/写操作 流采用缓冲区技术 流的作用(数据传输独立于相关设备)
字节流与字符流 按照Java的输入/输出流的数据类型,流可分为字节流和字符流两类。 字节流是由字节组成的读写以字节为单位进行。在javo.io包中,基本输入流类(InputStream)和基本输出流类(OutputStream)是处理以8位字节为基本单位的字节流类。在对数据流操作时,可以向输出流写入一个字节,或从输入流中读取一个字节。 字符流的输入/输出数据是Unicode字符,当遇到不同的编码时,Java的字符流会自动将其转换成Unicode字符。Reader类和Writer类是专门处理16位字符流的类,其读写以字符为单位进行。
基本流类的继承关系
数据流的基本操作 输入流 输出流 int read() int read(byte[] b) int read(byte[] b,int off,int len) void close() long skip(long l) 输出流 void write(int i) void write(byte[] b) void write(byte[] b,int off,int len) void close() void flush()
Java的标准数据流 Java通过系统类System实现标准输入输出的功能。 System类定义了三个成员变量,分别是: static PrintStream err “标准”错误输出流,对象是屏幕。 static InputStream in “标准”输入流,对象是键盘。 static PrintStream out “标准”输出流,对象是屏幕。 这三个变量都是static成员变量,即类成员变量,所以可以直接使用。 in定义为InputStream类的static成员变量,所以可以直接调用InputStream类提供的输入方法。 out和err定义为PrintStream类的static成员变量,所以可以直接调用PrintStream类提供的输出方法。
import java.io.*; public class Console{ public static void main(String args[]){ boolean done=false; int nr_read=0; byte b[]=new byte[100]; try{ while(!done){ nr_read=System.in.read(b); if(nr_read==-1) done=true; else{ System.out.print("b= "); System.out.write(b,0,nr_read); } }catch(Exception e){e.printStackTrace();} System.exit(0);
import java.io.*; public class Exam9_2{ public static void main(String args[]) throws IOException{ byte b[]=new byte[9]; //定义一个byte类型的数组b,用来做为缓冲区 System.out.println("请输入:"); int nb=System.in.read(b); //取出输入字节数的长度,存放在整型变量nb中 System.out.println("您输入的字符数为:"+nb); for(int i=0;i<=nb-1;i++){ //输出缓冲区元素值 System.out.println(b[i]); } System.out.print("您输入的字符是:"); for(int i=0;i<=nb-1;i++){ //按字符方式输出 System.out.print((char)(b[i]));
节点流和过滤器 节点流 过滤器 读取或写入的数据源是文件、缓冲区、字节数组以及其他类型数据的类。 一个输入流过滤器将与一个已存在的输入流相连接,这样当试图从该输入流过滤器中读取数据时,这些数据实际上是从其所连接的其他输入流中得到的。 更快的速度 更方便(简单)的操作
输入/输出 第二讲 字节流
字节流类 基本输入/输出类InputStream类,OutputStream类都是抽象类,不能实例化,因此在实际应用中并不使用这两个类,而是使用—些基本数据流类,他们都是InputStream类和OutputStream类的子类,在实现其超类方法的同时又定义了特有功能,用于不同的场合。
InputStream类的子类
InputStream类的常用方法 int read( ) int read( byte b[ ] ) 读取一个字节,返回值为所读的字节 int read( byte b[ ] ) 读取多个字节,放置到字节数组b中,通常读取的字节数量为b的长度,返回值为实际读取的字节的数量 int read( byte b[ ], int off, int len ) 读取len个字节,放置到以下标off开始字节数组b中,返回值为实际读取的字节的数量 int available( ) 返回值为流中尚未读取的字节的数量 long skip( long n ) 读指针跳过n个字节不读,返回值为实际跳过的字节数量
InputStream类的常用方法 close( ) void mark( int readlimit ) void reset( ) 流操作完毕后必须关闭 void mark( int readlimit ) 记录当前读指针所在位置,readlimit表示读指针读出readlimit个字节后所标记的指针位置才失效 void reset( ) 把读指针重新指向用mark方法所记录的位置 boolean markSupported( ) 当前的流是否支持读指针的记录功能
OutputStream类的子类
OutputStream类的常用方法 abstract void write(int b) void write(byte[] b) 将指定的字节写入此输出流。 void write(byte[] b) 将 b.length 个字节从指定的字节数组写入此输出流。 void write(byte[] b, int off, int len) 将指定字节数组中从偏移量 off 开始的 len 个字节写入此输出流。 void close() 关闭此输出流并释放与此流有关的所有系统资源。 void flush() 刷新此输出流并强制写出所有缓冲的输出字节。
字节流类的常用子类 BufferedInuputStream类与BufferedOutputStream类 BufferedInuputStream类是InputSteam类的子类,BufferedOutputStream类是OutputStream类的子类。当这两个类的对象被创建时,就产生了一个内部缓冲数组,以提高效率。 利用BufferedInuputStream类创建的对象可以根据需要从连接的输入数据流中一次性读多个字节的数据到内部缓冲数组中,利用BufferedOutputStream类创建的对象可以从连接的输出数据流中一次性向内部缓冲数组中写多个字节的数据。
字节流类的常用子类 BufferedInuputStream类的常用构造方法: BufferedOutputStream类的常用构造方法:: BufferedInputStream(InputStream in) 创建 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。 BufferedInputStream(InputStream in, int size) 创建具有指定缓冲区大小的 BufferedInputStream,并保存其参数,即输入流 in,以便将来使用。 BufferedOutputStream类的常用构造方法:: BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的基础输出流。 BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的基础输出流。
import java.io.*; public class Exam9_3{ void run(){ int num; byte input[]=new byte[256]; //用于字节输入的缓冲数组 BufferedInputStream bin=new BufferedInputStream(System.in); BufferedOutputStream bout=new BufferedOutputStream(System.out); try{ System.out.println("请输入:"); num=bin.read(input); //将键盘输入的字节放入数组input中 System.out.println("您输入的字节个数为:"+num); System.out.println("您输入的内容为:"); bout.write(input,0,num); //将数组input中的所有字节输出 bin.close(); //关闭缓冲字节输入流 bout.close(); //关闭缓冲字节输出流 }catch(IOException e){ System.out.println("I/O错误!"); } public static void main(String args[]){ Exam9_3 ee=new Exam9_3(); ee.run();
字节流类的常用子类 FileInuputStream类与FileOutputStream类 FileInuputStream类的常用构造方法 FileInuputStream类是InputSteam类的子类,FileOutputStream类是OutputStream类的子类。这两个类主要用于文件的输入与输出,创建的对象可以顺序地从本地机上的文件中读数据或写数据。 FileInuputStream类的常用构造方法 FileInputStream(File file) 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。 FileInputStream(String name) 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
字节流类的常用子类 FileOutputStream类的常用构造方法 FileOutputStream(File file) FileOutputStream(File file, boolean append) FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流。 FileOutputStream(String name, boolean append)
import java.io.*; public class Exam9_4{ void run(){ int num; byte input[]=new byte[256]; BufferedInputStream bin=new BufferedInputStream(System.in); try{ System.out.println("请输入:"); num=bin.read(input); FileOutputStream fout=new FileOutputStream("a.txt",true); fout.write(input,0,num); bin.close(); fout.close(); }catch(IOException e){ System.out.println("I/O错误!"); } public static void main(String args[]){ Exam9_4 ee=new Exam9_4(); ee.run();
import java.io.*; public class Exam9_5{ void run(){ byte input[]=new byte[256]; try{ FileInputStream fin=new FileInputStream("a.txt"); System.out.println("文件a.txt的内容为:"); while(fin.read(input)!=-1) { System.out.println(new String(input)); } fin.close(); }catch(IOException e){ System.out.println("I/O错误!"); public static void main(String args[]){ Exam9_5 ee=new Exam9_5(); ee.run();
import java.io.*; public class FileCopy{ public static void main(String[] args) { byte b[]=new byte[10000]; int nr_read=0; try{ FileInputStream fin=new FileInputStream(args[0]); FileOutputStream fout=new FileOutputStream(args[1]); nr_read=fin.read(b);
while(nr_read != -1){ fout.write(b,0,nr_read); nr_read=fin.read(b); } fout.close(); catch(IOException e){ System.err.println(args[1]+"not created"); fin.close();} System.err.println(args[0]+"not exist");}
字节流类的常用子类 DateInuputStream类与DateOutputStream类 有时需要处理的数据不一定是字节数据。如读写int型、float型、double型的数据时,一次需要读写几个字节,需要专门的数据输入输出流来处理。 DateInuputStream类和DateOutputStream类分别实现了java.io包中的DataInput和DataOutput接口,能够读写Java基本类型的数据和Unicode编码格式的字符串。这样,在输入输出数据时就不必关心该数据究竟包含几个字节了。 DateInuputStream类和DateOutputStream类是从过滤流类继承过来的,这两个流的对象均不能独立地实现数据的输入和输出处理,必须与其他输入流和输出流对象一起使用,才能实现不同类型数据的读写。这两个类与FileInputStream类和FileOutputStream类相配合可以完成对格式数据的读写。
字节流类的常用子类 DateInuputStream类的构造方法 DateOutputStream类的构造方法 DataInputStream(InputStream in) 使用指定的基础 InputStream 创建一个 DataInputStream。 DateOutputStream类的构造方法 DataOutputStream(OutputStream out) 创建一个新的数据输出流,将数据写入指定基础输出流。
DataInputStream类的读方法 DataOutputStream类的写方法 数据输入输出流的常用方法 DataInputStream类的读方法 DataOutputStream类的写方法 int read(byte[] b) void write(byte[] b, int off, int len) int read(byte[] b, int off, int len) void write(int b) boolean readBoolean() void writeBoolean(boolean v) byte readByte() void writeByte(int v) char readChar() void writeBytes(String s) double readDouble() void writeChar(int v) float readFloat() void writeChars(String s) void readFully(byte[] b) void writeDouble(double v) void readFully(byte[] b, int off, int len) void writeFloat(float v) int readInt() void writeInt(int v) long readLong() void writeLong(long v) short readShort() void writeShort(int v) String readUTF() void writeUTF(String str)
import java.io.*; public class Exam9_6{ void run(){ try{ FileOutputStream fout=new FileOutputStream("student.dat"); DataOutputStream dout=new DataOutputStream(fout); dout.writeInt(1); dout.writeUTF("李小平"); dout.writeDouble(95); dout.close(); fout.close(); }catch(IOException e){ System.out.println("文件错误!"); } public static void main(String args[]){ Exam9_6 ee=new Exam9_6(); ee.run();
import java.io.*; public class Exam9_7{ public static void main(String args[]){ int no; String name; double score; try{ FileInputStream fin=new FileInputStream("student.dat"); DataInputStream din=new DataInputStream(fin); int i=0; while(i==0){ no=din.readInt(); name=din.readUTF(); score=din.readDouble(); System.out.println(no+"\t"+name+"\t"+score); } din.close(); fin.close(); }catch(EOFException e){ System.out.println("文件结束!"); catch(IOException e){ System.out.println("文件错误!");
输入/输出 第三讲 字符流
Reader类和Writer类 Reader类的常用方法与InputStream类基本相似,Writer类的常用方法与OutputStream类基本相似。它们的主要区别是:InputStream类和OutputStream类操作的是字节,而Reader类和Writer类操作的是字符。 与InputStream 类的子类相同,Reader类的子类重写了不同功能的read()方法,与OutputStream类的子类相同,Writer类的子类重写了不同功能的write()方法。
字符流类的常用子类 BufferedReader类 InputStreamReader类 BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。 BufferedReader(Reader in, int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流。 InputStreamReader类 InputStreamReader类是将字节输入流转换成字符输入流的转换器。 InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。
字符流类的常用子类 BufferWriter类 OutputStreamWriter类 BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。 BufferedWriter(Writer out, int sz) 创建一个使用指定大小输出缓冲区的新缓冲字符输出流。 OutputStreamWriter类 OutputStreamWriter 是字符流通向字节流的桥梁,起到转换器的作用。 OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter。
import java.io.*; public class BufferedConsole{ public static void main(String args[]){ try{ String s=null; boolean done=false; BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out)); while(!done){ s=br.readLine(); if(s==null) done=true; else{ bw.write("s: "+s); bw.newLine(); bw.flush(); } bw.close();br.close(); }catch(Exception e){System.err.println("Error writing output");}
字符流类的常用子类 FileReader类 FileWriter类 FileReader(File file) 在给定File 的情况下创建一个新 FileReader。 FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建FileReader。 FileWriter类 FileWriter(File file) FileWriter(File file, boolean append) FileWriter(String fileName) FileWriter(String fileName, boolean append)
import java.io.*; public class Exam9_9{ public static void main(String args[]) throws IOException{ int n; byte b[]=new byte[256]; System.out.println("请输入:"); System.in.read(b); //通过键盘输入内容 String s1=new String(b); //将字节数组转换为字符串 s1=s1.trim(); //给字符串去空格 BufferedWriter bw=new BufferedWriter(new FileWriter("b.txt")); bw.write(s1,0,s1.length()); System.out.println("已存入文件"); bw.close(); BufferedReader br=new BufferedReader(new FileReader("b.txt")); String s2=br.readLine(); System.out.println("你存入到文件中的内容是:"+s2); br.close(); }
输入/输出 第四讲 文件操作
File类 File类是专门描述文件的各种属性(如文件名、大小、是否只读等),并提供方法操纵文件的路径等的类。 构造方法 File(String pathname) 通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例。 File ff=new File(“myfile.txt”); File(String parent, String child) 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。 File ff=new File(“e:\\myjava”,“myfile.txt”);
File类 常用方法 boolean canRead() 是否只读 boolean canWrite() 是否可写 boolean delete() 删除此抽象路径名表示的文件或目录。 boolean exists() 是否存在。 File getAbsoluteFile() 返回抽象路径名的绝对路径名形式。 String getAbsolutePath() 返回抽象路径名的绝对路径名字符串。 String getName() 返回由此抽象路径名表示的文件或目录的名称。 String getParent() 返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null。
File类 常用方法 String getPath() 将此抽象路径名转换为一个路径名字符串。 boolean isAbsolute() 测试此抽象路径名是否为绝对路径名。 boolean isDirectory() 测试此抽象路径名表示的文件是否是一个目录。 boolean isFile() 测试此抽象路径名表示的文件是否是一个标准文件。 boolean isHidden() 测试此抽象路径名指定的文件是否是一个隐藏文件。 long lastModified() 返回此抽象路径名表示的文件最后一次被修改的时间。 long length() 返回由此抽象路径名表示的文件的长度。
File类 常用方法 boolean mkdir() 创建此抽象路径名指定的目录。 boolean mkdirs() 创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。 boolean renameTo(File dest) 重新命名此抽象路径名表示的文件。 boolean setReadOnly()标记此抽象路径名指定的文件或目录,以便只可对其进行读操作。
import java.io.*; import java.util.*; public class Exam9_10{ void run(){ File fl=new File("a.txt"); System.out.println("路径:"+fl.getAbsoluteFile()); System.out.println("文件大小:"+fl.length()); System.out.println("是否隐藏:"+fl.isHidden()); System.out.println("是否可读:"+fl.canRead()); System.out.println("是否可写:"+fl.canWrite()); System.out.println("最后修改时间:"+new Date(fl.lastModified())); } public static void main(String args[]){ Exam9_10 ee=new Exam9_10(); ee.run();
示例 显示当前目录中文件列表。 FilesList.java
RandomAccessFile类 RandomAccessFile类直接继承自Object类,同时实现了DataInput接口和DataOutput接口。所以RandomAccessFile类既可以作为输入流,又可以作为输出流。 构造方法 RandomAccessFile(File file, String mode) 创建从中读取和向其中写入(可选)的随机存取文件流,该文件由 File 参数指定。 RandomAccessFile(String name, String mode) 创建从中读取和向其中写入的随机存取文件流,该文件具有指定名称。mode是访问方式,r表示读,w表示写,rw表示既可以读又可以写。
RandomAccessFile类 常用方法 void close() 关闭此随机存取文件流。 long length() 返回此文件的长度。 int read() 从此文件中读取一个数据字节。 String readLine() 从此文件读取文本的下一行。 void write(byte[] b) 将 指定字节数组写入到文件。 void write(byte[] b, int off, int len) 将len 个字节写入到文件。 seek(long pos) 设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。 int skipBytes(int n) 跳过输入的 n 个字节以丢弃跳过的字节。 long getFilePointer() 返回此文件中的当前偏移量。
import java.io.*; import java.util.*; public class AppendFile{ public static void main(String args[]) { try{ File logfile=new File(args[0]); if(logfile.exists()){ RandomAccessFile raf=new RandomAccessFile(logfile,"rw"); raf.seek(raf.length()); for(int i=0;i<10;i++) raf.writeBytes("Write "+new Date()+ "\r\n"); raf.close(); } }catch(IOException e){e.printStackTrace();}
可持续化 持续化的概念 如何持续化 DataInputStream、DataOutputStream 存入的是对象,取出的也是对象 实现Serializable接口 对象数据被保存下来 不希望被持续化的对象数据需要有transient修饰