Java--I/O与文件操作

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.File;
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("  --百度");
}
}
setOut和setErr均可以重定向输出位置,但不可混用。

一般情况下,建议不要使用此方法修改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();    //关闭输入流
}

字节转换流

OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流,即将一个字符流的输出对象变为字节流输出对象。

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可以提升操作性能。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值