java文件操作(转载)
File、输入、输出流、对象序列化
2、知识点
2.1、上次课程的主要知识点
1、 String与StringBuffer的区别
String一旦声明之后内容不可改变,可以直接赋值,连接可以用+号
StringBuffer的内容可以改变,必须实例化之后赋值
2、 Class类的作用
Class表示反射机制,表示一切类的组成
通过Class.forName()可以找到一个类,之后通过newInstance()实例化,但是要求使用此种方式的时候类中必须存在无参构造方法。
3、 比较器 —— Comparable
用于为一个对象进行排序操作
4、 日期操作类:
SimpleDateFormat ? Date ?日期显示
5、 正则表达式:
验证字符串的组成
拆分、替换
6、 使用正则验证email地址
public class RegDemo{
public static void main(String args[]){
String str = "a@aa.com.cn" ;
// com com.cn cn net net.cn org edu
System.out.println(str.matches("//w+@//w+.((com)|(com.cn)|(cn)|(net)|(net.cn)|(org)|(edu))")) ;
}
}
2.2、本次预计讲解的知识点
1、 File类的作用及使用
2、 字节输入流/字节输出流、字符输入流/字符输出流
3、 内存操作流
4、 打印流
5、 对象序列化
3、具体内容
在整个JAVA中所有的文件操作都是使用java.io包完成的,此包中包含了各种操作的类及接口。
IO包中有以下几个主要部分组成:
表示与文件本身的操作:File
IO的输入、输出类
对象序列化
3.1、File类(重点)
在整个IO包中,File类是唯一表示文件本身的,即:文件的创建、删除、存在与否的判断。
File类在使用的时候需要指定操作的文件路径,构造方法:
public File(String pathname)
例如:现在使用File类在硬盘上创建一个新的文件(e:/abc.txt)
创建文件的方法:public boolean createNewFile() throws IOException
import java.io.* ;
public class IODemo01{
public static void main(String args[]){
// 告诉系统准备操作这样的一个文件
File f = new File("e://abc.txt") ;
try{
System.out.println(f.createNewFile()) ;
}catch(Exception e){}
}
}
例如:删除在硬盘上建立好的文件
删除文件的方法:public boolean delete()
import java.io.* ;
public class IODemo02{
public static void main(String args[]){
// 告诉系统准备操作这样的一个文件
File f = new File("e://abc.txt") ;
// 删除文件
f.delete() ;
}
}
但是以上有一个问题,至少文件存在之后才可以删除。证明,在删除之前需要先判断此文件是否存在,判断语法:public boolean exists();
import java.io.* ;
public class IODemo03{
public static void main(String args[]){
// 告诉系统准备操作这样的一个文件
File f = new File("e://abc.txt") ;
if(f.exists()){
// 删除文件
f.delete() ;
}
}
}
例如:要求完成以下的功能
如果文件存在则删除,如果文件不存在则创建
import java.io.* ;
public class IODemo04{
public static void main(String args[]){
// 告诉系统准备操作这样的一个文件
File f = new File("e://abc.txt") ;
if(f.exists()){
// 删除文件
f.delete() ;
}else{
try{
f.createNewFile() ;
}catch(Exception e){}
}
}
}
发现此种操作并不是立刻生效的,有一定时间的延迟。
注意:
如果在程序中直接输出File类的对象,则会打印路径名称。
import java.io.* ;
public class IODemo05{
public static void main(String args[]){
// 告诉系统准备操作这样的一个文件
File f = new File("e://abc.txt") ;
System.out.println(f) ;
}
}
输出结果:
e:/abc.txt
例如:要求列出一个目录下的所有内容
方法名称如下:
public String[] list():只列出了所有的文件夹或文件的名称,不是绝对路径
public File[] listFiles():取得的是绝对路径
A、使用list()方法操作:
import java.io.* ;
public class IODemo06{
public static void main(String args[]){
// 告诉系统准备操作这样的一个文件
File f = new File("e://") ;
String s[] = f.list() ;
for(int i=0;i<s.length;i++){
System.out.println(s[i]) ;
}
}
}
B、使用listFiles()方法操作
import java.io.* ;
public class IODemo07{
public static void main(String args[]){
// 告诉系统准备操作这样的一个文件
File f = new File("e://") ;
File fs[] = f.listFiles() ;
for(int i=0;i<fs.length;i++){
System.out.println(fs[i]) ;
}
}
}
例如:区分一个给定的路径是文件还是文件夹
方法名称:public boolean isDirectory()
import java.io.* ;
public class IODemo08{
public static void main(String args[]){
// 告诉系统准备操作这样的一个文件
File f = new File("e://") ;
System.out.println(f.isDirectory()) ;
}
}
思考:
任意给定一个路径,要求把此路径下的所有文件包括各个子文件夹的文件全部列出。
思路:
|- 通过给定的路径判断是否是一个文件夹
|- 如果是一个文件夹,则继续列出里面的内容
|- 之后再将此文件夹里面的内容继续判断,观察是否是目录
import java.io.* ;
public class IODemo09{
public static void main(String args[]){
// 告诉系统准备操作这样的一个文件
File f = new File("e://") ;
print(f) ;
}
public static void print(File f){
if(f.isDirectory()){
File files[] = f.listFiles() ;
try{
for(int i=0;i<files.length;i++){
// 如果还有子文件夹,则肯定继续列出
print(files[i]) ;
}
}catch(Exception e){}
}else{
System.out.println(f) ;
}
}
}
3.2、RandomAccessFile类(了解)
RandomAccessFile:实现随机访问,可以在文件之中跳转。
在保存内容的时候,必须指定内容的长度。
现在向文件之中写入如下数据:
zhangsan 30
lisi 31
wangwu 32
例如:通过RandomAccessFile类向文件中保存内容
构造方法:public RandomAccessFile(File file,String mode) throws FileNotFoundException
String mode:表示的是文件的打开模式:
只读:r,但是使用此种方式的时候必须保证文件存在。
读写:rw,使用此种方式的时候,向文件中写入数据,如果文件不存在,则会自动创建一个新的文件出来
向文件中写数据:
向文件中写入字符串:public final void writeBytes(String s) throws IOException
向文件中写入数字:public final void writeInt(int v) throws IOException
文件操作之后必须关闭:
关闭:public void close() throws IOException
利用以上方法完成文件的写入,可是写的时候,必须注意,所有的内容长度必须固定。
import java.io.* ;
public class IODemo10{
public static void main(String args[]) throws Exception{
File f = new File("e:"+File.separator+"hello.txt") ;
RandomAccessFile raf = null ;
// 如果文件不存在,则会自动创建一个
raf = new RandomAccessFile(f,"rw") ;
String name = null ;
int age = 0 ;
name = "zhangsan" ;
age = 30 ;
raf.writeBytes(name) ;
raf.writeInt(age) ;
name = "lisi " ;
age = 31 ;
raf.writeBytes(name) ;
raf.writeInt(age) ;
name = "wangwu " ;
age = 32 ;
raf.writeBytes(name) ;
raf.writeInt(age) ;
raf.close() ;
}
}
例如:通过RandomAccessFile取出里面的内容
因为是读,所以可以使用只读的方式打开文件:r
读字符串:public final byte readByte() throws IOException
使用byte的方式读取进来
读数字:public final int readInt() throws IOException
跳过指定长度的内容:public int skipBytes(int n) throws IOException
跳回位置:public void seek(long pos) throws IOException
import java.io.* ;
public class IODemo11{
public static void main(String args[]) throws Exception{
File f = new File("e:"+File.separator+"hello.txt") ;
RandomAccessFile raf = null ;
// 如果文件不存在,则会自动创建一个
raf = new RandomAccessFile(f,"r") ;
String name = null ;
int age = 0 ;
byte b[] = new byte[8] ;
// 跳过第一个人的信息
raf.skipBytes(12) ;
for(int i=0;i<b.length;i++){
b[i] = raf.readByte() ;
}
age = raf.readInt() ;
name = new String(b) ;
System.out.println("姓名:" + name) ;
System.out.println("年龄:" + age) ;
raf.seek(0) ;
for(int i=0;i<b.length;i++){
b[i] = raf.readByte() ;
}
age = raf.readInt() ;
name = new String(b) ;
System.out.println("姓名:" + name) ;
System.out.println("年龄:" + age) ;
raf.close() ;
}
}
3.3、字节流、字符流操作类(重点)
文件操作的基本流程:
1、 通过File类找到一个文件
2、 通过File类去实例化字节流、字符流操作类
3、 进行读或写的操作,在写的时候如果文件不存在则会自动创建
4、 关闭文件
3.3.1、字节流
在字节流中分为两种:
输出流:OutputStream
输入流:InputStream
例如:向文件之中打印一个“Hello World!!!”。
肯定使用输出流。
定义:public abstract class OutputStream extends Objec timplements Closeable, Flushable
OutputStream子类:FileOutputStream
构造方法:public FileOutputStream(File file) throws FileNotFoundException
输出方法:public void write(byte[] b) throws IOException
可以发现只能写出一个byte数组,那么现在是一个字符串,如果要想使用此种方式,需要将一个字符串变为一个byte数组,String中的方法:public byte[] getBytes() 。
关闭:public void close() throws IOException
import java.io.* ;
public class IODemo12{
public static void main(String[] args){
// 通过File找到一个文件
File f = new File("e://hello.txt") ;
// 输出流操作类
OutputStream out = null ;
try{
// 通过子类实例化
out = new FileOutputStream(f) ;
}catch(Exception e){}
String str = "Hello World!!!" ;
byte b[] = str.getBytes() ;
try{
out.write(b) ;
}catch(Exception e){}
try{
out.close() ;
}catch(Exception e){}
}
}
例如:既然可以通过OutputStream向文件中写入内容,那么就一定可以从文件中读取内容,使用InputStream读取内容。
InputStream也是一个抽象类,所以必须使用其子类:FileInputStream
读的方式:
public int read(byte[] b) throws IOException
传入一个byte数组,将所有的内容保存在byte数组之中。
此方法返回向数组中写入数据的个数
将byte数组变为字符串:public String(byte b[])、public String(byte b[],int be,int len)
import java.io.* ;
public class IODemo13{
public static void main(String[] args){
// 通过File找到一个文件
File f = new File("e://hello.txt") ;
// 输出流操作类
InputStream input = null ;
try{
// 通过子类实例化
input = new FileInputStream(f) ;
}catch(Exception e){}
byte b[] = null ;
int len = 0 ;
try{
b = new byte[1024] ;
// 把所有的内容读到数组b中
// 返回读取的个数
len = input.read(b) ;
}catch(Exception e){}
try{
input.close() ;
}catch(Exception e){}
System.out.println(new String(b,0,len)) ;
}
}
但是读取的时候发现程序中开辟了一个很大的byte数组,不用的空间有些浪费,那能否根据文件的大小开辟呢?
File类中有取得文件长度的方法。
import java.io.* ;
public class IODemo14{
public static void main(String[] args){
// 通过File找到一个文件
File f = new File("e://hello.txt") ;
// 输出流操作类
InputStream input = null ;
try{
// 通过子类实例化
input = new FileInputStream(f) ;
}catch(Exception e){}
byte b[] = null ;
try{
b = new byte[(int)f.length()] ;
// 把所有的内容读到数组b中
// 返回读取的个数
input.read(b) ;
}catch(Exception e){}
try{
input.close() ;
}catch(Exception e){}
System.out.println(new String(b)) ;
}
}
如果现在不知道文件大小,该怎么读呢?
读取方法:
public abstract int read() throws IOException
如果读取的内容不是“-1”,就表示还有文件,可以继续读
import java.io.* ;
public class IODemo15{
public static void main(String[] args){
// 通过File找到一个文件
File f = new File("e://hello.txt") ;
// 输出流操作类
InputStream input = null ;
try{
// 通过子类实例化
input = new FileInputStream(f) ;
}catch(Exception e){}
byte b[] = null ;
try{
b = new byte[(int)f.length()] ;
int x = 0 ;
int foot = 0 ;
while((x=input.read())!=-1){
b[foot] = (byte)x ;
foot++ ;
}
}catch(Exception e){
System.out.println(e) ;
}
try{
input.close() ;
}catch(Exception e){}
System.out.println(new String(b)) ;
}
}
3.3.2、字符流
一个字符 = 两个字节(看计算机系统情况而定)。
在字符流操作中,主要使用以下两个类:
字符输出流:Writer
字符输入流:Reader
例如:向文件中保存一个数据
写内容的方法:public void write(String str) throws IOException
import java.io.* ;
public class IODemo16{
public static void main(String[] args){
// 通过File找到一个文件
File f = new File("e://hello.txt") ;
// 输出流操作类
Writer out = null ;
try{
// 通过子类实例化
out = new FileWriter(f) ;
}catch(Exception e){}
String str = "Hello World!!!" ;
try{
out.write(str) ;
}catch(Exception e){}
try{
out.close() ;
}catch(Exception e){}
}
}
例如:从文件中把内容读取进来
读的方法:
public int read(char[] cbuf) throws IOException
public int read() throws IOException
import java.io.* ;
public class IODemo17{
public static void main(String[] args){
// 通过File找到一个文件
File f = new File("e://hello.txt") ;
// 输出流操作类
Reader input = null ;
try{
// 通过子类实例化
input = new FileReader(f) ;
}catch(Exception e){}
char c[] = null ;
int len = 0 ;
try{
c = new char[(int)f.length()] ;
len = input.read(c) ;
}catch(Exception e){
System.out.println(e) ;
}
try{
input.close() ;
}catch(Exception e){}
System.out.println(new String(c,0,len)) ;
}
}
当然,也可以使用read()方法读取内容,代码如下:
import java.io.* ;
public class IODemo18{
public static void main(String[] args){
// 通过File找到一个文件
File f = new File("e://hello.txt") ;
// 输出流操作类
Reader input = null ;
try{
// 通过子类实例化
input = new FileReader(f) ;
}catch(Exception e){}
char c[] = null ;
try{
c = new char[(int)f.length()] ;
int x = 0 ;
int foot = 0 ;
while((x=input.read())!=-1){
c[foot] = (char)x ;
foot++ ;
}
}catch(Exception e){
System.out.println(e) ;
}
try{
input.close() ;
}catch(Exception e){}
System.out.println(new String(c)) ;
}
}
3.3.3、字节流和字符流的区别
字节与字符的不同在于:
所有的文件不管是使用Output、Writer实际上最终保存在文件上的都是字节。
字符是在内存中形成的。
例如:观察以下代码
使用字节流输出,但是并没有关闭
import java.io.* ;
public class IODemo19{
public static void main(String[] args){
// 通过File找到一个文件
File f = new File("e://hello.txt") ;
// 输出流操作类
OutputStream out = null ;
try{
// 通过子类实例化
out = new FileOutputStream(f) ;
}catch(Exception e){}
String str = "Hello World!!!" ;
byte b[] = str.getBytes() ;
try{
out.write(b) ;
}catch(Exception e){}
}
}
以上代码是使用字节流进行操作,但是文件本身并没有关闭,证明字节流是直接操作文件本身的。
那么,同样,将以上的字节流输出换为字符流输出:
import java.io.* ;
public class IODemo20{
public static void main(String[] args){
// 通过File找到一个文件
File f = new File("e://hello.txt") ;
// 输出流操作类
Writer out = null ;
try{
// 通过子类实例化
out = new FileWriter(f) ;
}catch(Exception e){}
String str = "Hello World!!!" ;
try{
out.write(str) ;
}catch(Exception e){}
}
}
运行之后,发现文件虽然已经创建,但是所有的内容并没有写进去,这是因为对于字符流在关闭操作的时候,会强制性的将缓存清空,那么以上代码并没有关闭,所以现在的内容还在缓存里,并没有直接到文件之中。
那么面对上面的情况,如果不关闭文件该如何解决呢?
在Writer类中提供了一个强制性清空缓存的操作:public abstract void flush() throws IOException
例如:修改之前的操作,清空缓存
import java.io.* ;
public class IODemo21{
public static void main(String[] args){
// 通过File找到一个文件
File f = new File("e://hello.txt") ;
// 输出流操作类
Writer out = null ;
try{
// 通过子类实例化
out = new FileWriter(f) ;
}catch(Exception e){}
String str = "Hello World!!!" ;
try{
out.write(str) ;
out.flush() ;
}catch(Exception e){}
}
}
但是:
一般程序对于字节流的使用相对较多,例如:图片、多媒体文件。
3.3.4、COPY功能的实现
命令格式:copy e:/hello.txt e:/abc.ini
此命令中有相关的错误提示。
那么现在要求使用JAVA编写这样的一个命令,例如:Java的类为Copy.class,则可以通过初始化参数的方式输入两个路径,例如:java Copy 路径1 路径2。
数据应该边读边写
要确定源路径是否存在及语法格式是否正确。
import java.io.* ;
public class Copy{
public static void main(String args[]) throws Exception{
// 判断参数
if(args.length!=2){
System.out.println("命令语法不正确。") ;
System.exit(1) ;
}
// 再判断源文件是否存在
File f1 = new File(args[0]) ;
if(!f1.exists()){
System.out.println("系统找不到指定的文件。") ;
System.exit(1) ;
}
File f2 = new File(args[1]) ;
//source ;
InputStream input = new FileInputStream(f1) ;
//dest;
OutputStream out = new FileOutputStream(f2) ;
int x = 0 ;
while((x=input.read())!=-1){
out.write(x) ;
}
System.out.println("拷贝完成。") ;
input.close() ;
out.close() ;
}
}
3.3、内存流(掌握)
一个子类决定父类的具体操作行为,那么对于整个IO操作来说,具体的输入、输出会根据子类的不同而有所不同。
内存流:指的是所有的输入、输出都是以内存为目的地。
内存的输出流:ByteArrayOutputStream,以内存为源目的地
内存输入流:ByteArrayInputStream,是指把内容向内存中输入。
ByteArrayInputStream方法:
构造:public ByteArrayInputStream(byte[] buf),表示把内容输入到内存里去
ByteArrayOutputstream方法:
构造:public ByteArrayOutputStream()
例如:以下代码完成了一个大-小写的转换功能
import java.io.* ;
public class IODemo22{
public static void main(String args[]) throws Exception{
ByteArrayInputStream bis = null ;
ByteArrayOutputStream bos = null ;
bos = new ByteArrayOutputStream() ;
String str = "helloworld" ;
// 把内容输入到内存里去
bis = new ByteArrayInputStream(str.getBytes()) ;
// 通过bos可以把内容读取出来
int c = 0 ;
while((c=bis.read())!=-1){
char x = Character.toUpperCase((char)c) ;
bos.write(x) ;
}
System.out.println(bos) ;
bis.close() ;
bos.close() ;
}
}
3.4、打印流(重点)
思考:
之前如果想向一个文件中保存一些内容,需要把内容变为byte数组,很麻烦,那么对于OutptuStream本身而言,只是具备了保存的功能,但是其功能并不完善。所以后来人们为了操作IO方便(输出方便)为OutptuStream增加了一个子类 —— PrintStream。
PrintStram之中提供了比OutputStram中更好的输出方法。
打印流实际上也分为两种:PrintStream、PrintWriter
PrintStream的使用:
构造:public PrintStream(OutputStream out)
根据传入的OutputStream来决定输出的位置。
使用:print()、println()
例如:观察PrintStream使用
import java.io.* ;
public class IODemo23{
public static void main(String args[]) throws Exception{
PrintStream ps = null ;
ps = new PrintStream(new FileOutputStream(new File("e://h.txt"))) ;
ps.print("hello ") ;
ps.print("world") ;
ps.println("/r/nHELLO") ;
ps.close() ;
}
}
如果需要在文件之后对内容进行追加的话,则直接编写以下代码即可:
import java.io.* ;
public class IODemo23{
public static void main(String args[]) throws Exception{
PrintStream ps = null ;
ps = new PrintStream(new FileOutputStream(new File("e://h.txt"),true)) ;
ps.print("hello ") ;
ps.print("world") ;
ps.println("/r/nHELLO") ;
ps.println("/r/nABC") ;
ps.close() ;
}
}
可以发现,使用打印流很方便的完成数据的输出。
3.5、System对IO的支持
回顾:System.out.println() ;
System中有以下两个静态属性:
System.out:对应的是标准输出,为显示器
System.in:对应的是标准输入,为键盘
3.6.1、System.out
System.out是PrintStream的类型,问:能否通过此对象为OutputStream实例化?
import java.io.* ;
public class IODemo24{
public static void main(String args[]) throws Exception{
OutputStream out = System.out ;
out.write("HELLO WORLD".getBytes()) ;
out.close() ;
}
}
以上代码进一步验证了面向对象的多态性,那个子类为父类实例化,那么父类就具备那个子类的功能。所有的目的地由子类决定。父类只是规定出了标准。
3.6.2、System.in
System.in对应着键盘的输入,是InputStream类型的对象。
那么既然是InputStream类型的对象,那么下面的代码实验了由键盘输入数据:
import java.io.* ;
public class IODemo25{
public static void main(String args[]) throws Exception{
// 现在代码从键盘中读取信息
InputStream input = System.in ;
byte b[] = new byte[1024] ;
System.out.print("请输入内容:") ;
int len = input.read(b) ;
System.out.println("输入的内容为:" + new String(b,0,len)) ;
}
}
以上确实完成了键盘的输入信息功能,但是否存在问题?
开辟的空间问题。
之前学过一种方式,不开辟一个空间,有多少读多少?
那么如果现在使用此种方式呢?
import java.io.* ;
public class IODemo27{
public static void main(String args[]) throws Exception{
// 现在代码从键盘中读取信息
InputStream input = System.in ;
StringBuffer buf = new StringBuffer() ;
System.out.print("请输入内容:") ;
int c = 0 ;
while((c=input.read())!=-1){
buf.append((char)c) ;
}
System.out.println("输入的内容为:" + buf) ;
}
}
以上代码没有指定出具体的空间大小,而是输入多少就保存多少,如果现在输入的是英文字母可以正确保存,如果是中文呢,因为是半个半个字保存的,所以是乱码。
3.6、BufferedReader(缓冲读取,重点)
之前出现乱码的根本原因在于是分着读的。
BufferedReader是一个字符流的子类,构造方法:
public BufferedReader(Reader in)
System.in是一个字节流的对象。
字节流-字符流的转换类:
InputStreamReader:把输入的字节流变为字符流
OutputStreamWriter:把输出的字符流变为字节流
观察InputStreamReader,是Reader的子类,构造方法:
public InputStreamReader(InputStream in)
BufferedReader中读取:public String readLine() throws IOException
键盘输入数据的标准格式:
import java.io.* ;
public class IODemo28{
public static void main(String args[]) throws Exception{
BufferedReader buf = null ;
buf = new BufferedReader(new InputStreamReader(System.in)) ;
System.out.print("请输入内容:") ;
String str = null ;
str = buf.readLine() ;
System.out.println("输入的内容为:" + str) ;
}
}
如果现在要想输入多个数据的话,则直接重复readLine()即可。
import java.io.* ;
public class IODemo29{
public static void main(String args[]) throws Exception{
BufferedReader buf = null ;
buf = new BufferedReader(new InputStreamReader(System.in)) ;
System.out.print("请输入内容1:") ;
String str = null ;
str = buf.readLine() ;
System.out.println("输入的内容1为:" + str) ;
System.out.print("请输入内容2:") ;
str = buf.readLine() ;
System.out.println("输入的内容2为:" + str) ;
}
};
3.6.1、练习一
完成以下功能
通过程序输入两个数字,之后进行两个数字的相加操作,并把结果打印输出。
要求:如果用户输入的不是数字,则应该提示用户输入错误,之后要求用户重新输入。
? 字符串 ? 整型:Integer.parseInt(String str)
A、 基础模型
import java.io.* ;
public class IODemo30{
public static void main(String args[]) throws Exception{
BufferedReader buf = null ;
buf = new BufferedReader(new InputStreamReader(System.in)) ;
int x = 0 ;
int y = 0 ;
System.out.print("输入第一个数字:") ;
String str = null ;
str = buf.readLine() ;
x = Integer.parseInt(str) ;
System.out.print("输入第二个数字:") ;
str = buf.readLine() ;
y = Integer.parseInt(str) ;
System.out.println("计算结果:" + x + " + " + y + " = " + (x+y)) ;
}
};
B、 为程序中加入判断
因为数据是由用户输入的,所以必须对输入的内容进行验证。使用正则表达式。
import java.io.* ;
public class IODemo31{
public static void main(String args[]) throws Exception{
BufferedReader buf = null ;
buf = new BufferedReader(new InputStreamReader(System.in)) ;
int x = 0 ;
int y = 0 ;
boolean flag = true ;
System.out.print("输入第一个数字:") ;
String str = null ;
while(flag){
str = buf.readLine() ;
if(str.matches("//d+")){
x = Integer.parseInt(str) ;
flag = false ;
}else{
System.out.print("输入的不是数字,请重新输入:") ;
}
}
System.out.print("输入第二个数字:") ;
flag = true ;
while(flag){
str = buf.readLine() ;
if(str.matches("//d+")){
y = Integer.parseInt(str) ;
flag = false ;
}else{
System.out.print("输入的不是数字,请重新输入:") ;
}
}
System.out.println("计算结果:" + x + " + " + y + " = " + (x+y)) ;
}
}
如果现在要求连续输入10个数字,则以上代码要重复10遍,下面设计一个输入数据的类,要求可以通过此类得到正确的整数、小数、日期(yyyy-mm-dd),和字符串,问此类如何设计,并将此类应用与之前的程序之上。
import java.io.* ;
import java.util.* ;
import java.text.* ;
class InputData{
private BufferedReader buf = null ;
public InputData(){
this.buf = new BufferedReader(new InputStreamReader(System.in)) ;
}
public String getString(String info){
String str = null ;
System.out.print(info) ;
try{
str = this.buf.readLine() ;
}catch(Exception e){}
return str ;
}
public int getInt(String info){
int temp = 0 ;
boolean flag = true ;
String str = null ;
while(flag){
try{
str = this.getString(info) ;
if(str.matches("//d+")){
temp = Integer.parseInt(str) ;
flag = false ;
}else{
System.out.print("输入的不是数字,请重新输入,") ;
}
}catch(Exception e){
System.out.print("输入的不是数字,请重新输入,") ;
}
}
return temp ;
}
public float getFloat(String info){
float temp = 0 ;
boolean flag = true ;
String str = null ;
while(flag){
try{
str = this.getString(info) ;
if(str.matches("//d+.?//d{1,2}")){
temp = Float.parseFloat(str);
flag = false ;
}else{
System.out.print("输入的不是数字,请重新输入,") ;
}
}catch(Exception e){
System.out.print("输入的不是数字,请重新输入,") ;
}
}
return temp ;
}
public Date getDate(String info){
Date temp = null ;
boolean flag = true ;
String str = null ;
while(flag){
try{
str = this.getString(info) ;
if(str.matches("//d{4}-//d{2}-//d{2}")){
// 把一个字符传变为Date类型
temp = new SimpleDateFormat("yyyy-MM-dd").parse(str) ;
flag = false ;
}else{
System.out.print("输入的不是日期,请重新输入,") ;
}
}catch(Exception e){
System.out.print("输入的不是日期,请重新输入,") ;
}
}
return temp ;
}
}
public class IODemo32{
public static void main(String args[]) throws Exception{
InputData input = new InputData() ;
int x = input.getInt("输入第一个数字:") ;
int y = input.getInt("输入第二个数字:") ;
System.out.println("计算结果:" + x + " + " + y + " = " + (x+y)) ;
System.out.println(input.getFloat("输入小数:")) ;
System.out.println(input.getDate("输入日期:")) ;
}
}
3.6.2、练习二
设计一个菜单程序
用户运行程序之后,可以显示一个菜单:
[1]、输入数据
[2]、查看数据
[3]、修改数据
[4]、退出系统
请选择:
提示:可以通过switch完成
import java.io.* ;
import java.util.* ;
import java.text.* ;
class InputData{
private BufferedReader buf = null ;
public InputData(){
this.buf = new BufferedReader(new InputStreamReader(System.in)) ;
}
public String getString(String info){
String str = null ;
System.out.print(info) ;
try{
str = this.buf.readLine() ;
}catch(Exception e){}
return str ;
}
public int getInt(String info){
int temp = 0 ;
boolean flag = true ;
String str = null ;
while(flag){
try{
str = this.getString(info) ;
if(str.matches("//d+")){
temp = Integer.parseInt(str) ;
flag = false ;
}else{
System.out.print("输入的不是数字,请重新输入,") ;
}
}catch(Exception e){
System.out.print("输入的不是数字,请重新输入,") ;
}
}
return temp ;
}
public float getFloat(String info){
float temp = 0 ;
boolean flag = true ;
String str = null ;
while(flag){
try{
str = this.getString(info) ;
if(str.matches("//d+.?//d{1,2}")){
temp = Float.parseFloat(str);
flag = false ;
}else{
System.out.print("输入的不是数字,请重新输入,") ;
}
}catch(Exception e){
System.out.print("输入的不是数字,请重新输入,") ;
}
}
return temp ;
}
public Date getDate(String info){
Date temp = null ;
boolean flag = true ;
String str = null ;
while(flag){
try{
str = this.getString(info) ;
if(str.matches("//d{4}-//d{2}-//d{2}")){
// 把一个字符传变为Date类型
temp = new SimpleDateFormat("yyyy-MM-dd").parse(str) ;
flag = false ;
}else{
System.out.print("输入的不是日期,请重新输入,") ;
}
}catch(Exception e){
System.out.print("输入的不是日期,请重新输入,") ;
}
}
return temp ;
}
}
class Operate{
public void add(){
System.out.println("选择的是输入操作!") ;
}
public void show(){
System.out.println("选择的是查看数据操作!") ;
}
public void update(){
System.out.println("选择的是修改操作!") ;
}
};
// 负责显示菜单
class Menu{
public Menu(){
while(true){
this.showMenu() ;
}
}
public void showMenu(){
System.out.println(" ================== 菜单程序 ================== ") ;
System.out.println("[1]、输入数据") ;
System.out.println("[2]、查看数据") ;
System.out.println("[3]、修改数据") ;
System.out.println("[4]、退出系统") ;
InputData input = new InputData() ;
Operate o = new Operate() ;
switch(input.getInt("请选择:")){
case 1:
{
o.add() ;
break ;
}
case 2:
{
o.show() ;
break ;
}
case 3:
{
o.update() ;
break ;
}
case 4:
{
System.out.println("byebye!") ;
System.exit(1) ;
break ;
}
case 5:
{
System.out.println("无效的选项,请重新选择!") ;
break ;
}
}
}
}
public class IODemo33{
public static void main(String args[]) throws Exception{
new Menu() ;
}
}
3.7、字符编码(了解)
在各个平台上都是有语言的支持的,那么一般对于文字来说有以下几种常见的编码方式:
GBK:包含了简体中文和繁体中文的编码集
GB2312:只包含了简体中文
ISO8859-1:是一个国际的通用编码
例如:取得本机的编码方式
public class IODemo34{
public static void main(String args[]) throws Exception{
System.getProperties().list(System.out) ;
}
}
显示结果:
任何编码都不写的情况下,肯定是GBK码,那么如果现在要保存一个文件的内容,但是文件的内容使用了ISO8859-1编码,问能正确解码吗?不可以
例如:以下代码对输出的内容进行重新编码
import java.io.* ;
public class IODemo35{
public static void main(String args[]) throws Exception{
OutputStream out = new FileOutputStream(new File("e://test.txt")) ;
out.write("世界,你好".getBytes("ISO8859-1")) ;
out.close() ;
}
}
因为程序本身与本地环境中的编码方式不一样,所以无法正确的进行解码。
程序造成乱码的根本原因:
编码不一致所造成
3.8、对象序列化(重点)
对象序列化:将一个对象进行IO操作,输入/输出。
如果要想实现对象序列化,则对象所在的类必须实现一个序列化接口 —— Serializable,但是此接口中没有任何的定义,所以此接口只是一个标识接口。
常见的标识接口:
Cloneable,表示可以被克隆
Serializable:标识可以被序列化
那么下面的代码以向文件中保存为例。
如果现在要想实现对象的输出和输入,则必须使用以下两个类:
ObjectOutputStream:对象输出流
构造方法:public ObjectOutputStream(OutputStream out) throws IOException
写对象:public final void writeObject(Object obj) throws IOException
ObjectInputStream:对象输入流,反序列化
构造方法:public ObjectInputStream(InputStream in) throws IOException
读对象:public final Object readObject() throws IOException,ClassNotFoundException
说明:
对象可以向任何地方保存。
例如:向文件之中写入一个对象
import java.io.* ;
class Person implements Serializable{
private String name;
private int age ;
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
public String toString(){
return "姓名:" + this.name + ",年龄:" + this.age ;
}
}
public class IODemo36{
public static void main(String args[]) throws Exception{
Person per = new Person("zhangsan",30) ;
ser(per) ;
}
public static void ser(Person per) throws Exception{
ObjectOutputStream oos = null ;
oos = new ObjectOutputStream(new FileOutputStream(new File("e://person.ser"))) ;
// 写对象
oos.writeObject(per) ;
oos.close() ;
}
}
例如:从文件之中读取出对象
import java.io.* ;
class Person implements Serializable{
private String name;
private int age ;
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
public String toString(){
return "姓名:" + this.name + ",年龄:" + this.age ;
}
}
public class IODemo37{
public static void main(String args[]) throws Exception{
Person per = new Person("zhangsan",30) ;
// ser(per) ;
System.out.println(dser()) ;
}
public static void ser(Person per) throws Exception{
ObjectOutputStream oos = null ;
oos = new ObjectOutputStream(new FileOutputStream(new File("e://person.ser"))) ;
// 写对象
oos.writeObject(per) ;
oos.close() ;
}
public static Person dser() throws Exception{
Person per = null ;
ObjectInputStream ois = null ;
ois = new ObjectInputStream(new FileInputStream(new File("e://person.ser"))) ;
per = (Person)ois.readObject() ;
ois.close() ;
return per ;
}
}
例如:现在不希望Person类中的name属性被序列化,那么次时对于不希望被序列化的属性就可以使用transient关键字声明。
import java.io.* ;
class Person implements Serializable{
private transient String name;
private int age ;
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
public String toString(){
return "姓名:" + this.name + ",年龄:" + this.age ;
}
}
public class IODemo37{
public static void main(String args[]) throws Exception{
Person per = new Person("zhangsan",30) ;
ser(per) ;
System.out.println(dser()) ;
}
public static void ser(Person per) throws Exception{
ObjectOutputStream oos = null ;
oos = new ObjectOutputStream(new FileOutputStream(new File("e://person.ser"))) ;
// 写对象
oos.writeObject(per) ;
oos.close() ;
}
public static Person dser() throws Exception{
Person per = null ;
ObjectInputStream ois = null ;
ois = new ObjectInputStream(new FileInputStream(new File("e://person.ser"))) ;
per = (Person)ois.readObject() ;
ois.close() ;
return per ;
}
}
4、总结
整个IO包中,实际上就五个类,一个接口、一个关键字
五个类:File、OutputStream、InputStream、Reader、Writer
一个接口:Serializable
一个关键字:transient
一切的操作以父类为准,但是里面有若干个子类很有用处:
OutputStream:
FileOutputStream:文件操作类
ByteArrayOutputStream:内存操作类
ObjectOutputStream:对象输出流
PrintStream:打印流
InputStream:
FileInputStream
ObjectInputStream
ByteArrayInputStream
Writer:
OutputStreamWriter:字符-字节的转换类
FileWriter
PrintWriter
Reader:
InputStreamReader
FileReader
BufferedReader
用户输入数据的标准格式
字符编码:GBK、GB2312、ISO8859-1