Java文件操作总结3

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]) ;

//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) ;

 }

}

显示结果:

 java文件操作(转载) - boy - MY SPACE

 任何编码都不写的情况下,肯定是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
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值