在Java中IO的核心组成是5个类(File、OutputStream、InputStream、Reader、Writer)和一个接口(Serializable)。
IO需要导入的包的是java.io。并在是阻塞式IO。
File操作文件类
java.io包中,FILE类是唯一 一个与文件本身操作(创建、删除、取得信息)有关,与文件内容无关的程序类。
FILE的基本使用
java.io.File类是一个普通的类,直接产生实例化对象即可。如果要实例化对象用到下面2个构造方法:
如果需要创建一个新文件,方法如下:
public boolean createNewFile() throws IOException
判断文件是否存在(可判断文件夹和文件)
public boolean exists();
删除文件:
public boolean delete();
对上面方法进行练习:
package CODE.JavaIo;
import java.io.File;
import java.io.IOException;
//文件的创建、判断是否存在、删除文件
public class Create {
public static void main(String[] args) {
//定义要操作的文件路径
File file=new File("C:\\Users\\lenovo\\Desktop\\IO.txt");
System.out.println(file); //C:\Users\lenovo\Desktop\IO.txt
//判断文件是否存在,不存在则创建,存在则删除
if(!file.exists())
{
System.out.println("文件不存在");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
else
file.delete();
}
}
注意:IO异常都是受查异常。
如果第一次执行这个Java程序,将会在桌面上新建一个IO.txt,第二次将会删除。
可以发现在实例化File对象时,路径之间用的是"",而在linux下用的"/",为了代码可移植性,一般将路径分隔符用 File.separator。
File file=new File("C:"+File.separator+"Users"+File.separator+ "lenovo"+File.separator+"Desktop"+File.separator+"IO.txt");
目录操作
取得父路径
public String getParent()
取得父File对象
public File getParentFile()
创建目录(无论有多少目录,都会创建)
public boolean mkdirs()
代码如下:
package CODE.JavaIo;
import java.io.File;
import java.io.IOException;
public class Create {
public static void main(String[] args) {
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+File.separator+"java"+
File.separator+"IO"+File.separator+"IO.txt");
//exists可以判断文件夹是否存在
if(!file.getParentFile().exists())
{
file.getParentFile().mkdirs(); //有多少目录,就创建多少父目录
}
else
{
System.out.println("父路径:"+file.getParent()+" 父文件:"+file.getParentFile());
if(!file.exists()) //如果IO.txt不存在,即创建该文件
{
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
else
{
System.out.println("文件已存在");
}
}
}
}
第一次执行,创建父目录;第二次执行,父目录存在,创建文件;第三次执行,文件已存在。
取得文件信息
在File类里面提供有一系列取得文件信息的操作:
package CODE.JavaIo;
import java.io.File;
import java.sql.Date;
public class File1 {
public static void main(String[] args) {
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+File.separator+"java"+
File.separator+"IO"+File.separator+"IO.txt");
if(file.exists()&&file.isFile())
{
System.out.println(file.length()); //取得文件大小 9字节
System.out.println(new Date(file.lastModified())); //2018-12-01
}
}
}
例:取得桌面文件夹测试工具里内容:
package CODE.JavaIo;
import java.io.File;
//查看文件夹测试工具内容
public class File1 {
public static void main(String[] args) {
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+File.separator+"测试工具");
if(file.exists()&&file.isDirectory())//是文件夹且存在
{
File files[]=file.listFiles();
for(File file2:files)
{
System.out.println(file2);
}
}
}
}
从图可以看出,这些都是文件夹,那怎么查看文件夹测试工具里所有文件呢?
package CODE.JavaIo;
import java.io.File;
//查看文件夹测试工具所有文件
public class File1 {
public static void main(String[] args) {
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+File.separator+"测试工具");
ListAllFile(file);
}
public static void ListAllFile(File file)
{
//如果file是文件则打印
if(file.isFile())
{
System.out.println(file);
return ;
}
//现在是文件夹
//files里存的是文件夹里内容,包括文件夹和文件
File files[]=file.listFiles();
if(files!=null) //如果这个文件夹什么都没有,需要判断
{
for(File file1:files)
{
ListAllFile(file1);
}
}
}
}
注意:由于IO操作是阻塞操作,所以一般将IO操作放在子线程中。new Thread( ( )->{ IO操作} ).start( );
字节流与字符流
File类不支持文件内容处理,如果要处理文件内容,必须通过流的操作模式来完成。流分为输入流和输出流。
在java.io包中,流分为两种:字节流和字符流。
1.字节流:InputStream、OutputStream
2.字符流:Reader、Writer
字节流和字符流操作的本质区别只有一个:字节流是原生的操作,而字符流是处理后操作。
一般使用字节流,无论是网络传输还是磁盘数据保存均以字节为单位。
只有处理文本时才会使用字符流。
流的操作流程:
无论是字节流还是字符流,操作流程几乎一样,以文件操作为例:
IO属于资源处理,所有资源树立(IO、数据库、网络)使用后都必须关闭。
字节输出流(OutputSream)
如果要想通过程序进行内容输出,可以使用java.io.OutputSream。
OutputStream类的定义结构:
public abstract class OutputStream implements Closeable, Flushable
OutputStream类实现了Closeable,Flushable两个接口,这两个接口中的方法为:
1.Closeable接口:public void close() throws IOException;
2.Flushable接口: public void flush() throws IOException;
在OutputStream抽象类中定义其他方法:
从OutputStream定义可以看见,OutputStream是一个抽象类,如果要实例化对象,需要依赖子类。如果要进行文件的操作,可以使用FileOutputStream类来处理,FileOutputStream构造方法如下:
覆盖式写入:
package CODE.JavaIo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class ByteStream {
public static void main(String[] args) throws IOException{
//取得File对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+
File.separator+"java"+File.separator+"IO.txt");
//文件输出时,如果文件不存在,会自动生成,但是必须保证父目录存在,如果父目录不存在,必须创建
if(!file.getParentFile().exists())
{
System.out.println("父目录不存在");
file.getParentFile().mkdirs();
}
//取得file对象的输出流
OutputStream out=new FileOutputStream(file); //覆盖式写入
String msg="hello pick";
//进行数据的写入
out.write(msg.getBytes()); //将字符串转换成字节数组
//关闭流
out.close();
}
}
如果父目录java不存在,将会创建一个父目录,如果该文件不存在,该文件会自动生成,不需要手动创建,但是必须保证父目录存在。
当使用FileOutputStream进行文件内容输出时,只要文件的父路径存在,FileOutputStream会自动创建文件。
上面代码使用的是覆盖式写入,也就是不论执行多少遍,IO.txt文档里都是"hello pick”这一句话。
如果需要追加式写入,用public FileOutputStream(File file, boolean append),代码如下:
package CODE.JavaIo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
////追加式写入
public class ByteStream {
public static void main(String[] args) throws IOException{
//取得File对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+
File.separator+"java"+File.separator+"IO.txt");
//文件输出时,如果文件不存在,会自动生成,但是必须保证父目录存在,如果父目录不存在,必须创建
if(!file.getParentFile().exists())
{
System.out.println("父目录不存在");
file.getParentFile().mkdirs();
}
//取得file对象的输出流
OutputStream out=new FileOutputStream(file,true); //追加式写入
String msg="hello pick\r\n";
//进行数据的写入
out.write(msg.getBytes()); //将字符串转换成字节数组
//关闭流
out.close();
}
}
部分内容写入:public void write(byte b[], int off, int len) throws IOException;
package CODE.JavaIo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//部分内容写入
public class ByteStream {
public static void main(String[] args) throws IOException{
//取得File对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+
File.separator+"java"+File.separator+"IO.txt");
//文件输出时,如果文件不存在,会自动生成,但是必须保证父目录存在,如果父目录不存在,必须创建
if(!file.getParentFile().exists())
{
System.out.println("父目录不存在");
file.getParentFile().mkdirs();
}
//取得file对象的输出流
OutputStream out=new FileOutputStream(file,true); //追加式写入
String msg="hello pick\r\n";
//进行数据的写入
out.write(msg.getBytes(),6,6); //将字符串转换成字节数组
//关闭流
out.close();
}
}
AutoCloseable自动关闭支持
从JDk1.7开始追加了一个AutoCloseable接口,这个接口的主要目的是自动进行关闭处理,但是这种处理一般不好用,因为使用它必须结合try…catch
代码如下:
package CODE.JavaIo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//AutoCloseable自动关闭
class Message implements AutoCloseable
{
@Override
public void close()
{
System.out.println("自动关闭");
}
}
public class ByteStream {
public static void main(String[] args) {
try(Message message=new Message()) //必须在try中定义对象
{
//取得File对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+
File.separator+"java"+File.separator+"IO.txt");
//文件输出时,如果文件不存在,会自动生成,但是必须保证父目录存在,如果父目录不存在,必须创建
if(!file.getParentFile().exists())
{
System.out.println("父目录不存在");
file.getParentFile().mkdirs();
}
//取得file对象的输出流
OutputStream out=new FileOutputStream(file,true); //追加式写入
String msg="hello pick\r\n";
//进行数据的写入
out.write(msg.getBytes(),6,6); //将字符串转换成字节数组
}catch (IOException e)
{
e.printStackTrace();
}
}
}
字节输入流(InputStream)
InputStream类的定义如下:
public abstract class InputStream implements Closeable
InputStream类只实现了Closeable接口。
在InputStream类中提供有如下方法:
同OutputStream的使用一样,InputStream是一个抽象类,如果要对其实例化,同样也需要使用子类。如果要对
文件进行处理,则使用FileInputStream类。
//从文件读取数据
package CODE.JavaIo;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ByteInStream {
public static void main(String[] args) throws IOException {
//取得File对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+
File.separator+"java"+File.separator+"IO.txt");
//从文件读数据,必须保证文件存在而且是文件即不能是文件夹
if(file.exists()&&file.isFile()) {
//取得file对象的输入流
InputStream in = new FileInputStream(file);
byte[] b = new byte[1024]; //每次可以读取的最大数量
int len=in.read(b); //将读取的数据放在字节数组b中,返回实际读取数据大小
System.out.println(new String(b,0,len)); //将字节数组b转换成String,并且长度是实际读取数据大小
in.close(); //关闭流
}
}
}
字符输出流(Writer)
Writer类的定义如下:
public abstract class Writer implements Appendable, Closeable, Flushable
Writer与OutputStream相比多了一个Appendable接口。
Writer类中其他方法:
如果要对将文件内容输出用子类FileWriter。
构造方法如下:
例:通过Writer实现输出:
package CODE.JavaIo;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
//字符输出流
public class CharOutStream {
public static void main(String[] args) throws IOException {
//取得File对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+
File.separator+"java"+File.separator+"IO.txt");
//必须保证父目录存在
if(!file.getParentFile().exists())
{
file.getParentFile().mkdirs();
}
//取得File对象的输出流
//覆盖式写入
//Writer wr=new FileWriter(file);
//追加式写入
Writer wr=new FileWriter(file,true);
wr.write("哈喽 pick\r\n");
//关闭流
wr.close();
}
}
字符输入流(Reader)
Reader类的定义:
public abstract class Reader implements Readable, Closeable
Reader类的其他方法:
注意:Writer类中提供有方法直接向目标源写入字符串,而在Reader类中没有方法可以直接读取字符串类型,这个时候只能通过字符数组进行读取操作。
package CODE.JavaIo;
import java.io.*;
//字符输入流
public class CharInStream {
public static void main(String[] args) throws IOException {
//取得File对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+
File.separator+"java"+File.separator+"IO.txt");
//从文件读数据,必须保证文件存在
if(file.exists())
{
//获取File对象的输入流
Reader re=new FileReader(file);
char[] cbuf=new char[1024]; //最大每次可以读取的最大数量
int len=re.read(cbuf); //将读取的数据存放到字符数组cbuf中,返回实际读取大小
System.out.println(new String(cbuf,0,len)); //将字符数组转化成字符串,并且大小的实际读取大小
re.close();//关闭流
}
}
}
字符流的输入和输出都支持中文,而字节流不支持中文。
字符流 V 字节流
package CODE.JavaIo;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
//字符输出流
public class CharOutStream {
public static void main(String[] args) throws IOException {
//取得File对象
File file=new File("C:"+File.separator+"Users"+File.separator+
"lenovo"+File.separator+"Desktop"+
File.separator+"java"+File.separator+"IO.txt");
//必须保证父目录存在
if(!file.getParentFile().exists())
{
file.getParentFile().mkdirs();
}
//取得File对象的输出流
//覆盖式写入
//Writer wr=new FileWriter(file);
//追加式写入
Writer wr=new FileWriter(file,true);
wr.write("哈喽 pick\r\n");
//清除缓冲区,如果没有wr.close,需要清除缓冲区,才能将内容输出到文档IO.txt中
wr.flush();
}
}
在博客前面讲到:字符流是处理后操作-- -->字符流是经过缓冲区处理后才输出到文件中或者输入时先经缓冲区处理。
在进行IO处理的时候,如果是图片、音乐、文字可以用字节流,如果处理中文需要用到字符流。