Java中的操作类都存放在java.io包中,最重要的就是5个类和1个接口。5个类分别是File、OutputStream、InputStream、Writer、Reader,一个接口是Serializable。
File类:
1、创建文件
使用File类中public boolean createNewFile() throws IOException{},使用了throws关键字,必须使用try..catch进行异常处理。
import java.io.File;
import java.io.IOException;
public class FileT1 {
public static void main(String[] args) {
File f=new File("d:"+File.separator+"test2.txt"); //实例化File类的对象
try{
f.createNewFile();
}catch (IOException e)
{
e.printStackTrace();
}
}
}
2、删除文件
File f=new File("d:"+File.separator+"test2.txt");
if(f.exists())
f.delete();
3、创建文件夹
File f=new File("d:"+File.separator+"www");
f.mkdir();
4、列出目录中全部内容
public String[] list():列出全部名称,返回一个字符串数组;
public File[] listFiles():列出完整的路径,返回一个File对象数组;
File f=new File("d:"+File.separator);
String str[]=f.list();
for(int i=0;i<str.length;i++)
{
System.out.println(str[i]);
}
5、判断给定路径是否为目录
File f=new File("d:"+File.separator);
if(f.isDirectory())
System.out.println(f.getPath()+"路径是目录");
else
System.out.println(f.getPath()+"路径不是目录");
字节流和字符流
java.io包中的两大流操作,分别有输入和输出操作。
字节流:输入数据使用InputStream类,输出数据使用OutputStream类。主要操作byte类型数据,以byte数组为准。
字符流:输入数据使用Reader类,输出数据使用Writer类。
一个字符等于两个字节。
使用字节流
1、字节输出流OutputStream:
类OutputStream是真难过个I/O包中字节输出流的最大父类:
public abstract class OutputStream extends Object implements Closeable,Flushable
FileOutputStream子类的构造方法:
public FileOutputStream(File file)throws FileNotFoundException
定义接口Closeable:
public interface Closeable{
void close() throws IOException
}
定义接口Flushable:
public interface Flushable{
void flush() throws IOException
}
类OutputStream中已经有了 这两个方法的实现,直接使用OutputStream类即可。
例:向文件中写入字符串
import java.io.File;
import java.io.OutputStream;
import java.io.FileOutputStream;
public class OutputStreamT1 {
//异常抛出,不处理
public static void main(String[] args)
throws Exception{
//第一步、使用File类找到一个文件,声明File对象
File f=new File("d:"+File.separator+"test2.txt");
//第二步、通过子类实例化父类对象
OutputStream out=null; //准备一个输出对象
out=new FileOutputStream(f); //通过对象多态性,进行实例化
//进行第三步、进行写操作
String str="Hello World!";
byte b[]=str.getBytes(); //只能输出byte数组,所以将字符串变为byte数组
out.write(b); //将内容输出,保存文件
out.close(); //关闭输出流
}
}
2、追加新内容
public FileOutputStream(File file,boolean append)throws FileNotFoundException
将append的值设为true,表示在文件的末尾追加内容。
将写入数据换行:String str=“\r\n Hello World!!”; //新的字符串
File f=new File("d:"+File.separator+"test2.txt");
FileOutputStream out2=null;
out2=new FileOutputStream(f,true);
String str="\r\nHello World!!";
byte b[]=str.getBytes();
out2.write(b);
out2.close();
3、字节输入流InputStream
定义:public abstract class InputStream extends Object implements Closeable
子类FileInputStream的构造方法:
public FileInputStream(File file)throws FileNotFoundException
例:从文件读取内容
import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;
public class InputStreamT1 {
//异常抛出,不处理
public static void main(String[] args)
throws Exception{
//第一步、使用File类找到一个文件,声明File对象
File f=new File("d:"+File.separator+"test2.txt");
//第二步、通过子类实例化父类对象
InputStream input=null; //准备一个输入对象
input=new FileInputStream(f); //通过对象多态性,进行实例化
//进行第三步、进行读操作
byte b[]=new byte[1024]; //所有内容都读到此数组中
input.read(b); //读取内容
input.close(); //关闭输出流
System.out.println("内容为:\n"+new String(b));//把byte数组变为字符串输出
}
}
上述代码存在一定问题,将byte数组变为字符串的时候将无用空间也转为字符串。
解决办法:观察read方法,它有一个返回值,表示向数组中写入了多少个数据。
4、开辟指定大小的byte数组
一是:根据文件数据量开辟空间大小,File类中存在一个length()方法。
byte b[]=new byte[(int)f.length()]; //所有内容都读到此数组中
int len= input.read(b);
System.out.println("读入数据长度: "+len);
二是:使用read()方法通过循环从文件中一个个把内容读取进来。
byte b[]=new byte[(int)f.length()];
for(int i=0;i<b.length;i++)
b[i]=(byte)input.read();
以上是在知道具体数组大小的前提下开展的,但在不知要输入的内容有多大的情况下,只能通过判断是否读到文件末尾的方式来读取文件。
byte b[]=new byte[1024]; //所有内容都读到此数组中
int len=0;
int temp=0; //读取每一个读取进来的数据
while((temp=input.read())!=-1) {
//表示还有内容,文件没有读完
b[len]=(byte)temp;
len++;
}
使用字符流
1、字符输出流Writer
定义:public abstract class Writer extends Object implements Appendable,Closeable,Flushable
定义子类:public FileWriter(File file)throws IOException
Appendable接口表示的是内容可以被追加,String类就实现了此接口,可以直接通过此接口的方法向输出流中追加内容。
例:向文件中写入数据
import java.io.File;
import java.io.Writer;
import java.io.FileWriter;
public class WriterT1 {
public static void main(String[] args) throws Exception {
//异常抛出,不处理
//第一步、使用File类找到一个文件,声明File对象
File f=new File("d:"+File.separator+"test2.txt");
//第二步、通过子类实例化父类对象
Writer out=null; //准备一个输出对象
out=new FileWriter(f); //通过对象多态性,进行实例化
//进行第三步、进行写操作
String str="Hi World!";
out.write(str); //将内容输出,保存文件
out.close(); //关闭输出流
}
}
与OutputStream操作流程大致相似,优势在于可以直接输出字符串,而不用将字符串变为byte数组之后再输出。
2、使用FileWriter追加文件内容
直接使用如下构造方法:
public FileWriter(File file,boolean append)throws IOException
将append的值设置为true表示追加。
Writer out=null; //准备一个输出对象
out=new FileWriter(f,true); //通过对象多态性,进行实例化
String str="\r\nAAAA\r\nHi World!";
3、字符输入流Reader
定义:public abstract class Reader extends Object implements Readable,Closeable
定义子类:public FileReader(File file)throws FileNotFoundException
例:读取文件内容
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
public class ReaderT1 {
public static void main(String[] args) throws Exception {
//异常抛出,不处理
//第一步、使用File类找到一个文件,声明File对象
File f=new File("d:"+File.separator+"test2.txt");
//第二步、通过子类实例化父类对象
Reader input=null; //准备一个输出对象
input=new FileReader(f); //通过对象多态性,进行实例化
//进行第三步、进行写操作
char c[]=new char[1024];
int len=input.read(c);
input.close(); //关闭输出流
System.out.println("内容为:\n"+new String(c,0,len));
}
}
如果不知道数据长度,可以像之前操作字节流那样,使用循环方式进行内容读取。
System类
System的三个常量:
public static final PrintStream out ------ 对应系统标准输出,一般是显示器
public static final PrintStream err ------ 错误信息输出
public static final InputStream in ------ 对应系统标准输入,一般是键盘
Syetem.out
System.out是PrintStream的对象,PrintStream是OutputStream的子类,可以直接使用此对象向屏幕输出信息。
OutputStream的哪个子类为其实例化,就具备了向哪里输出的能力。如果使用了FileOutputStream则表示向文件输出,使用了System.out则表示向显示器输出。体现了Java多态的好处--根据子类的不同完成的功能也不同。
System.err
实现错误信息的输出
public class SystemT2 {
public static void main(String[] args) {
String str="Hello"; //声明一个非数字的字符串
try {
System.out.println(Integer.parseInt(str)); //转型
}catch(Exception e) {
System.err.println(e);
}
}
}
System.in
键盘输入流,本身是InputStream类型的对象。
import java.io.InputStream;
public class SystemT2 {
//所有异常抛出
public static void main(String[] args) throws Exception{
//从键盘接收数据
InputStream input=System.in;
//开辟空间,接受数据
byte b[]=new byte[5];
//提示信息
System.out.print("请输入内容:");
//接受信息
int len=input.read(b);
System.out.println("输入的内容为:"+new String(b,0,len));
input.close();
}
}
上述代码存在两个问题:
一是:指定了输入数据的长度,如果现在输入的数据超出了其长度范围,则只能输入部分数据。
二是:如果指定的byte数组长度是奇数,则还有可能出现中文乱码。
解决办法: 不指定byte数组长度。执行后如果输入的是英文字母,没问题,若是中文,会出现乱码,这是因为数据是以一个个字节的方式读进来的,一个汉字是分两次读取的,所以造成乱码。
最好的输入方式:将全部输入的数据暂时放到一块内存中,然后一次性从内存中读取数据,这样所有数据只读了一次,不会造成乱码,而且也不会受长度的限制。需要用到BufferedRead类完成。
输入输出重定向:
pubic static void setOut(PrintStream out) ------ 重定向“标准”输出流
pubic static void setErr(PrintStream err) ------ 重定向“标准”错误输出流
pubic static void setIn(InputStream in) ------ 重定向“标准”输入流
为System.out输出重定向:
import java.io.FileOutputStream;
import java.io.PrintStream;
public class SystemT3 {
public static void main(String[] args)throws Exception {
System.setOut(
new PrintStream(
new FileOutputStream("d:"+File.separator+"red.txt")));
//System.out输出重定向
System.out.print("www.baidu.com"); //输出时,不再向屏幕上输出
System.out.println(" --百度");
}
}
一般情况下,建议不要使用此方法修改System.err的重定向,因为从概念上讲System.err的错误信息不希望用户看到。
为System.in输入重定向:
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class SystemT3 {
public static void main(String[] args)throws Exception {
//设置输入重定向
System.setIn(new FileInputStream("d:"+File.separator+"red.txt"));
InputStream input=System.in; //从文件中接受数据
byte b[]=new byte[1024]; //开辟空间,接收数据
int len=input.read(b); //接收
System.out.println("输入的内容为:"+new String(b,0,len));
input.close(); //关闭输入流
}
}
字节转换流
InputStreamReader:是Reader的子类,将输入的字节流变为字符流,即将一个字节流的输入对象变为字符流输入对象。
类OutputStreamWriter的构造方法如下所示:
public OutputStreamWriter(OutputStream out)
例:将字节输出流变为字符输出流
import java.io.*;
public class OutputStreamWriterT1 {
//所有异常抛出
public static void main(String[] args)throws Exception {
File f=new File("d:"+File.separator+"test.txt");
Writer out=null; //字符输出流
//字节流变为字符流
out=new OutputStreamWriter(new FileOutputStream(f));
out.write("HELLO WORLD!"); //使用字符流输出
out.close();
}
}
FileOutputStream是OutputStream的直接子类;
FileInputStream是InputStream的直接子类;
FileWriter不是Writer的直接子类,是OutputStreamWriter的子类;
FileReader不是Reader的直接子类,是InputStreamReader的子类。
从以上可以看出,不管使用字节流还是字符流,实际上最终都是以字节的形式操作输入/输出流的。
BufferedReader类
类BufferedReader能够从缓冲区读取内容,所有的输入字节数据都将放在缓冲区中。
BufferedReader类的常用方法:
public BufferedReader(Reader in) -- 构造方法 -- 接收一个Reader类的实例;
public String readLine() throws IOException -- 普通 -- 一次性从缓冲区中将内容全部读取进来;
BufferedReader只能接收字符流的缓冲区,这是因为每一个中文要占两个字节,所以需要将System.in这个字节的输入流变为字符的输入流。
将System.in变为字符流放入到BufferedReader后,可以通过方法readLine()等待用户输入信息。
键盘输入数据的标准格式:
import java.io.*;
public class BufferedReaderT {
public static void main(String[] args) {
BufferedReader buf=null; //声明对象
//字节流变为字符流
buf=new BufferedReader(new InputStreamReader(System.in));
String str=null; //接收输入内容
System.out.print("请输入内容: ");
try {
str=buf.readLine(); //读取一行数据
}catch (IOException e) {
e.printStackTrace(); //输出信息
}
System.out.println("输入端内容为: "+str);
}
}
例:输入两个数字,并让两个数字相加
由于从键盘接收过来的数据全部是采用字符串的形式存放的,可以直接通过包装类Integer将字符串转换为基本数据类型。
import java.io.*;
public class BufferedReaderT {
public static void main(String[] args) throws Exception{
int i=0;
int j=0;
BufferedReader buf=null; //接受键盘的输入数据
buf=new BufferedReader(new InputStreamReader(System.in));
String str=null; //接收数据
System.out.print("请输入第一个数字: ");
//接收数据
str=buf.readLine();
//将字符串变为整数
i=Integer.parseInt(str);
System.out.print("请输入第二个数字: ");
str=buf.readLine();
j=Integer.parseInt(str);
System.out.println(i+"+"+j+"="+(i+j));
}
}
上述代码存在以下几个问题:
如果输入的字符串不是数字,则无法进行转换,会出现数字格式化异常,因此在转换时应该使用正则进行验证,如果验证成功,则可以进行转换;如果验证失败,则无法进行转换,需等待用户重新输入数字才可以。
为处理最常见的可能是整数、小数、日期、字符串的数据,设计一个专门的输入数据类,完成输入数据的功能。
import java.io.*;
import java.util.*;
import java.text.*;
public class InputData {
private BufferedReader buf=null;
public InputData() { //只要输入数据就要使用此语句
this.buf=new BufferedReader(new InputStreamReader(System.in));
}
public String getString(String info) { //得到字符串信息
String temp=null;
System.out.print(info); //打印提示信息
try {
temp=this.buf.readLine(); //接收数据
}catch(IOException e){
e.printStackTrace();
}
return temp;
}
public int getInt(String info,String err) {
int temp=0;
String str=null;
boolean flag=true; //定义一个标记位
while(flag) {
str=this.getString(info); //接收数据
if(str.matches("^\\d+$")) { //判断是否由数字组成
temp=Integer.parseInt(str); //转型
flag=false; //结束循环
}else {
System.out.println(err); //打印错误信息
}
}
return temp;
}
public float getFloat(String info,String err) { //得到一个小数的输入数据
float temp=0;
String str=null;
boolean flag=true; //定义一个标记位
while(flag) {
str=this.getString(info); //接收数据
if(str.matches("^\\d+.?\\d+$")) { //判断是否由数字组成
temp=Float.parseFloat(str); //转型
flag=false; //结束循环
}else {
System.out.println(err); //打印错误信息
}
}
return temp;
}
public Date getDate(String info,String err) { //得到一个小数的输入数据
Date temp=null;
String str=null;
boolean flag=true; //定义一个标记位
while(flag) {
str=this.getString(info); //接收数据
if(str.matches("^\\d{4}-\\d{2}-\\d{2}$")) { //判断是否由数字组成
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
try {
temp=sdf.parse(str); //将字符串变为Date型数据
}catch(Exception e) {}
flag=false; //结束循环
}else {
System.out.println(err); //打印错误信息
}
}
return temp;
}
上述代码可以实现整数、小数、字符串、日期类型数据的输入。在得到日期类型时使用了SimpleDateFormat类,并指定了日期的转换模版,将一个字符串变为了一个Date类型的数据。
Scanner类
JDK1.5之后,Java专门提供了输入数据类,此类不但可以完成输入数据的操作,而且也能方便地验证输入的数据。Scanner类被放在java.util包中。Scanner类可以接收任意的输入流。在Scanner类中有一个可以接收InputStream类型的构造方法,这就表示只要是字节输入流的子类都可以通过Scanner类进行方便的读取。
最简单的数据输入方法是,直接使用Scanner类的next()方法来实现。
import java.util.*;
public class ScannerT1 {
public static void main(String[] args) {
//从键盘接收数据
Scanner scan=new Scanner(System.in);
System.out.println("输入数据: ");
String str=scan.next(); //接收数据
System.out.println("输入的数据为: "+str);
}
}
上述实例存在一个问题------如果输入了带有空格的内容,则只能取出空格之前的数据。这是因为Scanner将空格当作了一个分隔符。
如果要输入int或者float类型的数据,将类Scanner中也有支持这些类型的方法。但是在输入之前最好先使用方法hasNextInt()或者hasNextFloat()进行验证。
import java.util.*;
public class ScannerT1 {
public static void main(String[] args) {
//从键盘接收数据
Scanner scan=new Scanner(System.in);
int i=0;
float f=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类没有专门提供日期格式输入操作,若要得到日期类型数据,自己编写正则验证,并手工转换。
import java.util.*;
import java.text.*;
public class ScannerT1 {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in); //从键盘输入数据
String str=null;
Date date=null;
System.out.print("输入日期(yyyy-mm-dd):");
if(scan.hasNext("^\\d{4}-\\d{2}-\\d{2}$")) { //判断
str=scan.next("^\\d{4}-\\d{2}-\\d{2}$"); //接收
try {
date=new SimpleDateFormat("yyyy-MM-dd").parse(str);
}catch(Exception e) {}
}else {
System.out.println("输入的日期格式错误!");
}
System.out.println(date);
}
}
如果要从文件中取得数据,则直接将类File的实例传入到Scanner的构造方法中即可。
import java.util.*;
import java.text.*;
import java.io.*;
public class ScannerT1 {
public static void main(String[] args) {
File f=new File("D:"+File.separator+"test.txt"); //指定操作文件
Scanner scan=null;
try {
scan=new Scanner(f); //从键盘接收数据
}catch(Exception e) {}
StringBuffer str=new StringBuffer();
while(scan.hasNext()) {
str.append(scan.next()).append('\n'); //读取数据
}
System.out.println("文件内容为: \n"+str);
}
}
从操作过程看,此类有一个默认的分隔符,这样如果在文件中存在换行,则表示一次输入结束,所以本程序采用循环的方式读取,并在每次读完一行之后加入换行符,因为读取时内容需要反复修改,所以使用类StringBuffer可以提升操作性能。