JAVA文件操作

JAVA文件操作(一)
1、课程名称: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]) ;
  InputStream input = new FileInputStream(f1) ;
  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
 对象序列化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值