第八章 输入输出流
【课前思考】
1. 字节流和字符流的基类各是什么?
2. 什么是对象的串行化?对象串行化的作用是什么?
【学习目标】
本讲主要讲述了java语言中的输入/输出的处理,通过本讲的学习,同学们可以编写更为完善的java程序。
【学习指南】
仔细阅读本章各知识点的内容, 深刻理解 java 语言中输入/输出流的处理方法,掌握处理问题的方法,多练习,多上机。
【难 重 点】
遇到实际问题时,要根据需要正确使用各种输入/输出流,特别是对中文使用适当的字符输入流。
正确使用对象串行化的方法。
处理字符流时,其构造方法的参数是一个字节流。
对象串行化的概念。
【知 识 点】
I/O 流概述
文件处理
过滤流
字符流的处理
对象的串行化
其它常用的流
【内 容】
第一节 数据流的基本概念
理解数据流
流一般分为输入流(Input Stream)和输出流(Output Stream)两类,但这种划分并不是绝对的。比如一个文件,当向其中写数据时,它就是一个输出流;当从其中读取数据时,它就是一个输入流。当然,键盘只是一个数人流,而屏幕则只是一个输出流。
Java的标准数据流
标准输入输出指在字符方式下(如DOS),程序与系统进行交互的方式,分为三种:
标准输入studin,对象是键盘。
标准输出stdout,对象是屏幕。
标准错误输出stderr,对象也是屏幕。
例 8.1 从键盘输入字符。
本例用System.in.read(buffer)从键盘输入一行字符,存储在缓冲区buffer中,count保存实际读入的字节个数,再以整数和字符两种方式输出buffer中的值。Read方法在java.io包中,而且要抛出IOException异常。程序如下:
import java.io.*;
public class Input1
{
public static void main(String args[]) throws IOException
{
System.out.println("Input: ");
byte buffer[] = new byte[512]; //输入缓冲区
int count = System.in.read(buffer); //读取标准输入流
System.out.println("Output: ");
for (int i=0;i<COUNT;I++) 输出buffer元素值
{
System.out.print(" "+buffer[i]);
}
System.out.println();
for (int i=0;i<COUNT;I++) 按字符方式输出buffer
{
System.out.print((char) buffer[i]);
}
System.out.println("count = "+ count); //buffer实际长度
}
}
程序中,main方法采用throws子句抛出IOException异常交由系统处理。
Java.io包中的数据流及文件类
字节流:
从InputStream和OutputStream派生出来的一系列类。这类流以字节(byte)为基本处理单位。
InputStream、OutputStream
◇ FileInputStream、FileOutputStream
◇ PipedInputStream、PipedOutputStream
◇ ByteArrayInputStream、ByteArrayOutputStream
◇ FilterInputStream、FilterOutputStream
◇ DataInputStream、DataOutputStream
◇ BufferedInputStream、BufferedOutputStream
字符流:
从Reader和Writer派生出的一系列类,这类流以16位的Unicode码表示的字符为基本处理单位
Reader、Writer
◇ InputStreamReader、OutputStreamWriter
◇ FileReader、FileWriter
◇ CharArrayReader、CharArrayWriter
◇ PipedReader、PipedWriter
◇ FilterReader、FilterWriter
◇ BufferedReader、BufferedWriter
◇ StringReader、StringWriter
第二节 字节流初步
InputStream 和OutputStream
read():从流中读入数据
skip():跳过流中若干字节数
available():返回流中可用字节数
mark():在流中标记一个位置
reset():返回标记过得位置
markSupport():是否支持标记和复位操作
close():关闭流
int read()
从输入流中读一个字节,形成一个0~255之间的整数返回(是一个抽象方法)。
int read(byte b[])
读多个字节到数组中。
int read(byte b[], int off, int len)
write(int b)
将一个整数输出到流中(只输出低位字节,抽象)
write(byte b[])
将字节数组中的数据输出到流中
write(byte b[], int off, int len)
将数组b中从off指定的位置开始,长度为len的数据输出到流中
flush():刷空输出流,并将缓冲区中的数据强制送出
close():关闭流
从输入流中读取长度为len的数据,写入数组b中从索引off开始的位置,并返回读取得字节数。
进行I/O操作时可能会产生I/O例外,属于非运行时例外,应该在程序中处理。如:型FileNotFoundException, EOFException, IOException
例 8.2 打开文件。
本例以FileInputStream的read(buffer)方法,每次从源程序文件OpenFile.java中读取512个字节,存储在缓冲区buffer中,再将以buffer中的值构造的字符串new String(buffer)显示在屏幕上。程序如下:
import java.io.*;
public class OpenFile
{
public static void main(String args[]) throws IOException
{
try
{ //创建文件输入流对象
FileInputStream rf = new FileInputStream("OpenFile.java");
int n=512;
byte buffer[] = new byte[n];
while ((rf.read(buffer,0,n)!=-1) && (n>0)) //读取输入流
{
System.out.print(new String(buffer));
}
System.out.println();
rf.close(); //关闭输入流
}
catch (IOException ioe)
{
System.out.println(ioe);
}
catch (Exception e)
{
System.out.println(e);
}
}
}
例 8.3 写入文件。
本例用System.in.read(buffer)从键盘输入一行字符,存储在缓冲区buffer中,再以FileOutStream的write(buffer)方法,将buffer中内容写入文件Write1.txt中,程序如下:
import java.io.*;
public class Write1
{
public static void main(String args[])
{
try
{
System.out.print("Input: ");
int count,n=512;
byte buffer[] = new byte[n];
count = System.in.read(buffer); //读取标准输入流
FileOutputStream wf = new FileOutputStream("Write1.txt");
//创建文件输出流对象
wf.write(buffer,0,count); //写入输出流
wf.close(); //关闭输出流
System.out.println("Save to Write1.txt!");
}
catch (IOException ioe)
{
System.out.println(ioe);
}
catch (Exception e)
{
System.out.println(e);
}
}
}
第三节 文件操作
File类
File类声明如下:
public class File ectends Object implements Serializable,Comparable
构造方法:
public File(String pathname)
public File(File patent,String chile)
public File(String patent,String child)
文件名的处理
String getName( ); //得到一个文件的名称(不包括路径)
String getPath( ); //得到一个文件的路径名
String getAbsolutePath( );//得到一个文件的绝对路径名
String getParent( ); //得到一个文件的上一级目录名
String renameTo(File newName); //将当前文件名更名为给定文件的完整路径
文件属性测试
boolean exists( ); //测试当前File对象所指示的文件是否存在
boolean canWrite( );//测试当前文件是否可写
boolean canRead( );//测试当前文件是否可读
boolean isFile( ); //测试当前文件是否是文件(不是目录)
boolean isDirectory( ); //测试当前文件是否是目录
普通文件信息和工具
long lastModified( );//得到文件最近一次修改的时间
long length( ); //得到文件的长度,以字节为单位
boolean delete( ); //删除当前文件
目录操作
boolean mkdir( ); //根据当前对象生成一个由该对象指定的路径
String list( ); //列出当前目录下的文件
例 8.4 自动更新文件。
本例使用File类对象对指定文件进行自动更新的操作。程序如下:
import java.io.*;
import java.util.Date;
import java.text.SimpleDateFormat;
public class UpdateFile
{
public static void main(String args[]) throws IOException
{
String fname = "Write1.txt"; //待复制的文件名
String childdir = "backup"; //子目录名
new UpdateFile().update(fname,childdir);
}
public void update(String fname,String childdir) throws IOException
{
File f1,f2,child;
f1 = new File(fname); //当前目录中创建文件对象f1
child = new File(childdir); //当前目录中创建文件对象child
if (f1.exists())
{
if (!child.exists()) //child不存在时创建子目录
child.mkdir();
f2 = new File(child,fname); //在子目录child中创建文件f2
if (!f2.exists() || //f2不存在时或存在但日期较早时
f2.exists()&&(f1.lastModified() > f2.lastModified()))
copy(f1,f2); //复制
getinfo(f1);
getinfo(child);
}
else
System.out.println(f1.getName()+" file not found!");
}
public void copy(File f1,File f2) throws IOException
{ //创建文件输入流对象
FileInputStream rf = new FileInputStream(f1);
FileOutputStream wf = new FileOutputStream(f2);
//创建文件输出流对象
int count,n=512;
byte buffer[] = new byte[n];
count = rf.read(buffer,0,n); //读取输入流
while (count != -1)
{
wf.write(buffer,0,count); //写入输出流
count = rf.read(buffer,0,n);
}
System.out.println("CopyFile "+f2.getName()+" !");
rf.close(); //关闭输入流
wf.close(); //关闭输出流
}
public static void getinfo(File f1) throws IOException
{
SimpleDateFormat sdf;
sdf= new SimpleDateFormat("yyyy年MM月dd日hh时mm分");
if (f1.isFile())
System.out.println("<FILE>\t"+f1.getAbsolutePath()+"\t"+
f1.length()+"\t"+sdf.format(new Date(f1.lastModified())));
else
{
System.out.println("