0
点赞
收藏
分享

微信扫一扫

JavaSE_输入输出

孟祥忠诗歌 2022-03-23 阅读 79
java

第五章 输入输出

  • 异常的基本概念
又称为例外,是特殊的运行错误对象
Java中声明了很多异常类,每个异常类都代表了一种运行错误,类中包含了该运行错误的信息处理错误的方法。每当Java程序运行中出现错误有一个异常类与之相对应时,系统都会产生一个相应的该异常类的对象,即产生一个异常。
  • 常见异常

在这里插入图片描述

  • 捕获异常语法
说明:
▫ try 语句 
 其后跟随可能产生异常的代码块。
▫ catch语句 
 其后跟随异常处理语句,通常都要用到两个方法: 
 getMessage() – 返回一个字符串,对发生的异常进行描述。
 printStackTrace() – 给出方法的调用序列,一直到异常的产生位置 。
▫ finally语句 
 不论在try代码段是否产生异常,finally 后的程序代码段都会被执行。通常在这里释放内 存以外的其他资源。
• 注意事项 ▫ 如果并列有多个catch语句捕获多个异常,则一般的异常类型放在后面,特殊的放在前面。 
try { throw new ArithmeticException(); } 
catch(ArithmeticException ae){ System.out.println(ae); } 
  • 声明自己的异常类
• 自定义的所有异常类都必须是Exception的子类
• 声明语法如下
public class MyExceptionName extends SuperclassOfMyException {
public MyExceptionName() {
super("Some string explaining the exception");
}
} 
  • I/O (Input/Output)流
  • 面向字符
面向字符的抽象流类——ReaderWriter
• java.io包中所有字符流的抽象超类。
• Reader提供了输入字符的API。
• Writer提供了输出字符的API。
• 它们的子类又可分为两大类
▫ 节点流:从数据源读入数据或往目的地写出数据;(下面阴影部分)
▫ 处理流:对数据执行某种处理。(非阴影部分)
• 多数程序使用这两个抽象类的一系列子类来读入/写出文本信息
▫ 例如FileReader/FileWriter用来读/写文本文件。
  • 面向字节
    在这里插入图片描述
面向字节的流—InputStreamOutputStream
数据源或目标中含有非字符数据,必须用字节流来输入/输出
• 通常被用来读写诸如图片、声音之类的二进制数据
• 绝大多数数据是被存储为二进制文件的,通常二进制文件要比含有相同数据量的文本文件小得多

System类的静态成员变量
▫ System.in: InputStream类型的,代表标准输入流,默认状态对应于键盘输入。
▫ System.out:PrintStream类型的,代表标准输出流,默认状态对应于显示器输出。
▫ System.err:PrintStream类型的,代表标准错误信息输出流,默认状态对应于显示器输出。
• setIn(InputStream): 设置标准输入流
• setOut(PrintStream):设置标准输出流
• setErr(PrintStream):设置标准错误输出流

按类型输入/输出数据-printf和Scanner
System.out.printf(%-12s is %2d long, name, l);
System.out.printf(“value = %2.2F, value);  # %n 是平台无关的换行标志。
Scanner s = new Scanner(System.in);
int n = s.nextInt();
▫ 还有下列方法:nextByte(),nextDouble(),nextFloat,nextInt(),nextLine(),nextLong(),nextShort()
import java.io.*;
public class Redirecting {
public static void main(String[] args) throws IOException {
BufferedInputStream in = new BufferedInputStream(new FileInputStream( "Redirecting.java"));
PrintStream out = new PrintStream( new BufferedOutputStream( new FileOutputStream("test.out")));
System.setIn(in); System.setOut(out); System.setErr(out);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s;
while((s = br.readLine()) != null) System.out.println(s);
in.close();
out.close();
}
} 
  • I/O异常
多数IO方法在遇到错误时会抛出异常,因此调用这些方法时必须
▫ 在方法头声明抛出IOException异常;
▫ 或者在try块中执行IO,然后在catch块中捕获IOException异常。
  • FileWriter创建文件并写入若干行文本 (面向字符)
#通过FileWriter流创建一个文本文件,并写入若干行文本。
import java.io.*;
class FileWriterTester {
public static void main ( String[] args ) throws IOException {
//main方法中声明抛出IO异常
String fileName = "C:\\Hello.txt";
FileWriter writer = new FileWriter( fileName );
writer.write( "Hello!\n");
writer.write( "This is my first text file,\n" );
writer.write( "You can see how this is done.\n" );
writer.write("输入一行中文也可以\n");
writer.close();
}
}
#使用这个类,换行有些问题,此外每次运行都会删除旧文件生成新文件。
#演示了捕获和处理I/O异常
import java.io.*;
class FileWriterTester {
public static void main ( String[] args ) {
String fileName = "c:\\Hello.txt" ;
try { //将所有IO操作放入try块中
FileWriter writer = new FileWriter( fileName ,true );
writer.write( "Hello!\n");
writer.write( "This is my first text file,\n" );
writer.write( "You can see how this is done. \n" );
writer.write("输入一行中文也可以\n");
writer.close();
}
catch ( IOException iox) { System.out.println("Problem writing" + fileName ); }
}
}
#运行此程序,会发现在原文件内容后面又追加了重复的内容,这就是将构
造方法的第二个参数设为true的效果。
#如果将文件属性改为只读属性,再运行本程序,就会出现IO错误,程序将
转入catch块中,给出出错信息。
  • BufferedWriter类
#如果需要写入的内容很多,就应该使用更为高效的缓冲器流类BufferedWriter。
#FileWriterBufferedWriter类都用于输出字符流,包含的方法几乎完全一样,但BufferedWriter多提供了一个newLine()方法用于换行。
import java.io.*;
class BufferedWriterTester {
public static void main ( String[] args ) throws IOException {
String fileName = "C:/newHello.txt" ;
BufferedWriter out = new BufferedWriter(new FileWriter( fileName ) );
out.write( "Hello!" );
out.newLine() ;
out.write( "This is another text file using BufferedWriter," );
out.newLine(); ;
out.write( "So I can use a common way to start a newline" );
out.close();
}
}
  • Reader 类、FileReader 类、BufferedReader类和readLine() 、文本文件复制
#同写的操作方法
import java.io.*;
class BufferedReaderTester {
public static void main ( String[] args ) {
String fileName = "C:/Hello.txt" , line;
try {
BufferedReader in = new BufferedReader(new FileReader( fileName ) );
line = in.readLine(); //读取一行内容
while ( line != null ) {
System.out.println( line ); line = in.readLine();
}
in.close();
}
catch ( IOException iox ) { System.out.println("Problem reading " + fileName ); }
}
}
#运行该程序,屏幕上将逐行显示出Hello.txt文件中的内容。
 FileReader对象:创建后将打开文件,如果文件不存在,会抛出一个IOException
 BufferedReader类的readLine()方法:从一个面向字符的输入流中读取一行文本。如果其中
不再有数据,返回null
 Reader类的read()方法:也可用来判别文件结束。该方法返回的一个表示某个字符的int型整
数,如果读到文件末尾,返回 -1。据此,可修改本例中的读文件部分:
int c;
while((c=in.read())!= -1) System.out.print((char)c);
 close()方法:为了操作系统可以更为有效地利用有限的资源,应该在读取完毕后,调用该方
法
  • 文件复制
#指定源文件和目标文件名,将源文件的内容复制到目标文件。调用方式为:
java FileCopy sourceFile destinationFile

#CopyMakerprivate boolean openFiles()private boolean copyFiles()private boolean closeFiles()public boolean copy(String src, String dst )
#FileCopymain()

import java.io.*;
class CopyMaker {
String sourceName, destName;
BufferedReader source;
BufferedWriter dest;
String line;
private boolean openFiles() {
try {
source = new BufferedReader(new FileReader( sourceName ));
}
catch ( IOException iox ) {
System.out.println("Problem opening " + sourceName );
return false;
}
try {
dest = new BufferedWriter(new FileWriter( destName ));
}
catch ( IOException iox )
{
System.out.println("Problem opening " + destName );
return false;
}
return true;
} 
private boolean copyFiles() {
try {
line = source.readLine();
while ( line != null ) {
dest.write(line);
dest.newLine();
line = source.readLine();
}
}
catch ( IOException iox ) {
System.out.println("Problem reading or writing" );
return false;
}
return true;
}
private boolean closeFiles() {
boolean retVal=true;
try { source.close(); }
catch ( IOException iox ) {
System.out.println("Problem closing " + sourceName );
retVal = false;
}
try { dest.close(); }
catch ( IOException iox ) {
System.out.println("Problem closing " + destName );
retVal = false;
}
return retVal;
}
public boolean copy(String src, String dst ) {
sourceName = src ;
destName = dst ;
return openFiles() && copyFiles() && closeFiles();
}
}
public class FileCopy //一个文件中只能有一个公有类
{
public static void main ( String[] args ) {
if ( args.length == 2 ) new CopyMaker().copy(args[0], args[1]);
else System.out.println("Please Enter File names");
}
}
#在命令行方式下执行如下命令:java FileCopy c:/Hello.txt c:/CopyHello.txt
  • 抽象类 OutputStream 、派生类FileOutputStream 、派生类DataOutputStream 写二进制件
名称 说明
public DataOutputStream(outputStream out) 构造函数
protected int written 私有属性,代表当前已写出的字节数
public void flush () 冲刷此数据流,使流内的数据都被写出
public final int size () 返回私有变量written的值,即已经写出的字节
public void write(int b) 向底层输出流输出int变量的低八位。执行后,计数器+1
public final void writeBoolean (boolean b) 写一个布尔数,计数器+1
public final void writeByte(int b) 将int参数的低八位写入,舍弃高24位,计数器+1
public void writeBytes(String s) 每个字符被丢掉高八位写入流中,计数器+字符个数
public final void writeChar(int c) 将16-bit字符写入流中,高位在前,计数器增加2
public void writeDouble(double v) 写双精度数,计数器增加8
public void writeFloat (float f) 写单精度数,计数器增加4
public void writelnt (int I) 写整数,计数器增加4
public void writeLong (long l) 写长整数,计数器增加8
public final void writeShort(int s) 写短整数,计数器增加2
  • DataOutputStream将int写入文件
#将三个int型数字255/0/1写入数据文件data1.dat
import java.io.*;
class FileOutputstreamTester {
public static void main ( String[] args ) {
String fileName = "c:/data1.dat" ;
int value0 = 255, value1 = 0, value2 = -1;
try {
DataOutputStream out = new DataOutputStream(
new FileOutputStream( fileName ) );
out.writeInt( value0 );
out.writeInt( value1 );
out.writeInt( value2 );
out.close();
}
catch ( IOException iox ){
System.out.println("Problem writing " + fileName ); }
}
}
  • BufferedOutputStream类
DataOutputStream out = new DataOutputStream(new BufferedOutputStream( new FileOutputStream( fileName ) ) );
#通过DataOutputStream流向文件中写多种类型的数据,并统计字节数
import java.io.*;
class BufferedOutputStreamTester {
public static void main ( String[] args ) throws IOException {
String fileName = "mixedTypes.dat" ;
DataOutputStream dataOut = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream( fileName ) ) );
dataOut.writeInt( 0 );
System.out.println( dataOut.size() + " bytes have been written.");
dataOut.writeDouble( 31.2 );
System.out.println( dataOut.size() + " bytes have been written.");
dataOut.writeBytes("JAVA");
System.out.println( dataOut.size() + " bytes have been written.");
dataOut.close();
}
}
#运行结果
– 4 bytes have been written
– 12 bytes have been written
– 16 bytes have been written
  • 通过捕获异常控制读取结束
import java.io.*;
class DataInputStreamTester {
public static void main ( String[] args ) {
String fileName = "c:/data1.dat" ; long sum = 0;
try {
DataInputStream instr = new DataInputStream(new BufferedInputStream(
new ileInputStream(fileName)));
try {
while ( true )
sum += instr.readInt();
}
catch ( EOFException eof ) {
System.out.println( "The sum is: " + sum );
instr.close();
}
}
catch ( IOException iox ) {
System.out.println("IO Problems with " + fileName ); }
}
}
}
  • 用字节流读取文本文件
import java.io.*;
public class InputStreamTester {
public static void main(String[] args) throws IOException {
FileInputStream s=new FileInputStream("c:/Hello.txt");
int c;
while ((c = s.read()) != -1) //读取1字节,结束返回-1
System.out.write(c);
s.close();
}
}read()方法读取一个字节,转化为[0 ,255]的之间的一个整数,返回一个int。如果读到
了文件末尾,则返回-1。
– write(int)方法写一个字节的低8位,忽略高24位。


  • 处理压缩文件
压缩流类
• java.util.zip包中提供了一些类,使我们可以以压缩格式对流进行读写
• 都继承自字节流类OutputStreamInputStreamGZIPOutputStreamZipOutputStream
▫ 可分别把数据压缩成GZIP格式和Zip格式
• GZIPInputStreamZipInputStream
▫ 可以分别把压缩成GZIP格式或Zip的数据解压缩恢复原状

#将文本文件“Hello.txt” 压缩为文件“test.gz”,再解压该文件,显示其中内容,并另存为“newHello.txt”
import java.io.*;
import java.util.zip.*;
public class GZIPTester {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("c:/Hello.txt");
GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream("c:/test.gz"));
System.out.println("Writing compressing file from c:/Hello.txt to c:/test.gz");
int c;
while((c = in.read()) != -1) out.write(c); //写压缩文件
in.close();
out.close(); 
System.out.println("Reading file form c:/test.gz to monitor");
BufferedReader in2 = new BufferedReader( new InputStreamReader(new GZIPInputStream(new FileInputStream("c:/test.gz"))));
String s;
while((s = in2.readLine()) != null) System.out.println(s);
in2.close();
System.out.println("Writing decompression to c:/newHello.txt");
GZIPInputStream in3=new GZIPInputStream(new FileInputStream("c:/test.gz"));
FileOutputStream out2=new FileOutputStream("c:/newHello.txt");
while((c=in3.read())!=-1) out2.write(c);
in3.close();
out2.close();
}
}read()方法读取一个字节,转化为[0 ,255]的之间的一个整数,返回一个int。如果读到
了文件末尾,则返回-1。
– write(int)方法写一个字节的低8位,忽略了高24位。
  • Zip文件压缩与解压缩
Zip文件
▫ 可能含有多个文件,所以有多个入口(Entry)
▫ 每个入口用一个ZipEntity对象表示,该对象的getName()方法返回文件的最初名称
• ZipOutputStream
▫ 父类是DeflaterOutputStream
▫ 可以把数据压缩成ZIP格式
• ZipInputStream
▫ 父类是InflaterInputStream
▫ 可以把压缩成ZIP格式的数据解压缩

#从命令行输入若干个文件名,将所有文件压缩为“c:/test.zip”,再从此压缩文件中解压并显示
import java.io.*;
import java.util.*;
import java.util.zip.*;
public class ZipOutputStreamTester {
public static void main(String[] args) throws IOException {
ZipOutputStream out=new ZipOutputStream(new BufferedOutputStream(new FileOutputStream("c:/test.zip")));
for(int i = 0; i < args.length; i++) {
System.out.println("Writing file " + args[i]);
BufferedInputStream in =new BufferedInputStream(new FileInputStream(args[i]));
out.putNextEntry(new ZipEntry(args[i]));
int c;
while((c = in.read()) != -1) out.write(c);
in.close();
}
out.close(); 
System.out.println("Reading file");
ZipInputStream in2 =new ZipInputStream(new BufferedInputStream(new FileInputStream("c:/test.zip")));
ZipEntry ze;
while((ze = in2.getNextEntry()) != null) {
System.out.println("Reading file " + ze.getName());
int x;
while((x = in2.read()) != -1) System.out.write(x);
System.out.println();
}
in2.close();
}
}
– 在命令行输入两个文本文件名后,将生成c:/test.zip文件
– 在屏幕上显示出解压后每个文件的内容
– 在资源管理器窗口中,使用winzip软件可解压缩该文件,恢复出和原来文件相同的两个文本文件
  • 解压缩Zip文件,并恢复其原来路径
import java.util.*;
import java.util.zip.*;
import java.lang.*;
import java.io.*;
class Unzip {
byte doc[]=null; //存储解压缩数据的缓冲字节数组
String Filename=null; //压缩文件名字符串
String UnZipPath=null; //解压缩路径字符串
public Unzip(String filename,String unZipPath) {
this.Filename=filename;
this.UnZipPath=unZipPath;
this.setUnZipPath (this.UnZipPath);
}
public Unzip(String filename) {
this.Filename=new String(filename);
this.UnZipPath=null;
this.setUnZipPath (this.UnZipPath);
}
private void setUnZipPath(String unZipPath) {
if(unZipPath.endsWith("\\"))
this.UnZipPath=new String(unZipPath);
else
this.UnZipPath=new String(unZipPath+"\\");
}
public void doUnZip() {
try {
ZipInputStream zipis=new ZipInputStream(
new FileInputStream(Filename));
ZipEntry fEntry=null;
while((fEntry=zipis.getNextEntry())!=null) {
if (fEntry.isDirectory()) //是路径则创建路径
checkFilePath(UnZipPath+fEntry.getName());
else { //是文件则解压缩文件
String fname=new String(UnZipPath+fEntry.getName());
try{
FileOutputStream out = new FileOutputStream(fname);
doc=new byte[512];
int n;
while ((n = zipis.read(doc,0,512)) != -1)
out.write(doc, 0, n);
out.close();
out=null;
doc=null;
}
catch (Exception ex) { }
}
}
zipis.close(); //关闭输入流
}
catch(IOException ioe) { System.out.println(ioe); }
}
private void checkFilePath(String dirName) throws IOException {
File dir = new File(dirName);
if(!dir.exists())
dir.mkdirs();
}
}
//主类,用于输入参数,生成Unzip类的实例
public class UnZipTester {
public static void main(String [] args) {
String zipFile=args[0]; //第一个参数为zip文件名
String unZipPath=args[1]+"\\"; //第二个参数为指定解压缩路径
Unzip myZip=new Unzip(zipFile,unZipPath);
myZip.doUnZip();
}
}
  • 对象序列化(针对对象进行存储)
ObjectInputStream/ObjectOutputStream类

• 不保存对象的transient和static类型的变量
• 对象要想实现序列化,其所属的类必须实现Serializable接口
FileOutputStream out = new FileOutputStream("theTime");
ObjectOutputStream s = new ObjectOutputStream(out);#ObjectOutputStream是一个处理流类,非节点类
s.writeObject("Today");
s.writeObject(new Date());
s.flush();

FileInputStream in = new FileInputStream("theTime");
ObjectInputStream s = new ObjectInputStream(in);
String today = (String)s.readObject();
Date date = (Date)s.readObject();

Seriealizable
• 空接口,使类的对象可实现序列化
• Serializable 接口的定义
package java.io;
public interface Serializable {
// there's nothing in here!
};
• 实现Serializable接口的语句
public class MyClass implements Serializable {
...
}
• 使用关键字transient可以阻止对象的某些成员被自动写入文件

#创建一个书籍对象,并把它输出到一个文件book.dat中,然后再把该对象读出来,在屏幕上显示对象信息
class Book implements Serializable {
int id;
String name;
String author;
float price;
public Book(int id,String name,String author,float price) {
this.id=id;
this.name=name;
this.author=author;
this.price=price;
}
}
import java.io.*;
public class SerializableTester {
public static void main(String args[]) throws
IOException,ClassNotFoundException {
Book book=new Book(100032,"Java Programming
Skills","Wang Sir",30);
ObjectOutputStream oos=new ObjectOutputStream(
new FileOutputStream("c:/book.dat"));
oos.writeObject(book);
oos.close(); 
book=null;
ObjectInputStream ois=new ObjectInputStream(
new FileInputStream("c:/book.dat"));
book=(Book)ois.readObject();
ois.close();
System.out.println("ID is:"+book.id);
System.out.println("name is:"+book.name);
System.out.println("author is:"+book.author);
System.out.println("price is:"+book.price);
}
}
  • Externalizable接口
API中的说明为
public interface Externalizable extends Serializable
• 其中有两个方法writeExternal()readExternal(),因此实现该接口的类必须实现
这两个方法
• ObjectOutputStreamwriteObject()方法只写入对象的标识,然后调用对象所属
类的writeExternal()//不再使用ObjectInputStream的write()ObjectInputStreamreadObject()方法调用对象所属类的readExternal()//不再使用ObjectInputStream的read():原因因为检测到Externalizable接口
  • 随机文件读取
RandomAccessFile类
• 可跳转到文件的任意位置读/写数据
• 可在随机文件中插入数据,而不破坏该文件的其他数据
• 实现了DataInputDataOutput 接口,可使用普通的读写方法
• 有个位置指示器,指向当前读写处的位置。刚打开文件时,文件指示器指向文件的开
头处。对文件指针显式操作的方法有:
▫ int skipBytes(int n):把文件指针向前移动指定的n个字节
▫ void seek(long):移动文件指针到指定的位置。
▫ long getFilePointer():得到当前的文件指针。
• 在等长记录格式文件的随机读取时有很大的优势,但仅限于操作文件,不能访问其它
IO设备,如网络、内存映像等

• **构造方法**
public RandomAccessFile(File file,String mode)
throws FileNotFoundException
public RandomAccessFile(String name, String mode)
throws FileNotFoundException
• 构造RandomAccessFile对象时,要指出操作:仅读,还是读写
new RandomAccessFile("farrago.txt", "r");
new RandomAccessFile("farrago.txt", "rw");
  • RandomAccessFile类常用API

在这里插入图片描述

#创建一个雇员类,包括姓名、年龄。姓名不超过8个字符,年龄是int类型。每条记录固定为20个字节。使用RandomAccessFile向文件添加、修改、读取雇员信息
import java.io.*;
class Employee {
char name[]={'\u0000','\u0000','\u0000','\u0000',
'\u0000','\u0000','\u0000','\u0000'};
int age;
public Employee(String name,int age) throws Exception {
if(name.toCharArray ().length>8)
System.arraycopy(name.toCharArray(),0,this.name,0,8);
else
System.arraycopy(name.toCharArray(),0,this.name,
0,name.toCharArray().length);
this.age=age;
}
}
public class RandomAccessFileTester {
String Filename;
public RandomAccessFileTester (String Filename) {
this.Filename=Filename;
}
public void writeEmployee(Employee e,int n) throws Exception {
RandomAccessFile ra=new RandomAccessFile(Filename,"rw");
ra.seek(n*20); //将位置指示器移到指定位置上
for(int I=0;I<8;I++) ra.writeChar (e.name[I]);
ra.writeInt(e.age);
ra.close();
}
public void readEmployee(int n) throws Exception {
char buf[]=new char[8];
RandomAccessFile ra=new RandomAccessFile(Filename,"r");
ra.seek(n*20);
for(int I=0;I<8;I++) buf[I]=ra.readChar();
System.out.print("name:");
System.out.println(buf);
System.out.println("age:"+ra.readInt());
ra.close();
}
public static void main(String[] args) throws Exception {
RandomAccessFileTester t=new RandomAccessFileTester ("d:/temp/1.txt");
Employee e1=new Employee("ZhangSantt",23);
Employee e2=new Employee(“李晓珊”,33);
Employee e3=new Employee(“王华”,19);
t.writeEmployee(e1,0);
t.writeEmployee(e3,2);
System.out.println("第一个雇员信息");
t.readEmployee(0);
System.out.println("第三个雇员信息");
t.readEmployee(2);
t.writeEmployee (e2,1);
System.out.println("第二个雇员信息");
t.readEmployee (1);
}
}
举报

相关推荐

0 条评论