Java IO(二)
-----------------
IO操作实例
实例操作一:加法操作
要求从键盘上输入两个数字,之后完成两个整数的加法操作。因为从键盘接收过来的内容全部是采用字符串的形式存放的,所以此时直接将符串通过包装类Integer将字符串变为基本数据类型。
实现:首先构造专门接收数据的InputData类
import java.io.* ;
import java.util.* ;
import java.text.* ;
public class InputData{
privateBufferedReader buf = null ;
publicInputData(){// 只要输入数据就要使用此语句
this.buf= new BufferedReader(new InputStreamReader(System.in)) ;
}
publicString getString(String info){ // 得到字符串信息
Stringtemp = null ;
System.out.print(info); // 打印提示信息
try{
temp= this.buf.readLine() ; // 接收数据
}catch(IOExceptione){
e.printStackTrace();
}
returntemp ;
}
publicint getInt(String info,String err){ //得到一个整数的输入数据
inttemp = 0 ;
Stringstr = null ;
booleanflag = true ; // 定义一个标记位
while(flag){
str= this.getString(info) ; // 接收数据
if(str.matches("^\\d+{1}quot;)){ // 判断是否由数字组成
temp= Integer.parseInt(str) ; // 转型
flag= false ; // 结束循环
}else{
System.out.println(err); // 打印错误信息
}
}
returntemp ;
}
}
主类(测试类1):调用InputData完成加法操作:
import java.io.* ;
public class ExecDemo02{
publicstatic void main(String args[]) throws Exception{
inti = 0 ;
intj = 0 ;
InputDatainput = new InputData() ;
i= input.getInt("请输入第一个数字:","输入的数据必须是数字,请重新输入!") ;
j= input.getInt("请输入第二个数字:","输入的数据必须是数字,请重新输入!") ;
System.out.println(i+ " + " + j + " = " + (i + j)) ;
}
};
在开发中可能输入各种类型的数据:整数、小数、字符串、日期,这就要进一步扩充InputData类。
import java.io.* ;
import java.util.* ;
import java.text.* ;
public class InputData{
privateBufferedReader buf = null ;
publicInputData(){// 只要输入数据就要使用此语句
this.buf= new BufferedReader(new InputStreamReader(System.in)) ;
}
publicString getString(String info){ // 得到字符串信息
Stringtemp = null ;
System.out.print(info); // 打印提示信息
try{
temp= this.buf.readLine() ; // 接收数据
}catch(IOExceptione){
e.printStackTrace();
}
returntemp ;
}
publicint getInt(String info,String err){ //得到一个整数的输入数据
inttemp = 0 ;
Stringstr = null ;
booleanflag = true ; // 定义一个标记位
while(flag){
str= this.getString(info) ; // 接收数据
if(str.matches("^\\d+{1}quot;)){ // 判断是否由数字组成
temp= Integer.parseInt(str) ; // 转型
flag= false ; // 结束循环
}else{
System.out.println(err); // 打印错误信息
}
}
returntemp ;
}
publicfloat getFloat(String info,String err){ //得到一个小数的输入数据
floattemp = 0 ;
Stringstr = null ;
booleanflag = true ; // 定义一个标记位
while(flag){
str= this.getString(info) ; // 接收数据
if(str.matches("^\\d+.?\\d+{1}quot;)){ // 判断是否由数字组成
temp= Float.parseFloat(str) ; // 转型
flag= false ; // 结束循环
}else{
System.out.println(err) ; // 打印错误信息
}
}
returntemp ;
}
publicDate getDate(String info,String err){ // 得到一个小数的输入数据
Datetemp = null ;
Stringstr = null ;
booleanflag = true ; // 定义一个标记位
while(flag){
str= this.getString(info) ; // 接收数据
if(str.matches("^\\d{4}-\\d{2}-\\d{2}{1}quot;)){ // 判断是否由数字组成
SimpleDateFormatsdf = new SimpleDateFormat("yyyy-MM-dd") ;
try{
temp= sdf.parse(str) ; // 将字符串变为Date型数据
}catch(Exceptione){e}
flag= false ; // 结束循环
}else{
System.out.println(err); // 打印错误信息
}
}
returntemp ;
}
};
以上InputData类,完成了既可以接收整数,也可以接收小数和日期类型的数据。
测试类2:测试小数:
import java.io.* ;
public class ExecDemo02{
publicstatic void main(String args[]) throws Exception{
floati = 0 ;
floatj = 0 ;
InputDatainput = new InputData() ;
i= input.getFloat("请输入第一个数字:","输入的数据必须是数字,请重新输入!") ;
j= input.getFloat("请输入第二个数字:","输入的数据必须是数字,请重新输入!") ;
System.out.println(i+ " + " + j + " = " + (i + j)) ;
}
};
测试类3,测试日期:
import java.io.* ;
import java.util.* ;
public class TestInput{
publicstatic void main(String args[]) throws Exception{
InputDatainput = new InputData() ;
Dated = input.getDate("请输入日期,格式为(yyyy-mm-dd):","输入的日期格式不正确,请重新输入") ;
System.out.println("日期" + d) ;
}
};
实例操作二:菜单显示
使用IO操作完成一个简单的菜单程序,如下所示:
******Xxx系统****** [1]、增加数据 [2]、删除数据 [3]、修改数据 [4]、查看数据 [0]、系统退出 请选择: |
如果用户输入编号不正确,则要给出错误提示,并等待用户重新选择。
实现:Operate类
public class Operate{
publicstatic void add(){ // 增加操作
System.out.println("**选择的是增加操作") ;
}
publicstatic void delete(){ // 删除操作
System.out.println("**选择的是删除操作") ;
}
publicstatic void update(){ // 更新操作
System.out.println("**选择的是更新操作") ;
}
publicstatic void find(){ // 查看操作
System.out.println("**选择的是查看操作") ;
}
};
Menu类:
public class Menu{
publicMenu(){
while(true){
this.show(); // 无限制调用菜单的显示
}
}
publicvoid show(){
System.out.println("=====Xxx系统 =====") ;
System.out.println(" [1]、增加数据") ;
System.out.println(" [2]、删除数据") ;
System.out.println(" [3]、修改数据") ;
System.out.println(" [4]、查看数据") ;
System.out.println(" [0]、系统退出\n") ;
InputDatainput = new InputData() ;
inti = input.getInt("请选择:","请输入正确的选项!") ;
switch(i){
case1:{
Operate.add(); // 调用增加操作
break;
}
case2:{
Operate.delete(); // 调用删除操作
break;
}
case3:{
Operate.update(); // 调用更新操作
break;
}
case4:{
Operate.find(); // 调用查看操作
break;
}
case0:{
System.exit(1); // 系统退出
break;
}
default:{
System.out.println("请选择正确的操作!") ;
}
}
}
};
测试类:越简单越好
import java.io.* ;
public class ExecDemo03{
publicstatic void main(String args[]) throws Exception{
newMenu() ;
}
};
Scanner类
在JDK1.5之后JAVA提供了专门的输入数据类,此类可以完成BufferedReader类的功能。也可以方便的对输入数据进行验证,此类存放在java.util包中。
实例:使用Scanner接收键盘的输入数据:
import java.util.* ;
public class ScannerDemo02{
publicstatic void main(String args[]){
Scannerscan = new Scanner(System.in) ; // 从键盘接收数据
System.out.print("输入数据:") ;
scan.useDelimiter("\n");
Stringstr = scan.next() ; // 接收数据
System.out.println("输入的数据为:" + str) ;
}
};
实例二:使用Scanner类返回整数或者小数
import java.util.* ;
public class ScannerDemo03{
publicstatic void main(String args[]){
Scannerscan = new Scanner(System.in) ; // 从键盘接收数据
inti = 0 ;
floatf = 0.0f ;
System.out.print("输入整数:") ;
if(scan.hasNextInt()){ // 判断输入的是否是整数
i= scan.nextInt() ; // 接收整数
System.out.println("整数数据:" + i) ;
}else{
System.out.println("输入的不是整数!") ;
}
System.out.print("输入小数:") ;
if(scan.hasNextFloat()){ // 判断输入的是否是小数
f= scan.nextFloat() ; // 接收小数
System.out.println("小数数据:" + f) ;
}else{
System.out.println("输入的不是小数!") ;
}
}
};
Scanner类虽然可以接收各种类型的数据,但对于日期的数据却无法接收,如果想要接收Data类型的数据,则只能通过字符串转型来实现。
实例:接收Date类型的数据
import java.util.* ;
import java.text.* ;
public class ScannerDemo04{
publicstatic void main(String args[]){
Scannerscan = new Scanner(System.in) ; // 从键盘接收数据
Stringstr = null ;
Datedate = null ;
System.out.print("输入日期(yyyy-MM-dd):");
if(scan.hasNext("^\\d{4}-\\d{2}-\\d{2}{1}quot;)){ // 判断
str= scan.next("^\\d{4}-\\d{2}-\\d{2}{1}quot;) ; // 接收
try{
date= new SimpleDateFormat("yyyy-MM-dd").parse(str) ;
}catch(Exceptione){}
}else{
System.out.println("输入的日期格式错误!") ;
}
System.out.println(date);
}
};
实例:利用Scanner读取文件内容
import java.util.* ;
import java.text.* ;
import java.io.* ;
public class ScannerDemo05{
publicstatic void main(String args[]){
Filef = new File("D:" + File.separator + "test.txt") ; // 指定操作文件
Scannerscan = null ;
try{
scan= new Scanner(f) ; // 从键盘接收数据
}catch(Exceptione){}
StringBufferstr = new StringBuffer() ;
while(scan.hasNext()){
str.append(scan.next()).append('\n') ; // 取数据
}
System.out.println("文件内容为:" + str) ;
}
};
数据操作流 DataOutputStream DataInputStream
通常数据输出流会按照一定的格式将数据输出,再通过输入流按照一定格式将数据读入
例如有以下的定单数据
商品名称 | 商品价格 | 商品数量 |
衬衣 | 98.3 | 3 |
手套 | 30.3 | 2 |
围巾 | 50.5 | 1 |
DataOutputStream
DataOutputStream是OutputStream的子类,此类继承了FilterOutputStream类,同时实现了DataOutput接口,在DataOutput接口定义了一系列的写入各种数据的方法。
数据的写入格式:
以上每条数据与数据之间使用”\n”分隔,每条数据中的每个内容之间使用”\t”分隔。每一行数据,通过”\n”完结,每行中的各个数据之间通过”\t”完结。
代码如下:
import java.io.DataOutputStream ;
import java.io.File ;
import java.io.FileOutputStream ;
public class DataOutputStreamDemo{
publicstatic void main(String args[]) throws Exception{ // 所有异常抛出
DataOutputStreamdos = null ; // 声明数据输出流对象
Filef = new File("d:" + File.separator + "order.txt") ; // 文件的保存路径
dos= new DataOutputStream(new FileOutputStream(f)) ; // 实例化数据输出流对象
Stringnames[] = {"衬衣","手套","围巾"}; // 商品名称
floatprices[] = {98.3f,30.3f,50.5f} ; //商品价格
intnums[] = {3,2,1} ; // 商品数量
for(inti=0;i<names.length;i++){ // 循环输出
dos.writeChars(names[i]); // 写入字符串
dos.writeChar('\t'); // 写入分隔符
dos.writeFloat(prices[i]); // 写入价格
dos.writeChar('\t'); // 写入分隔符
dos.writeInt(nums[i]); // 写入数量
dos.writeChar('\n'); // 换行
}
dos.close() ; // 关闭输出流
}
};
使用DataOutputStream写入的数据要使用DataInputStream读取进来。
代码:
import java.io.DataInputStream ;
import java.io.File ;
import java.io.FileInputStream ;
public class DataInputStreamDemo{
publicstatic void main(String args[]) throws Exception{ // 所有异常抛出
DataInputStreamdis = null ; // 声明数据输入流对象
Filef = new File("d:" + File.separator + "order.txt") ; // 文件的保存路径
dis= new DataInputStream(new FileInputStream(f)) ; //实例化数据输入流对象
Stringname = null ; // 接收名称
floatprice = 0.0f ; // 接收价格
intnum = 0 ; // 接收数量
chartemp[] = null ; // 接收商品名称
intlen = 0 ; // 保存读取数据的个数
charc = 0 ; // '\u0000'
try{
while(true){
temp= new char[200] ; // 开辟空间
len= 0 ;
while((c=dis.readChar())!='\t'){ // 接收内容
temp[len]= c ;
len ++ ; // 读取长度加1
}
name= new String(temp,0,len) ; // 将字符数组变为String
price= dis.readFloat() ; // 读取价格
dis.readChar(); // 读取\t
num= dis.readInt() ; // 读取int
dis.readChar(); // 读取\n
System.out.printf("名称:%s;价格:%5.2f;数量:%d\n",name,price,num);
}
}catch(Exceptione){}
dis.close();
}
};
以上代码中 使用了抛出异常的方式来跳出while(true)循环 在这里感谢李叶、黄伟龙同学的指导。
合并流
合并流的主要功能是将两个文件的内容合并成一个文件即:a.txt + b.txt = ab.txt
合并流利用SequenceInputStream类来实现。
代码:
import java.io.File ;
import java.io.SequenceInputStream ;
import java.io.FileInputStream ;
import java.io.InputStream ;
import java.io.FileOutputStream ;
import java.io.OutputStream ;
public class SequenceDemo{
publicstatic void main(String args[]) throws Exception { // 所有异常抛出
InputStreamis1 = null ; // 输入流1
InputStreamis2 = null ; // 输入流1
OutputStreamos = null ; // 输出流
SequenceInputStreamsis = null ; // 合并流
is1= new FileInputStream("d:" + File.separator + "a.txt") ;
is2= new FileInputStream("d:" + File.separator + "b.txt") ;
os = new FileOutputStream("d:"+ File.separator + "ab.txt") ;
sis= new SequenceInputStream(is1,is2) ; //实例化合并流
inttemp = 0 ; // 接收内容
while((temp=sis.read())!=-1){ // 循环输出
os.write(temp); // 保存内容
}
sis.close(); // 关闭合并流
is1.close(); // 关闭输入流1`
is2.close(); // 关闭输入流2
os.close(); // 关闭输出流
}
};
压缩流
在日常的使用中经常会使用到WinRAR或WinZIP这样的压缩文件,通过这些软件可以把一个很大的文件进行压缩以方便传输。在JAVA中为了减少传输时的数据量也提供了专门的压缩流,可以将文件或文件压缩成ZIP、JAR、GZIP等文件形式。
压缩流的实现
ZIP是一种较为常见的压缩形式,在JAVA中要想实现ZIP的压缩需要导入java.util.zip包。可以使用此包中的ZipFIle、ZipOutputStream、ZipInputStream、ZipEntry几个类完成操作。
ZipEntry:在每个压缩文件中都会存在多个子文件,那么这每一个子文件在JAVA中就使用ZipEntry表示。
ZipOutputStream:如果要完成一个文件或文件夹的压缩,要使用ZipOutputStream类完成。ZipOutputStream是OutputStream的子类。
实现代码:压缩一个文件
import java.io.File ;
import java.io.FileInputStream ;
import java.io.InputStream ;
import java.util.zip.ZipEntry ;
import java.util.zip.ZipOutputStream ;
import java.io.FileOutputStream ;
public class ZipOutputStreamDemo01{
publicstatic void main(String args[]) throws Exception{ // 所有异常抛出
Filefile = new File("d:" + File.separator + "hm.txt") ; // 定义要压缩的文件
FilezipFile = new File("d:" + File.separator + "hm.zip") ; // 定义压缩文件名称
InputStreaminput = new FileInputStream(file) ; // 定义文件的输入流
ZipOutputStreamzipOut = null ; // 声明压缩流对象
zipOut= new ZipOutputStream(new FileOutputStream(zipFile)) ;
zipOut.putNextEntry(newZipEntry(file.getName())) ; // 设置ZipEntry对象
zipOut.setComment("www"); // 设置注释
inttemp = 0 ;
while((temp=input.read())!=-1){ // 读取内容
zipOut.write(temp); // 压缩输出
}
input.close(); // 关闭输入流
zipOut.close(); // 关闭输出流
}
};
实现代码:压缩一个文件夹
import java.io.File ;
import java.io.FileInputStream ;
import java.io.InputStream ;
import java.util.zip.ZipEntry ;
import java.util.zip.ZipOutputStream ;
import java.io.FileOutputStream ;
public class ZipOutputStreamDemo02{
publicstatic void main(String args[]) throws Exception{ // 所有异常抛出
Filefile = new File("d:" + File.separator + "hm") ; // 定义要压缩的文件夹
FilezipFile = new File("d:" + File.separator + "hmdir.zip") ; // 定义压缩文件名称
InputStreaminput = null ; // 定义文件输入流
ZipOutputStreamzipOut = null ; // 声明压缩流对象
zipOut= new ZipOutputStream(new FileOutputStream(zipFile)) ;
zipOut.setComment("www.java.cn") ; // 设置注释
inttemp = 0 ;
if(file.isDirectory()){ // 判断是否是文件夹
Filelists[] = file.listFiles() ; // 列出全部文件
for(inti=0;i<lists.length;i++){
input= new FileInputStream(lists[i]) ; // 定义文件的输入流
zipOut.putNextEntry(newZipEntry(file.getName()
+File.separator+lists[i].getName())); // 设置ZipEntry对象
while((temp=input.read())!=-1){ // 读取内容
zipOut.write(temp); // 压缩输出
}
input.close(); // 关闭输入流
}
}
zipOut.close(); // 关闭输出流
}
};
ZipFile:是一个专门表示压缩文件的类
在JAVA中,每一个压缩文件都可以使用ZipFile表示,还可以使用ZipFile根据压缩后的文件名称找到每一个压缩文件中的ZipEntry并将其进行解压缩操作。ZipFile在实例化的时候必须接收File类的实例,此File类的实例是指向一个压缩的*.zip文件。
实例:通过ZipFile文件,为hm.zip进行解压缩操作
import java.io.File ;
import java.io.FileInputStream ;
import java.io.InputStream ;
import java.io.OutputStream ;
import java.util.zip.ZipEntry ;
import java.util.zip.ZipOutputStream ;
import java.util.zip.ZipFile ;
import java.io.FileOutputStream ;
public class ZipFileDemo02{
publicstatic void main(String args[]) throws Exception{ // 所有异常抛出
Filefile = new File("d:" + File.separator + "hm.zip") ; // 找到压缩文件
FileoutputFile = new File("d:" + File.separator + "hm_unzip.txt"); // 定义解压缩的文件名称
ZipFilezipFile = new ZipFile(file) ; // 实例化ZipFile对象
ZipEntryentry = zipFile.getEntry("hm.txt") ; //得到一个压缩实体
OutputStreamout = new FileOutputStream(outputFile) ; // 实例化输出流
InputStreaminput = zipFile.getInputStream(entry) ; //得到一个压缩实体的输入流
inttemp = 0 ;
while((temp=input.read())!=-1){
out.write(temp);
}
input.close(); // 关闭输入流
out.close(); // 关闭输出流
}
};
以上操作中,有一个问题,必须知道压缩文件中的每一个压缩实体的名称才可以进行解压缩操作。
ZipInputStream类
可以不用输入实体名称就可以得到每一个ZipEntry对象
实例:解压缩文件夹
import java.io.File ;
import java.io.OutputStream ;
import java.io.InputStream ;
import java.util.zip.ZipEntry ;
import java.util.zip.ZipFile ;
import java.util.zip.ZipInputStream ;
import java.io.FileInputStream ;
import java.io.FileOutputStream ;
public class ZipInputStreamDemo02{
publicstatic void main(String args[]) throws Exception{ // 所有异常抛出
Filefile = new File("d:" + File.separator + "hmdir.zip") ; // 定义压缩文件名称
FileoutFile = null ; // 输出文件的时候要有文件夹的操作
ZipFilezipFile = new ZipFile(file) ; // 实例化ZipFile对象
ZipInputStreamzipInput = null ; // 定义压缩输入流
OutputStreamout = null ; // 定义输出流,用于输出每一个实体内容
InputStreaminput = null ; // 定义输入流,读取每一个ZipEntry
ZipEntryentry = null ; // 每一个压缩实体
zipInput= new ZipInputStream(new FileInputStream(file)) ; // 实例化ZIpInputStream
while((entry= zipInput.getNextEntry())!=null){ // 得到一个压缩实体
System.out.println("解压缩" + entry.getName() + "文件。") ;
outFile= new File("d:" + File.separator + entry.getName()) ; // 定义输出的文件路径
if(!outFile.getParentFile().exists()){ // 如果输出文件夹不存在
outFile.getParentFile().mkdir(); // 创建文件夹
}
if(!outFile.exists()){ // 判断输出文件是否存在
outFile.createNewFile(); // 创建文件
}
input= zipFile.getInputStream(entry) ; // 得到每一个实体的输入流
out= new FileOutputStream(outFile) ; // 实例化文件输出流
inttemp = 0 ;
while((temp=input.read())!=-1){
out.write(temp);
}
input.close(); // 关闭输入流
out.close(); // 关闭输出流
}
input.close();
}
};
如果目录不存在,则应该进行创建操作。
压缩流总结:
1、 压缩文件中的每一个压缩实体都使用ZipEntry保存,一个压缩文件中可能包含一个或多个的ZipEntry对象
2、 在JAVA中可以进行zip、jar、gz三种格式的压缩支持,操作流基本上是一样的。
3、 ZipOutputStream可以进行压缩的输出,但是输出的位置不一定是文件。
4、 ZipFile表示每一个压缩文件,可以得到每一个压缩实体的输入流。
5、 ZipInputStream可以得到每一个实体,但是却无法得到每一个实体的输入流。