如果希望在程序中操作文件和目录,都可以通过File完成,其能新建、删除、重命名文件和目录,但是不能访问文件内容。
https://www.runoob.com/java/java-file.html
File类中的list()方法可以接受一个FilenameFilter参数,通过该参数可以只列出符合条件的文件。
FilenameFilter接口包含一个accept(File dir,String name)方法,该方法一次对指定File的所有子目录或文件进行迭代,如果该方法返回true,list()方法会列出该子目录或文件。
//用的lambda表达式new的FilenameFilter File file = new File("."); String[] nameList = file.list( (dir,name) -> name.endsWith(".java")||name.endsWith(".iml") || new File(name).isDirectory() ); for(String name : nameList){ System.out.println(name); }
上面用Lambda表达式实现了FilenameFilter接口,该接口内只有一个抽象方法accept(),是一个函数式接口;等同于如下代码:
static class filter implements FilenameFilter{ @Override public boolean accept(File dir, String name) { if(name.endsWith(".java")||name.endsWith(".iml") || new File(name).isDirectory()){ return true; } return false; } } public static void main(String args[]) { File file = new File("."); System.out.println(file.getAbsolutePath()); filter f = new filter(); String[] nameList = file.list(f); for(String name : nameList){ System.out.println(name); } }
所有的IO流设计的类都是从InputStream和OutputStream,Reader和Writer这几个类派生的;JAVA的流能分为以下几种:
输入流:只能从中读取数据,不能向里面写;
输出流:只能向里面写数据,不能从里面读;
用法几乎一样,区别在于字节流操作的数据单元是8位的字节,字符流是16位的字符;
字节流主要由InputStream和OutputStream作为基类,字符流主要由Reader和Writer作为基类;
从/向一个特定的IO设备进行读/写的流,称为节点流,节点流也被称为低级流;
处理流用于对一个已存在的流进行封装,通过封装后的流实现数据读/写功能。也被称为高级流;
使用处理流时,程序并不会直接连接到实际的数据源,使用数据流,程序可以使用完全相同的输入输出代码访问不同数据源。
int read();读取单个字节;
int read(byte[] b);读取最多b.length个字节的数据,并将其存储在字节数组b中;
int read(byte[] b,int off,int len)读取最多len个字节的数据,并将其存储在字节数组b中,从off位置开始放;
void mark(int readAheadLimit)在记录指针当前位置放一个标记
boolean markSupported();判断该输入流是否支持mark()操作
void reset();记录指针定位到上次mark位置
long skip(long n);记录指针向前移动n个字节/字符
类似,就把read换成write,用法相反,前面是读,这里是写
一般使用处理流来包装结点流,程序通过处理流来执行输入输出,让节点流与底层IO设备和文件交互。
只要一个流的构造参数不是物理节点而是已经存在的流,那么这个流就一定是处理流。
FileOutputStream fos = new FileOutputStream("a.txt"); PrintStream printStream = new PrintStream(fos);
转换流(InputStreamReader和OutputStreamReader)用于实现将字节流转换成字符流,
InputStreamReader reader = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(reader); String line = null; while ((line=br.readLine())!=null){ if(line.equals("00")){ System.exit(1); } else { System.out.println(line); }
PushbackInputStream和PushbackReader
void read(int buf);把一个字节或字符内容退回缓冲区,从而允许重复读取刚刚读取的内容;
void read(byte[]/char[] b);把一个字节或字符数组的内容退回缓冲区,从而允许重复读取刚刚读取的内容;
void read(byte[]/char[] b,int off,int len),把一个字节或字符数组中,从off开始长度为len的字符的内容退回缓冲区,从而允许重复读取刚刚读取的内容;
JAVA标准输入输出分别通过System.in和System.out代表键盘和显示器,System提供三个方法重定向输入输出,(重定向后,System.out.print从原本的键盘和显示器读写,变成了你指定的文件或其他东西)
setErr(PrintStream)重定向错误输出流
setIn(InputStream)重定向输入流
setOut(PrintStream)重定向输出流
PrintStream printStream = new PrintStream("a.txt"); System.setOut(printStream); System.out.println("输出一个字符串");
使用Runtime对象的exec()对象可运行平台上其他程序,该方法返回一个Process对象,代表该JAVA程序启动的子进程,可通过Process对象让程序和子进程进行通信;
InputStream getErrorStream();获取子进程的错误流;
InputStream getInputStream();获取子进程的输入流;
OutputStream getOutputStream();获取子进程的输出流;
Process p = Runtime.getRuntime().exec("javac"); try( BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream())) ) { String buff =null; while ((buff = br.readLine())!=null){ System.out.println(buff); } }
该类提供了众多方法来访问文件内容,可以随机读取文件内容,也可以向文件输出数据(特点在于可以直接跳转到文件的任意地方读写数据);
但是它只能读写文件,不能读写其他IO节点;
通过以下两个方法操纵指针:
long getFilePointer();返回文件记录指针的当前位置;
void seek( long pos );把文件记录指针定位到当前位置;
同时RandomAccessFile也能使用三个read和三个write方法;
上面传统的输入输出流都可能会阻塞线程,而且都是通过字节的移动来处理的,也就是说,面向流的输入输出都是系统一次只能处理一个字节,效率不高,从JDK1.4开始,JAVA提供了一系列改进的输入输出新功能,被放在java.nio包下;
NIO和传统IO都用于进行输入输出,但是NIO采用内存映射文件的方式来处理输入输出,NIO将文件或文件的一段区域隐射到内存之中,由此可以向访问内存一样去访问文件;
JAVA中NIO相关的包如下:
java.nio;主要包含各种与Buffer相关的类
java.nio.channels;主要包含与Channel和Selector相关的类
java.nio.charest;主要包含与字符集相关的类
java.nio.channels.spi;主要包含与Channels相关的服务提供者编程接口
java.nio.charest.spi;包含与字符集相关的服务提供者编程接口
Channel(通道)和Buffer(缓冲)是NIO中的两个核心对象,Channel是对传统的输入输出系统的模拟,新IO系统中所有数据都要通过通道传输;Channel与系统的InputStream、OutputStream最大区别在于它提供了一个map()方法,通过该方法可以直接把一块数据映射到内存中。
Buffer类似一个容器,它的本质是一个数组,发送到Channel中的所有对象都必须先放到Buffer中,而从Channel读取的数据也要先放到Buffer中。
Charest类:用于将Unicode字符创映射成字节序列以及逆映射
Selector类:用于支持非阻塞式输入输出;
一般用下面函数得到一个Buffer对象:
static XXXBuffer allocate(int capacity);创建一个容量为capacity的XXbuffer对象;
Buffer有三个重要概念:
capacity - 缓冲区大小,缓冲区一旦创建出来以后,这个属性就不会再变化了。
position - 读写数据的定位指针,用来指明下一个可以被读写的缓冲区位置索引。
limit - 读写的边界,第一个不应该被读出或写入的缓冲区位置索引。位于其后的数据不能被读或写。
同时Buffer也支持mark;
Buffer主要作用就是装数据,,开始时position为0,limit为capacity,当往里面通过put()填数据的时候,position相应的向后移,装入数据结束后,调用filp()方法,该方法将limit设置为position所在位置,position设置为0;输出数据结束后,调用clear()方法,不清空数据,只是将position设为0;limit设为capacity;
一般用put()和get()来访问数据
CharBuffer charBuffer = CharBuffer.allocate(8); charBuffer.put('a'); charBuffer.put('c'); charBuffer.put('b'); System.out.println(charBuffer.get()); charBuffer.flip(); System.out.println(charBuffer.get(0)); charBuffer.clear(); System.out.println(charBuffer.get(0));
Channel类似于传统的流对象,但有两个区别:
Channel可直接将指定文件的部分或全部直接映射成Buffer。
程序不能直接访问Channel中的数据,Channel只能与Buffer进行交互。
Channel分很多种,Pipe.SinkChannel、Pipe.SourceChannel是用于支持线程通信的管道Channel,SeverSockerChannel、SocketChannel是用于支持TCP通信的Channel等,本节主要使用FileChannel;
所有的Channel都不应该使用构造器直接创建,而是通过传统的节点InputStream、OutputStream的geChannel()方法获得;
Channel最常用的方法有:
map():用于将Channel对应的数据映射成ByteBuffer;
read()和write()由一系列重载,用于读写数据;
File f = new File("D:\\JAVA_Project\\a1\\src\\IO\\NIO.java"); FileChannel inc = new FileInputStream(f).getChannel(); FileChannel outc = new FileOutputStream("channel.txt").getChannel(); MappedByteBuffer buffer = inc.map(FileChannel.MapMode.READ_ONLY,0,f.length()); //使用GBK字符集创建解码器 Charset charset = Charset.forName("GBK"); outc.write(buffer); buffer.clear(); //使用解码器将ByteBuffer转换成CharBuffer CharsetDecoder decoder = Charset.defaultCharset().newDecoder(); CharBuffer charBuffer =decoder.decode(buffer); System.out.println(charBuffer);
JAVA默认使用Unicode字符集,但很多操作系统不实用Unicode字符集,则从系统中读取数据到JAVA程序中时可能乱码;
Charest用于处理字节序列和字符序列直接的转换关系;
可通过如下方式获得Charest对象
Charset charset = Charset.forName("GBK"); Charset charset1 = Charset.forName("UTF-8");
然后获得编码解码对象:
CharsetDecoder decoder = Charset.defaultCharset().newDecoder(); CharsetEncoder encoder = Charset.defaultCharset().newEncoder();
之后通过encode()和decode()方法转换;
可以使用FileLock防止多个程序并发操作同一个文件
lock():试图锁定某个文件时,如果无法得到锁,会堵塞下去;
tryLock():尝试锁定文件,得到就会返回文件锁,否则返回Null;
JAVA7对NIO进行的改进
早期的File类功能有限,性能也不高,大多数方法出错时也不会提供异常信息
NIO.2引入的Path接口,代表一个平台无关的平台路径,此外NIO.2还提供了Files(提供大量静态的操作文件的方法)、Paths(包含两个返回Path的静态工厂方法)两个工具类;
https://www.cnblogs.com/codderYouzg/p/12418878.html
File提供下面两个方法遍历文件和子目录
WalkFileTree(Path start,FileVisitor<? super Path > visitor);遍历start路径下的所有文件和子目录;
WalkFileTree(Path start,Set< FileVisitOption >options,int maxDepth ,FileVisitor<? super Path > visitor);类似,最多遍历maxDepth深度的文件;
两个方法都需要FileVisitor参数,可通过重写下面四个方法自定义FileVisitor
FileVisitResult主要包含四个常见的操作。
FileVisitResult.CONTINUE 继续遍历
FileVisitResult.TERMINATE 中止访问
FileVisitResult.SKIP_SIBLINGS 不访问同级的文件或目录
FileVisitResult.SKIP_SUBTREE 不访问子目录
FileAttributeView:代表某种文件属性的“视图”;
FileAttributes:代表某种文件属性的“集合”,一般通过FileAttributeView获取