文章目录
类图
引自(https://blog.youkuaiyun.com/jeryjeryjery/article/details/72236643)
File类
file类既能代表一个特定文件的名称,又能代表一个目录下一组文件的名称,可用list()方法返回一个字符数组,即文件名的集合;
File files = new File(".");
String[] list;
list = files.list();
for(String name : list){
log.info(name);
}
文件名过滤FilenameFilter
FilenameFilter是一个接口,声明了accept(File var1, String var2)方法;
File files = new File(".");
String[] list;
if(args.length == 0){
list = files.list(new FilenameFilter() {
@Override
public boolean accept(File file, String s) {
return s.indexOf("xml")>=0;
}
});
}else{
list = files.list(new FileTest(args[0]));
}
for(String name : list){
log.info(name);
}
输出如下:
list()方法以实现FilenameFilter接口的类做参数,可以实现文件名称的过滤;
文件属性、检查、创建
文件各种属性的获取
public void getFile(){
File file = new File("E:\\file\\test.txt");
System.out.println("getAbsolutePath--" + file.getAbsolutePath()); //文件绝对路径
System.out.println("canRead--" + file.canRead()); //是否可读
System.out.println("canWrite--" + file.canWrite()); //是否可写
System.out.println("getName--" + file.getName()); //文件名称
System.out.println("getParent--" + f`在这里插入代码片`ile.getParent()); //文件父节点
System.out.println("getPath--" + file.getPath()); //路径
System.out.println("length--" + file.length()); //文件大小,字节数
System.out.println("lastModified--" + file.lastModified()); //文件修改时间
}
输出如下:
文件是否存在以及文件的创建
public void createFile(){
File file = new File("E:\\file\\data");
if(!file.exists()){
System.out.println("file not exit!");
//创建目录,可创建多级目录
file.mkdirs();
try {
file = new File("E:\\file\\data\\test.txt");
//创建文件
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("file is created!");
}else{
System.out.println("file already exit!");
}
}
文件名称的修改、删除
@Test
public void updateFile(){
File file = new File("E:\\file\\test.txt");
if(file.exists()){
//修改文件名称
file.renameTo(new File("E:\\file\\test1.txt"));
}
File file1 = new File("E:\\file\\data.txt");
if(file1.exists()){
//文件删除
file1.delete();
}
}
输入和输出
流代表右能力产生数据的数据源对象或者有能力接收数据的接收端对象,流屏蔽了实际的I/O设备中处理数据的细节。任何由InputStream或Reader派生而来的类都含有read()方法,用于读取单个字节或字节数组,任何由OutputStream或Writer派生而来的类都有writer()方法,用于写单个字节或者字节数组;创建单一的结果流需要创建多个对象。
InputStream类
InputStream表示从不同数据源产生输入的类,这些数据源包括:
1、字节数组
2、String对象
3、文件
4、管道,工作方式与实际管道相似,一端输入,另一端输出
5、由其他种类的流组成的序列,以便将他们收集合并到一个流内
6、其他数据源,如Internet连接等
InputStream相关子类
类 | 功能 | 如何使用 | 构造器 |
---|---|---|---|
ByteArrayInputStream | 允许将内存的缓冲区当作InputStream使用 | 作为一种数据源:将其与FilterInputStream对象连接已提供有用的接口 | 缓冲区,字节从中取出; |
StringBufferInputStream | 将String转换为成InputStream | 作为一种数据源:将其与FilterInputStream对象连接已提供有用的接口 | 字符串,底层实现使用StringBuffer; |
FileInputStream | 用于从文件中读取信息 | 作为一种数据源:将其与FilterInputStream对象连接已提供有用的接口 | 字符串,表示文件名、文件或FileDescriptor对象 |
PipedInputStream | 产生用于写入相关PipedOutputStream的数据,实现管道化概念 | 作为多线程中的数据源:将其与FilterInputStream对象连接已提供有用的接口 | PipedOutputStream |
SequenceInputStream | 将多个InputStream对象转换成单一InputStream | 作为一种数据源:将其与FilterInputStream对象连接已提供有用的接口 | 两个InputStream或一个容纳InputStream对象的容器Enumeration |
FilterInputStream | 抽象类,作为装饰器的接口,装饰器为其他继承InputStream的类提供有用功能 |
ByteArrayInputStream
字段:
protected byte[] buf; //保存字节输入流数据的字节数组
protected int pos; //读取下一个字节的索引,由0到count
protected int mark = 0; //标记索引,可通过mark()和reset()方法进行设置
protected int count; //字节流的长度
构造方法:
//接收字节数组
public ByteArrayInputStream(byte[] var1) {
this.buf = var1;
this.pos = 0;
this.count = var1.length;
}
//接收字节数组, var2读取数组索引起始位置,var2为从索引读取字节的长度
public ByteArrayInputStream(byte[] var1, int var2, int var3) {
this.buf = var1;
this.pos = var2;
this.count = Math.min(var2 + var3, var1.length);
this.mark = var2;
}
内部方法:
public synchronized int read(); //读取下一个字节,如果已经读取完,将会返回-1
//读取字节数组,由0开始,读取var3个字节,var1的长度为var2 + var3.
public synchronized int read(byte[] var1, int var2, int var3);
public synchronized long skip(long var1);//跳过字节流中var1个字节
public synchronized int available();//剩余可读字节数量
public boolean markSupported();//是否支持mark()和reset()
public void mark(int var1);//标记当前的位置
public synchronized void reset();//将缓冲区的位置重置到mark标记的位置
public void close(); //关闭流
测试方法:
@Test
public void readData(){
byte[] data = "0123456789".getBytes();
ByteArrayInputStream input = new ByteArrayInputStream(data);
byte[] bytes = new byte[6];
input.read(bytes,4,2);
input.skip(1);
System.out.println("剩余长度:" + input.available());
for(byte b: bytes){
System.out.print((char)b);
}
int i;
System.out.println();
while((i = input.read()) != -1){
System.out.print((char)i);
if('7'== (char)i){
input.mark(5);
}
}
System.out.println();
input.reset();
System.out.println((char)input.read());
}
输出:
StringBufferInputStream类(已过时)
字段:
protected String buffer; //读取的字符串
protected int pos; //下一个被读取的字符的索引
protected int count; //输入流中的有效字符数
构造方法:
public StringBufferInputStream(String var1) {
this.buffer = var1;
this.count = var1.length();
}
公开方法:
public synchronized int read(); //读取一个字节
//将var3个字符读取到var1中,在var1中从var2开始
public synchronized int read(byte[] var1, int var2, int var3);
public synchronized long skip(long var1); //跳过var1个字符
public synchronized int available(); //返回剩余可读字符数量
public synchronized void reset(); //重置索引
测试方法:
@Test
public void readData(){
StringBufferInputStream input = new StringBufferInputStream("123456");
int i;
byte[] bytes = new byte[10];
input.read(bytes, 1, 3);
for(byte b : bytes){
System.out.print((char)b);
}
input.skip(1);
System.out.println();
System.out.println("剩余字符数:" + input.available());
while((i = input.read()) != -1){
System.out.print((char)i);
}
}
输出:
FileInputStream类
字段:
private final FileDescriptor fd; //文件描述类,处理打开的文件
private final String path; //路径
private FileChannel channel; //文件通道
private final Object closeLock; //关闭锁,确保多线程中同步调用
private volatile boolean closed; //输入流是否关闭状态
构造函数:
// 文件路径创建File对象,并调用下边的重载的构造函数
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
// 根据File对象来构造文件输入流
public FileInputStream(File file) throws FileNotFoundException {
// 获取文件路径
String name = (file != null ? file.getPath() : null);
// 获取系统的安全管理器
SecurityManager security = System.getSecurityManager();
if (security != null) {
// 确保有文件的读取权限
security.checkRead(name);
}
if (name == null) {
// 文件路径为null,抛出空指针异常
throw new NullPointerException();
}
if (file.isInvalid()) {
// 如果file对象无效,抛出未找到文件异常
throw new FileNotFoundException("Invalid file path");
}
// 创建文件描述符
fd = new FileDescriptor();
// 在文件描述符中保存该对象引用
fd.attach(this);
// 路径名赋值path
path = name;
// 打开该路径进行读取
open(name);
}
// 根据文件描述符构造输入流
public FileInputStream(FileDescriptor fdObj) {
SecurityManager security = System.getSecurityManager();
if (fdObj == null) {
throw new NullPointerException();
}
if (security != null) {
security.checkRead(fdObj);
}
// 文件描述符对象属性的赋值
fd = fdObj;
path = null;
// 在文件描述符中保存该对象引用
fd.attach(this);
}
方法:
// 调用open0(name)本地方法,打开指定的文件以进行读取
private void open(String name) throws FileNotFoundException {
open0(name);
}
//打开指定的文件以进行读取
private native void open0(String name) throws FileNotFoundException;
// 从输入流中读取下一个字节的数据,调用本地方法
// 该方法一直阻塞直到有可用的数据
public int read() throws IOException {
return read0();
}
// 本地方法,读取下一个字节的数据
private native int read0() throws IOException;
// 读取b.length数量的字节,并从字节数组b的0下标开始填满b数组
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
// 读取b.length数量的字节,并从字节数组b的off下标位置开始填满b数组
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
// 本地方法,将子数组作为字节序列读取
private native int readBytes(byte b[], int off, int len) throws IOException;
// 本地方法,跳过n个字节
public native long skip(long n) throws IOException;
// 本地方法,返回可读的字节数
public native int available() throws IOException;
public void close() throws IOException {
// 使用对象锁
synchronized (closeLock) {
// 如果流已经关闭则返回
if (closed) {
return;
}
// 否则将关闭状态设为true
closed = true;
}
// 操作文件的通道不为空,也要进行关闭
if (channel != null) {
channel.close();
}
// 文件描述符相关资源的关闭,并调用本地关闭方法关闭流
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
//本地方法,关闭此文件输入流并释放与该流关联的所有系统资源
private native void close0() throws IOException;
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) {
// 如果fd正在被其他流使用,就不能进行关闭,只有当所有流都不再引用这个文件描述符才关闭
close();
}
}
方法测试:
@Test
public void writeData() throws IOException {
FileInputStream in = new FileInputStream("E:\\file\\test1.txt");
int i;
byte[] bytes = new byte[8];
in.read(bytes, 3, 4);
for(byte b : bytes){
System.out.print((char)b);
}
System.out.println();
System.out.println("剩余字节数:" + in.available());
while((i = in.read()) != -1){
System.out.print((char)i);
}
}
输出:
SequenceInputStream类
将多个流合并,依次读取;
构造方法:
//var1为流的集合
public SequenceInputStream(Enumeration<? extends InputStream> var1) {
this.e = var1;
try {
this.nextStream();
} catch (IOException var3) {
throw new Error("panic");
}
}
public SequenceInputStream(InputStream var1, InputStream var2) {
Vector var3 = new Vector(2);
var3.addElement(var1);
var3.addElement(var2);
this.e = var3.elements();
try {
this.nextStream();
} catch (IOException var5) {
throw new Error("panic");
}
}
方法测试:
@Test
public void readData() throws IOException {
FileInputStream in1 = new FileInputStream("E:\\file\\test1.txt");
FileInputStream in2 = new FileInputStream("E:\\file\\test2.txt");
Vector<FileInputStream> vector = new Vector();
vector.addElement(in1);
vector.addElement(in2);
SequenceInputStream input = new SequenceInputStream(vector.elements());
int i;
while ((i = input.read()) > 0){
System.out.print((char)i);
}
}
OutputStream类
OutputStream或继承该类的类决定了输出所要去往的目标:字节数组(不是String)、文件或管道。此外FilterOutputStream为装饰器类提供了一个基类,装饰器类把属性或者有用的接口与输出流连接了起来;
OutputStream相关子类
类 | 功能 | 如何使用 | 构造器 |
---|---|---|---|
ByteArrayOutputStream | 在内存中创建缓冲区,所有送往流的数据都要放置在次缓冲区 | 用于指定数据的目的地将其与FilterOutputStream对象连接以提供有用接口 | 缓冲区初始化尺寸(可不填,有默认值) |
FileOutputStream | 用于将信息写至文件 | 用于指定数据的目的地将其与FilterOutputStream对象连接以提供有用接口 | 字符串,表示文件名、文件或者FileDescription对象 |
PipedOutputStream | 任何写入其中的信息都会作为相关PipedInputStream的输出,实现管道化概念 | 用于指定多线程数据的目的地将其与FilterOutputStream对象连接以提供有用接口 | 字符串,表示文件名、文件或者FileDescription对象 |
FilterOutputStream | 抽象类,作为装饰器的接口,装饰器为其他继承OutputStream类的类提供功能 |
ByteArrayOutputStream
ByteArrayOutputStream对byte数据类型进行写入,相当于一个中间缓冲层,将类写入到文件或其他OutputStream,对字节进行操作,相当于内存操作流。
字段:
protected byte[] buf;//存储数据的数组
protected int count; //计数器,表示数据个数
private static final int MAX_ARRAY_SIZE = 2147483639; //数组最大值
构造器:
//默认数组初始化大小为32
public ByteArrayOutputStream() {
this(32);
}
public ByteArrayOutputStream(int var1) {
if (var1 < 0) {
throw new IllegalArgumentException("Negative initial size: " + var1);
} else {
this.buf = new byte[var1];
}
}
私有方法:
private void ensureCapacity(int var1); //扩容方法
private void grow(int var1); //扩容方法
private static int hugeCapacity(int var0); 扩容方法
公共方法:
public synchronized void write(int var1); //将var1写入byte数组输出流
//将var1数组从var2开始的var3个字节写入输出流
public synchronized void write(byte[] var1, int var2, int var3);
public synchronized void writeTo(OutputStream var1);//将输出流的全部内容写入var1
public synchronized void reset(); //将count字段置为0
public synchronized byte[] toByteArray(); //返回缓冲区中的有效内容
public synchronized int size(); //缓冲区的当前大小
public void close(); //关闭输出流
FileOutputStream类
字段:
private final FileDescriptor fd; //文件描述类,处理打开的文件
private final boolean append; //是否在原有文件上拼接,默认为覆盖原有文件
private final String path; //路径
private FileChannel channel; //文件通道
private final Object closeLock; //关闭锁,确保多线程中同步调用
private volatile boolean closed; //输入流是否关闭状态
构造方法:
public FileOutputStream(String var1); //var1为路径
public FileOutputStream(String var1, boolean var2); //var1为路径,var2为是否拼接
public FileOutputStream(File var1); //var1为文件
public FileOutputStream(File var1, boolean var2); //var1为文件,var2为是否拼接
public FileOutputStream(FileDescriptor var1);
写入方法:
public void write(int var1); //写入一个字符
public void write(byte[] var1); //写入一个字符数组
//将var1从var2位,截取var3长度,写入
public void write(byte[] var1, int var2, int var3);
方法测试:
@Test
public void writeData() throws IOException {
FileOutputStream output = new FileOutputStream("E:\\file\\test.txt");
byte[] data = "123456789".getBytes();
output.write(data);
output.write("\n".getBytes());
output.write(data, 2, 3);
output.close();
}
输出:
FilterInputStream类与FilterOutputStream类
装饰者模式与继承:
将原有的基础流进行装饰,装饰后的方法要与原先被装饰的基础类保持一致,也可以对基础流进行扩展,而继承是继承父类的属性和方法,也可以起到装饰作用,比如重写父类的一些方法,区别是装饰者模式可以动态的扩展一个对象,给对象添加额外的功能,而不会与被装饰者产生耦合;装饰者模式的意义就在于没有那么多繁杂的类,类与类之间的耦合性降低。具体实现就是将提出一个类FilterInputStream,而其子类就是各个功能的实现类.如果想要基础输入流要某个功能,那么就可以将对应的基础输入流传到对应的子类构造方法中。
DataInputStream读取不同的基本类型数据以及String对象,其他类型在内部修改InputStream的行为方式:是否缓冲,是否保留行数,是否把单一字符推回输入流等
FilterInputStream相关子类
类 | 功能 | 如何使用 | 构造器 |
---|---|---|---|
DataInputStream | 与DataOutputStream搭配使用,可以按照可移植方式从流读取基本数据类型 | 包含用于读取基本类型数据的全部接口 | InputStream |
BufferedInputStream | 防止每次读取时都得进行实际写操作,代表使用缓冲区 | 本质上不提供接口是向进程中添加缓冲区,与接口对象搭配 | InputStream, 可指定缓冲区大小 |
LineNumberInputStream | 跟踪输入流中的行号,可调用getLineNumber()和setLineNumber(int line) | 增加了行号,要与接口对象搭配使用 | InputStream |
PushbackInputStream | 能弹出一个字节的缓冲区,可以将读到的最后一个字符退回 | 通常作为编译器的扫描器,之所以包含在内,是因为Java编译器的需要,用到的地方较少 | InputStream |
DataInputStream对应的是DataOutputStream,可以将各种数据类型以及String对象格式化输出到流中,任何机器上的任何DataInputStream都能读取他们;BufferedOutputStream是一个修改过的OutputStream,它对数据流使用缓冲技术,每次数据写入时,不必都执行实际的物理写动作。
FilterOutputStream相关子类
类 | 功能 | 如何使用 | 构造器 |
---|---|---|---|
DataOutputStream | 与DataInputStream搭配使用,可以按照可移植方式向流中写入基本数据类型 | 包含用于写入基本类型数据的全部接口 | OutpPutStream |
BufferedOutputStream | 防止每次读取时都得进行实际写操作,代表使用缓冲区 ,可调用flush()清空缓冲区 | 本质上不提供接口是向进程中添加缓冲区,与接口对象搭配 | OutpPutStream, 可指定缓冲区大小 |
PrintStream | 用于产生格式化输出,其中DataOutputStream处理数据的存储,PrintStream处理显示 | 可以用boolean值指示是否在换行时清空缓冲区,是对OutputStream的final封装 | OutpPutStream |
DataOutputStream与DataInputStream类
方法测试:
@Test
public void readData() throws IOException {
DataOutputStream out = new DataOutputStream(new FileOutputStream("E:\\file\\test.txt"));
DataInputStream in = new DataInputStream(new FileInputStream("E:\\file\\test.txt"));
out.write(1);
System.out.println(in.read());
out.close();
in.close();
out = new DataOutputStream(new FileOutputStream("E:\\file\\test.txt"));
in = new DataInputStream(new FileInputStream("E:\\file\\test.txt"));
out.writeInt(2);
System.out.println(in.readInt());
out.close();
in.close();
out = new DataOutputStream(new FileOutputStream("E:\\file\\test.txt"));
in = new DataInputStream(new FileInputStream("E:\\file\\test.txt"));
out.writeDouble(1.23);
System.out.println(in.readDouble());
out.close();
in.close();
out = new DataOutputStream(new FileOutputStream("E:\\file\\test.txt"));
in = new DataInputStream(new FileInputStream("E:\\file\\test.txt"));
out.writeBoolean(true);
System.out.println(in.readBoolean());
out.close();
in.close();
out = new DataOutputStream(new FileOutputStream("E:\\file\\test.txt"));
in = new DataInputStream(new FileInputStream("E:\\file\\test.txt"));
out.writeBytes("szz");
int i;
while ((i = in.read()) != -1){
System.out.print((char)i);
}
out.close();
in.close();
}
输出:
BufferedInputStream与BufferedOutputStream类
方法测试:
@Test
public void bufferedStreamTest() throws IOException {
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("E:\\file\\test.txt"));
BufferedInputStream in = new BufferedInputStream(new FileInputStream("E:\\file\\test.txt"));
out.write("szz".getBytes());
out.flush();
int i;
while ((i = in.read()) > -1){
System.out.print((char)i);
}
}
LineNumberInputStream类(已弃用)
测试方法:
@Test
public void readData() throws IOException {
LineNumberInputStream input = new LineNumberInputStream(new FileInputStream("E:\\file\\test.txt"));
input.setLineNumber(3);
while (input.getLineNumber() <= 3){
System.out.print((char)input.read());
}
}
输出结果:
PushbackInputStream类
字段:
protected byte[] buf; //推回缓冲区的字节数组
protected int pos; //推回缓冲区中的位置,从该位置读取下一个字节
构造方法:
public PushbackInputStream(InputStream var1)
public PushbackInputStream(InputStream var1, int var2) //var3为推回字节数组的最大长度
推回方法:
public void unread(int var1) //推回字节
public void unread(byte[] var1) //推回字节数组
public void unread(byte[] var1, int var2, int var3) //推回字节数组,从第var2位开始,推回var3个字节
测试方法:
@Test
public void readData() throws IOException {
PushbackInputStream push = new PushbackInputStream(new FileInputStream("E:\\file\\test.txt"));
int i;
while ((i = push.read()) > -1){
System.out.print((char)i);
if(i == '0'){
push.unread('a');
}
}
System.out.println();
push = new PushbackInputStream(new FileInputStream("E:\\file\\test.txt"), 4);
byte[] bytes = new byte[4];
while (push.read(bytes) > -1){
for(byte b : bytes){
System.out.print((char)b);
if(b == '1'){
push.unread("abc".getBytes(), 1, 2);
}
}
bytes = new byte[4];
}
}
输出:
Reader和Writer类
Reader和Writer主要是为了国际化,老IO流继承结构仅支持8为字节流,而Reader和Writer可以很好的处理16位Unicode字符。
java1.0类 | 对应的Java1.1类 |
---|---|
InputStream | Reader,适配器:InputStreamReader |
OutputStream | Writer,适配器:OutputStreamReader |
FileInputStream | FileReader |
FileOutputStream | FileWriter |
StringBufferInputStream(已弃用) | StringReader |
无相应的类 | StringWriter |
ByteArrayInputStream | CharArrayReader |
ByteArrayOutputStream | CharArrayWriter |
PipedInputStream | PipedReader |
PipedOutputStream | PipedWriter |
对应的装饰器类
java1.0类 | 对应的Java1.1类 |
---|---|
FilterInputStream | FilterReader |
FilterOutputStream | FilterWriter(抽象类,没有子类) |
BufferedInputStream | BufferedReader(也有readLine()) |
BufferedOutputStream | BufferedWriter |
DataInputStream | DataInputStream,若用readLine()时,可用BufferedReader |
PrintStream | PrintWriter |
LineNumberInputStream(已弃用) | LineNumberReader |
StreamTokenizer | StreamTokenizer(使用接收Reader的构造器) |
PushbackInputStream | PushbackReader |
未发生变化的类:DataInputStream,File,RandomAccessFile,SequenceInputStream
RandomAccessFile类
RandomAccessFile适用于由大小已知的记录组成的文件,可以用seek()将记录从一处转移到另一处,然后读取或者修改记录;其除了实现了DataInput和DataOutput接口外,和InputStream与OutputStream继承层次结构没有任何关联,是一个完全独立的类,从Object派生而来;
从本质上来说,RandomAccessFile的工作方式类似于把DataInputStream与DataOutputStream组合起来使用,还添加了一些方法,getFilePointer()用于查找当前所处的文件位置,seek()用于在文件中移至新的位置,length()用于判断文件的最大尺寸;只有RandomAccessFile支持搜寻方法,并且只适用于文件。
构造方法:
//va1为文件路径,var2为模式,取值r, rw, rws, rwd
//r:只读方式打开,调用write方法会抛出IOException异常
//rw:读写方式打开,文件不存在则创建文件
//rws:读写方式打开,要求文件的内容或元数据的每个更新都同步写入到底层存储设备
//rwd:读写方式打开,要求文件的内容的每个更新都同步写入到底层存储设备
public RandomAccessFile(String var1, String var2)
public RandomAccessFile(File var1, String var2)
主要方法:
public native long getFilePointer() //返回当前偏移量
public final void writeChars(String var1) //将字符串写入
public final void writeUTF(String var1)//以UTF-8编码写入
方法测试:
@Test
public void readData() throws IOException {
RandomAccessFile file = new RandomAccessFile("E:\\file\\test.txt", "rw");
System.out.println(file.length());
String s;
while (!StringUtils.isEmpty(s=file.readLine())){
System.out.println(s);
}
file.writeBytes("szz4");
file.writeUTF("szz5");
}
输出: