在整个Java.io包中最重要的就是
五个类:File,OutputStream,IntputStream,Reader,Writer
一个接口:Serializable
主要的类如下:
1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。
2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。
3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。
4.Reader(文件格式操作):抽象类,基于字符的输入操作。
5. Writer(文件格式操作):抽象类,基于字符的输出操作。
6. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。
Java中IO流的体系结构如果:
类结构图:
1、流的概念和作用
流:代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象<Thinking in Java>
流的本质:数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
流的作用:为数据源和目的地建立一个输送通道。
Java中将输入输出抽象称为流,就好像水管,将两个容器连接起来。流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流.
1.File文件操作类
File类是唯一一个与文件本身操作(创建、删除、取得信息..)有关的程序类
1.1目录操作:
File类中取得目录的方法:
1.创建一个新文件:
public boolean createNewFile() throws IOException
2.判断文件是否存在
public boolean exists()
3.删除文件
public boolean delete()
4.获取父路径或者父File类对象
public String getParent()
public File getParentFile()
5.创建父路径,此时最好取得父路径的File类对象
public boolean mkdirs()
具体范例:
package JavaIO;
import java.io.File;
import java.io.IOException;
public class demo {
public static void main(String[] args) throws IOException {
File file=new File(File.separator+"D:"+File.separator+"测试文夹"+File.separator+"aa.txt");
if (!file.getParentFile().exists())
{
file.getParentFile().mkdir();//创建目录
}
if (file.exists())
{
file.delete();//文件如果存在则删除
}else
{
file.createNewFile();//文件不存在即创建
}
}
}
1.2文件信息
File类提供的取得文件信息的方法
1. 判断路径是否是文件: public boolean isFile()
2. 判断路径是否是目录: public boolean isDirectory()
3. 取得文件大小(字节): public long length()
4. 最后一次修改日期 : public long lastModified()
import java.io.File;
import java.io.IOException;
import java.util.Date;
public class test {
public static void main(String[] args) throws IOException {
//如果不创建一个新线程,所有代码都是在main线程下完成,如果listAllFiles()方法没有完成,那么对于main后续的执行将无法完
//成。这种耗时的操作让主线程出现了阻塞,而导致后续代码无法正常执行完毕。如果不想让阻塞产生,最好再产生一个新的线程进行处理。
new Thread(()->{
File file = new File("D:\\测试文件夹");
listAllFile(file);
}).start();
System.out.println("开始文件输出---");
}
public static void listAllFile(File file) {
if (file.isDirectory())
//现在给定的file对象属于目录
{
//File[] listFiles() 获取该目录中的所有子项,每一个子项都是一个File实例,包括所有的文件及目录。()
File[] result = file.listFiles();//继续列出子目录内容
if (result != null) {
for (File file1 : result) {
//这一段代码主要是打印当前目录下的所有子目录及文件
// if (file1.isDirectory()) {
// System.out.println("目录:" + file1);
// } else {
// System.out.println("文件:" + file1);
// }
//递归主要是实现打印改目录下包括子目录下所有的file的文件
listAllFile(file1);
}
}
} else {
//给定的file是文件,直接打印
System.out.println("是文件" + file);
}
}
}
注意:实际项目部署环境可能与开发环境不同。那么这个时候路径的问题就很麻烦了。windows下使用的是"", 而Unix系统下使用的是"/"。所以在使用路径分隔符时都会采用File类的一个常量"public static final String separator "来描述。
2.字节流和字符流
File类不支持文件内容处理,如果要处理文件内容,必须要通过流的操作模式来完成。流分为输入流和输出流
2.1流的简单介绍
在java.io包中,流分为俩种,字节流和字符流。
1. 字节流:InputStream、OutputStream
2. 字符流:Reader、Write
字节流与字符流操作的本质区别只有一个:字节流是原生的操作,而字符流是经过处理后的操作。 在进行网络数据传输、磁盘数据保存所保存所支持的数据类型只有:字节。 而所有磁盘中的数据必须先读取到内存后才能进行操作,而内存中会帮助我们把字节变为字符。字符更加适合处理 中文。
使用流的其基本的操作流程(以文件操作为例):
1.根据文件路径创建File类对象
2.根据字节流或字符流的子类实例化父类对象
3.进行数据的读取或写入操作
4,关闭流close()
2.2字节输出流-outputStream
想要通过程序进行内容的输出,则可以用java.io.OutputStream。
观察OutputStream类的定义结构:
public abstract class OutputStream implements Closeable, Flushable
我们会发现:
OutputSream实现了Closeable,Flushable俩个接口,这俩个接口中的方法:
1. Closeable: public void close() throws IOException;
2. Flushable: public void flush() throws IOException;
在OutputStream类中还定义有其他方法:
1. 将给定的字节数组内容全部输出:public void write(byte b[]) throws IOException
2. 将部分字节数组内容输出:public void write(byte b[], int off, int len) throws IOException
3. 输出单个字节:public abstract void write(int b) throws IOException;
由于OutputStream是一个抽象类,所以要想为父类实例化,就必须要使用子类。由于方法名称都由父类声明好 了,所以我们在此处只需要关系子类的构造方法。如果要进行文件的操作,可以使用FileOutputStream类来处理, 这个类的构造方法如下:
1. 接收File类(覆盖):public FileOutputStream(File file) throws FileNotFoundException
2. 接收File类(追加):public FileOutputStream(File file, boolean append)
输出流的范例:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Outputdemo {
public static void main(String[] args) throws Exception{
File file=new File("D:\\测试文夹\\aa.txt");
//首先判断父目录是否存在
if (!file.getParentFile().exists())
{
file.getParentFile().mkdir();
}
//OutputStream是一个抽象类,所以需要通过子类进行实例化,此时只能操作File类---public class FileOutputStream extends OutputStream
//此时注意FileOutputStream的俩种构造方式来决定输入的文字是覆盖还是追加--此时是追加
OutputStream outputStream= new FileOutputStream(file,true);
String msg="我最喜欢上班啦,爱上班啦\n";
outputStream.write(msg.getBytes());
outputStream.close();
}
}
结果:文件中新添加了一条
2.3字节输入流--InputStream
字节输入流可以实现程序输出内容到文件的处理。
InputStream类的定义:
public abstract class InputStream implements Closeable
发现InputStream类只实现了Closeable接口,在InputStream类中提供有如下方法:
1. 读取数据到字节数组中,返回数据的读取个数。如果此时开辟的字节数组大小大于读取的数据大小,则返 回的就是读取个数;如果要读取的数据大于数组的内容,那么这个时候返回的就是数组长度;如果没有 数据了还在读,则返回-1: public int read(byte b[]) throws IOException.最常用方法
2. 读取部分数据到字节数组中,每次只读取传递数组的部分内容,如果读取满了则返回长度(len),如果没有 读取满则返回读取的数据个数,如果读取到最后没有数据了返回-1:public int read(byte b[], int off, int len) throws IOException
3. 读取单个字节,每次读取一个字节的内容,直到没有数据了返回-1:public abstract int read() throws IOException;
同OutputStream的使用一样,InputStream是一个抽象类,如果要对其实例化,同样也需要使用子类。如果要对 文件进行处理,则使用FileInputStream类。
范例:实现文件信息的读取
//字符流
//如果字符流不关闭,数据就有可能保存在缓存中并没有输出到目标源。这种情况下就必须强制刷新才能够得到完整
//数据。
//out.flush(); // 写上此语句表示强制清空缓冲内容,所有内容都输出。
public class Inputdemo {
public static void main(String[] args) throws Exception {
File file=new File("D:\\测试文夹\\aa.txt");
if (file.exists())
{
InputStream in =new FileInputStream(file);
//相当于缓冲器作用
byte[] bytes=new byte[1024];
//此时的数据读到了数组之中,并且计算出了长度
int len=in.read(bytes);
//// 将字节数组转为String
String result=new String (bytes,0,len);
System.out.println("读取内容:\n"+result);
in.close();
}
}
}
结果:
2.5字符输出流
字符适合于处理中文数据,Writer是字符输出流的处理类,这个类的定义如下:
public abstract class Writer implements Appendable, Closeable, Flushable
与OutputStream相比多了一个Appendable接口。
在Writer类里面也提供write()方法,而且该方法接收的类型都是char型,要注意的是,Writer类提供了一个直接输 出字符串的方法:
public void write(String str) throws IOException
如果要操作文件就使用FileWriter子类
范例:
mport java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Writerdemo {
public static void main(String[] args) throws IOException {
File file=new File("D:\\测试文夹\\aa.txt");
if (!file.getParentFile().exists())
{
file.getParentFile().mkdir();
}
String msg="要和旧的人一起体验新的事物,而不是和新的人体验旧事物\n";
Writer writer=new FileWriter(file,true);
writer.write(msg);
writer.close();
}
}
2.4字符输入流
Reader依然也是一个抽象类。如果要进行文件读取,同样的,使用FileReader。
在上面讲到的Writer类中提供有方法直接向目标源写入字符串,而在Reader类中没有方法可以直接读取字符串类 型,这个时候只能通过字符数组进行读取操作.
范例:
package JavaIO;
//字符流:字符流适合处理中文,字节流适合处理一切数据类型(对中文支持不好)
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
public class Readerdemo {
public static void main(String[] args) throws Exception{
// 1.定义文件路径
File file=new File("D:\\测试文夹\\aa.txt");
// 2.必须保证文件存在才能进行处理
if (file.exists()) {
Reader in = new FileReader(file) ;
char[] data = new char[1024] ;
int len = in.read(data) ; // 将数据读取到字符数组中
String result = new String(data, 0, len) ;
System.out.println("读取内容:\n"+result+"") ;
in.close();
}
}
}
总结:
通过上述这一系列流的讲解可以发现,使用字节流和字符流从代码形式上区别不大。但是如果从实际开发来讲,字节流一定是优先考虑的,只有在处理中文时才会考虑字符流。因为所有的字符都需要通过内存缓冲来进行处理。所有字符流的操作,无论是写入还是输出,数据都先保存在缓存中。