第六节 Java I/O流
1. I/O流概述
1.1 字节流和字符流
按照流操作的数据单位的不同,分为字节流和字符流。字节流以字节为单位进行数据的读写,每次读写一个或多个字节数据;字符流以字符为单位进行数据的读写,每次读写一个或者多个字符数据。
1.2 输入流和输出流
根据流的传输方向不同,分为输入和输出流,输入流只能从流中读取数据,输出流只能向流中写如数据。
1.3 节点流和处理流
节点流是指它只能直接连接数据源,进行数据的读写操作;处理流它用于对一个已存在的节点流进行连接和封装,通过封装后的流来实现流的读写能力。程序不会直接连接到实际的数据源。
1.4 I/O 框架如下
2. 字节流
计算机中无论文本、图片、音频、视频所有文件都是以二进制(字节)形式存在的。它有两个顶级父类InputStream输入流和OutputStream输出流,他两个是抽象类。所有处理字节的输入输出流都继承它们。
InputStream的常用方法:
方法声明 | 功能描述 |
---|---|
int read() | 从输入流中读取一个8位的字节,把它转换位0~255之间的整数,并返回这一整数。当没有可用字节时,将返回-1 |
int read(byte[ ] b | 从输入流中读取若干字节,把他们保存到参数b指定的字节数组中,返回的整数表示读取字节的数目 |
int read(byte[ ] b,int off, int len ) | 从输入流中读取若干字节,把他们保存到参数b指定的字节数组中,off指定字节数组开始保存数据的起始下标,len表示读取的 字节数目 |
void close() | 关闭此输入流并释放与该流关联的所有系统资源 |
OutputStream的常用方法:
方法声明 | 功能描述 |
---|---|
void write(int b) | 向输出流写入一个字节 |
void write(byte[ ] b) | 把参数b指定的字节数组的所有字节写到输出流 |
void write(byte[ ] b,int off ,int len) | 将指定byte数组从偏移量off开始的len个字节写入输出流 |
void flush() | 刷新此输出流并强制写出所有缓冲的输出字节 |
void close() | 关闭输出流,释放资源 |
由于上面两个都是字节流的顶级类,而且是抽象类,因此我们都是用他们的子类,他们的具体子类如下:
InputStream子类:
OutputStream子类:
字节流读文件:
public class FileStreamDemo {
public static void main(String[] args) throws IOException {
//1.创建输入流
FileInputStream fis=new FileInputStream("hello.txt");
int b;
while((b=fis.read())!=-1){
System.out.print((char)b);
}
}
}
针对文件读写主要用FileInputStream和FileOutputStream。
利用上面两个流实现文件的copy:
FileInputStream fis = new FileInputStream("hello.txt");
FileOutputStream fos = new FileOutputStream("out.txt");
try {
byte[] buff = new byte[1024];
int len;
while ((len = fis.read(buff)) != -1) {
fos.write(buff);
}
}catch(IOException e){
System.out.println(e.getMessage());
} finally{
fis.close();
fos.flush();
fos.close();
}
}
}
将某个字符串写入到文件:
public class FileWriteDemo {
public static void main(String[] args) throws IOException {
//创建输出流
FileOutputStream fos=new FileOutputStream("string.txt");
String str="World";
fos.write(str.getBytes());
fos.close();
}
}
在上面我们 使用FileOutStream去写入的时候如果文件不存在会自动的进行创建,如果文件已经存在,他会清空里面内容再写入,如果我们希望我们新添加的内容加到文件原来内容后面我们可以使用FileOutputStream的构造函数FileOutputSream(String fileName,boolean append)把append设置位true。
2.1 字节流的缓冲区
我们如果一个字节读入一个字节的去写入的话效率会比较低,这时候我们可以定义一个字节数组,将这个字节数组当作缓冲区,这个缓冲区就像集装箱一样,装满了一下子就发往目的地了。这样效率就提高了很多,同时FileInputStream和FileOutputStream也提供了相关的read()和write()方法。我们在上面的文件拷贝就用到了字节缓冲。
2.2 字节缓冲流
BufferedInputStream和BufferedOutputStream这两个为字节缓冲流,他们分别为FileInputStream和FileOutputStream流的子类,他们参数接受InputStream和OutputStream类型。他们直接和应用程序相连接,他们和源文件和目标文件不直接连接,而是通过节点流来进行连接。它的底层也是由字节数字完成的。
具体的使用方法如下:
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
//创建输入和输出字节缓冲流
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("source.txt"));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("target.txt"));
int len=0;
while((len=bis.read())!=-1){
bos.write(len);
}
bis.close();
bos.close();
}
3. 字符流
字节流操作的都是字节,如果希望在程序中操作字符就会有些不方便。所以JDK就提供了字符流。字符流也有两个顶级父类一个是Reader一个是Writer。他们也有很多的子类。
Reader的常用子类:
Writer常用子类:
其中FileReader和FileWriter用来读写文件,BufferedReader和BufferWriter是具有缓冲功能的流。
FileReader和FileInputStream流的使用方法类似,FileWriter和FileOutputStream流的使用方法类似,BufferedReader和BufferedInputStream使用方法类似,但是BufferedReader中有一个重要的方法readLine()可以用于一次读取一行文本。
以下说明以下readLine()方法的使用:
public class BufferedDemo {
public static void main(String[] args) throws IOException {
BufferedReader br=new BufferedReader(new FileReader("read.txt"));
BufferedWriter bw=new BufferedWriter(new FileWriter("write.txt"));
String str=null;
while((str=br.readLine())!=null){
bw.write(str);
bw.newLine();//用于写入一个换行符
}
br.close();
bw.close();
}
}
3.1 转换流
这个是用来进行将字节流转换成字符流用的。他们分别是InputStreamReader和OutputStreamWriter
具体使用方法如下:
public class TransStreamDemo {
public static void main(String[] args) throws IOException {
//创建字节流输入流
FileInputStream in=new FileInputStream("read.txt");
//将字节流转换为字符流
InputStreamReader isr=new InputStreamReader(in);
//用字符缓冲
BufferedReader br=new BufferedReader(isr);
//创建字节输出流
FileOutputStream out=new FileOutputStream("write.txt");
//将字节输出流转换为字符输出流
OutputStreamWriter osw=new OutputStreamWriter(out);
//用字符缓冲流
BufferedWriter bw=new BufferedWriter(osw);
String str=null;
while((str=br.readLine())!=null){
bw.write(str);
bw.newLine();
}
bw.close();
br.close();
}
}
注意:这里进行转换的话一定要是文本文件不然的话数据会造成丢失。
4. File 类
这个类主要用来对文件的一些操作。File类用于封装一个路径,这个路径可以是相对路径也可以是绝对路径。
File类常用的构造方法:
方法声明 | 功能描述 |
---|---|
File(String pathname) | 通过指定字符串封装一个File对象 |
File(String parent,String child) | 根据指定的一个字符串类型的父路径和一个字符串的子路径,创建一个File对象 |
File(File parent,String child) | 根据指定的File类的父路径和字符串类型的子路径创建FIle对象 |
File的常用方法:
方法声明 | 功能描述 |
---|---|
boolean exists() | 判断File对象对应的文件或目录是否存在 |
boolean delete() | 删除File对象对应的文件目录,删除成功返回true |
boolean createNewFile() | 当File对象对应的文件不存在时,创建一个新的File对象指定的新文件,创建成功返回true |
String getName() | 返回File对象表示的文件或文件夹名称 |
String getPath() | 返回File对象对应的路径 |
String getAbsolutePath() | 返回绝对路径,在Unix/Linux系统上,以“/”开始,在Windows上绝对路径是从盘符开始 |
boolean canRead() | 判断File对象对应的文件或目录是否为可读 |
boolean canWrite() | 判断File对象对应的文件或目录是否为可写 |
String getParent() | 返回File对象对应目录的父目录(返回不包含最后一级子目录) |
boolean isFile() | 判断File对象对应的是否是文件 |
boolean isDirectory() | 判断File对象是否是目录 |
boolean isAbsolute() | 判断File对象对应的是不是绝对路径 |
long lastModified() | 返回1970年1月1日0时0分0秒到文件最后一次修改时间的毫秒值 |
long length() | 返回文件内容的长度(bytes为单位) |
String[ ] list(FilenameFilter filter) | 接受一个FilenameFilter参数,通过该参数可以只列出符合条件的文件 |
String[ ] list() | 列出指定目录的全部内容,只是列出名称 |
File[ ] listFiles() | 返回一个包含了File对象所有子文件和子目录的File数组 |
4.1 遍历目录下的文件
public class FilelistDemo {
public static void main(String[] args) {
//用File对象里面的list()方法遍历指定目录下的所有文件名称
//创建File对象
File file=new File("E:\\javaworkspace\\testproject");
//判断是否是目录
if(file.isDirectory()){
//获取目录中的所有文件名称
String[] fileNames=file.list();
Arrays.stream(fileNames).forEach(f-> System.out.println(f));
}
}
}
遍历并筛选
public class FilelistFilterDemo {
public static void main(String[] args) {
File file=new File("E:\\javaworkspace\\testproject");
if(file.isDirectory()){
//使用Lambda表达式过滤目录中所有以.txt结尾的文件名称
//利用list(FilenameFilter filter)方法去进行筛选
String[] fileNames=file.list((dir,name)->name.endsWith(".txt"));
Arrays.stream(fileNames).forEach(f-> System.out.println(f));
}
}
}
遍历指定目录下的所有文件(包括文件里面的子文件)
public class FileAllDemo {
public static void main(String[] args) {
File file = new File("E:\\javaworkspace\\testproject");
fileDir(file);
}
public static void fileDir(File file){
//获取File对象的指定目录下的所有文件
File[] filelist=file.listFiles();
//遍历
for (File files:filelist){
if (files.isDirectory()){
//递归遍历所有目录下的文件文件
fileDir(files);
}
System.out.println(files);
}
}
}
删除文件及目录
public class DeleteFileDemo {
public static void main(String[] args) {
File files=new File("E:\\images");
deleteDir(files);
}
public static void deleteDir(File files){
File[] listfiles=files.listFiles();
for(File file:listfiles){
if(file.isDirectory()){
deleteDir(file);
}
file.delete();
}
files.delete();
}
}
注意:我们利用这里面的delete删除是不走回收站的,Java虚拟机直接删除了,因此我们再删除的时候需要留意。
5. RandomAccessFile
我们前面说的IO只能按照先后顺序读取源设备中的数据,或按照数据的先后顺序顺序向目标设备写入。而RandomAccessFile对象实现了从文件的任意位置开始执行读写数据的操作,它不属于流类。它可以将文件以指定的操作权限(只读、可读写等)的方法打开。
常用构造方法:
方法声明 | 功能描述 |
---|---|
RandomAccessFile(File file String mode) | 使用参数file指定被访问的文件,并使用mode来指定访问模式 |
RandomAccessFile(String name,String mode) | 使用参数name指定被访问的路径,并使用mode来指定访问模式 |
mode有四个值:
(1)r:表示以只读模式打开文件
(2)rw:以读写的模式打开文件,不存在会自动创建该文件
(3)rws:表示以读写模式打开文件,与rw相比,它要求对文件的内容或元数据的每个更新同步都写入到底层的存储设备
(4)rwd:与rw相比,它要求对文件的内容的每个更新都同步写入到底层的存储设备
RandomAccessFile中的常用方法:
方法声明 | 功能描述 |
---|---|
long getFilePointer() | 返回当前读写指针所处的位置 |
void seek(long pos) | 设定读写指针的位置,与文件开头相隔pos个字节 |
int skipBytes(int n) | 使读写指针从当前位置开始,跳过n个字节 |
void write(byte[ ] b) | 将指定的字节数组写入到这个文件,并从当前文件指针开始 |
void setLength(long newLength) | 设置此文件的长度 |
final String readLine() | 从指定文件当前指针读取下一行内容 |
常见使用:
public class RandomAccessFileDemo {
public static void main(String[] args) throws IOException {
//创建RandomAccessFile对象
RandomAccessFile raf=new RandomAccessFile("time.txt","rw");
int time=Integer.parseInt(raf.readLine())-1;
if(time>=0){
System.out.println("你的试用次数还有"+time);
raf.seek(0);
raf.write((time+"").getBytes());
}else{
System.out.println("您的试用次数已经试用完,请充值!");
}
}
}
6. 对象序列化
我们都知道Java在运行的时候数据都是保存在对象中的,如何将对象保存到磁盘中,这里就需要使用对象序列化。
对象序列化(Serializable)是指将一个Java对象换成一个I/O流中字节序列的过程。目的就是将对象保存到磁盘中,或允许在网络上直接传输对象。对象序列化机制可以使内存中的Java对象转换成与平台无关的二进制流,既可以将这种二进制流持久的保存在磁盘上,又可以通过网络将这种二进制流传输到另一个网络节点,其他程序在获得了这种二进制流后,还可以将它恢复成原来的Java对象。这种将I/O流中的字节序列恢复为Java对象的过程被称为反序列化。
如果想让某个对象支持序列化机制,那么这个对象所在类必须是可序列化的(里面的属性方法、对象也要是可序列化的,一般的基本数据类型,和String类型是可序列化的,其他不清楚需要查查)。在Java中,可序列化的类必须实现Serializable或Externalizable两个接口之一。其次要定义一个序列版本号的常量。
与Serializable相比,Externalizable接口可以在性能上的提升,但增强了编程的复杂难度,在实际开发中大部分都采用Serializable接口。
实现Serializable和Externalizable
实现Serializable接口 | 实现Externalizable接口 |
---|---|
系统自动存储必要的信息 | 由程序员决定存储的信息 |
Java 内部支持,易于实现,只需实现该接口即可,不需要其他代码支持 | 接口中只提供了两个空方法,实现该类接口必须为两个空方法提供实现 |
性能比较差 | 性能比较好 |
public class SerializableDemo implements Serializable {
//为该类指定一个serialVersionUID变量值
private static final long serialVersionUID = 1L;
//.....
}
上面代码中指定了一个serialVersionUID变量,这个变量的作用是标识Java类的序列化版本。如果我们不显示定义,JVM会根据类的相关信息计算出一个serialVersionUID变量值。
注意:serialVersionUID适用于Java的序列化机制。java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。所以为了在反序列化时确保序列化版本的兼容性,最好在每一个要序列化的类中加入private static final long serialVersionUID的变量值,具体数值可自定义(默认是1L,系统还可以根据类名、接口名、成员方法及属性等生成的一个64位的哈希字段)。这样,某个对象被序列化之后,即使它所对应的类被修改了,该对象依然可以被正确的反序列化。
7. NIO
NIO是为替代传统标准的I/O。它与传统的IO的工作方式不同。NIO采用内存映射文件的方式来处理输入输出,它将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了。
7.1 传统IO与NIO的区别
标准IO中,使用的是 字节流和字符流,而NIO使用的是通道(Channel)和缓冲区(Buffer),数据总是从通道读入缓冲区,或从缓冲区写入通道。
在Java API中,与NIO相关的包:
(1)java.nio:主要包含各种与Buffer有关的类
(2)java.nio.channels:主要包含与Channel和Selector(多线程相关选择器)相关的类
(3)java.nio.channels.spi:主要包含与Channel相关的服务提供者编程呢个接口
(4)java.nio.charset:主要包含与字符集相关的类
(5)java.nio.charset.spi:主要包含与字符集相关的服务提供者编程接口
NIO主要有三大核心部分:Buffer、Channel和Selector。其中Buffer可以看成容器,本质是数组缓冲区。读入或写出到Channel中的所有对象都会先放在Buffer中;Channel是对传统的输入输出的模拟,在NIO中所有的数据都需要通过通道流的形式传输;Selector(选择器)用于监听多个通道的事件(例如:连接打开、数据到达等),主要用于多线程处理。
7.2 缓冲器(Buffer)
Buffer是一个抽象类,其子类有ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和ShortBuffer,这些子类中最常用的是ByteBuffer和CharBuffer。
我们通过Buffer子类的静态方法 static XxxBuffer allocate(int capacity)方法来获得XxxBuffer对象。例如下面语句获得CharBuffer对象:
//创建一个容量为6的CharBuffer对象
CharBuffer bufferCharBuffer.allocate(6);
Buffer中重要的三个概念:
(1)capacity(容量):缓冲区的容量表示该Buffer的最大数据容量,即最多可以存储多少数据。不能为负值,也不能改变
(2)limit(界限):表示Buffer容器中不可被读取的区域的第一个索引,即位于Buffer容器中索引为0到limit之间的区域都可以进行读取操作。缓冲区的limit值从不为负,也不大于容量。
(3)position(位置):用于指定下一个可以被读写的缓冲区位置索引。新创建的Buffer对象position的默认值为0,每进行一次读取或写入操作,position的值都会自动向后移动一步。
Buffer类中常用方法:
方法声明 | 功能描述 |
---|---|
int capacity() | 获取缓冲区大小 |
Buffer clear() | 清除缓冲区,将position设置为0,limit设置为capacity |
Buffer flip() | 反转缓冲区,先将limit设置为当前position位置,然后在将position设置为0 |
boolean hasRemaining() | 判断当前位置(position)和界限(limit)之间是否还有元素 |
int limit() | 获取Buffer的limit位置 |
Buffer limit(int newLimit) | 设置limit的值,并返回一个新的limit缓冲区对象 |
Buffer mark() | 设置Buffer的标记(mark),只能在0到position之间做标记 |
int position() | 获取Buffer中的position值 |
Buffer position(int newPosition) | 设置Buffer的position并返回位置被修改之后的Buffer对象 |
int remaining() | 获取当前位置和界限之间的元素个数 |
Buffer reset() | 将此缓冲区的位置重置为先前标记的位置 |
Buffer rewind() | 倒带缓冲区,将position设置为0,并取消设置的标记 |
Buffer的所有子类都提供了put和get()方法用于向Buffer中存放和取出数据。支持批量数据的访问。
具体使用如下:
public class BufferDemo {
public static void main(String[] args) {
//创建Buffer对象
CharBuffer charbuf=CharBuffer.allocate(6);
System.out.println("Buffer对象的界限为:"+charbuf.limit());
System.out.println("Buffer对象的位置为:"+charbuf.position());
System.out.println("Buffer对象的容量为:"+charbuf.capacity());
//向Buffer对象中放入元素
charbuf.put('x');
charbuf.put('y');
charbuf.put('z');
//放完之后的界限、位置
System.out.println("Buffer对象的界限为:"+charbuf.limit());
System.out.println("Buffer对象的位置为:"+charbuf.position());
//进行反转
charbuf.flip();
System.out.println("反转后Buffer对象的位置为:"+charbuf.position());
System.out.println("反转后Buffer对象的界限为:"+charbuf.limit());
//取出第一个元素之后的位置和界限
System.out.println("取出的第一个元素是:"+charbuf.get());
System.out.println("取出后的位置为:"+charbuf.position());
System.out.println("取出后的界限为:"+charbuf.limit());
//进行清除
charbuf.clear();
//清除之后的位置和界限
System.out.println("清除之后的界限为:"+charbuf.limit());
System.out.println("清除之后的位置为:"+charbuf.position());
//取出第一个元素之后,位置值不变
System.out.println("执行clear()之后取出的第一个元素:"+charbuf.get(0));
System.out.println("界限为:"+charbuf.limit());
System.out.println("位置为:"+charbuf.position());
}
}
结果如下图:
7.3 Channel(通道)
它是一个接口对象,类似于传统流对象但是区别如下:
(1)Channel可以异步执行IO读写操作
(2)Channel的读写操作是双向的,既可以从Channel中读取数据,也可以写入数据,而流的读写通常都是单向的
(3)Channel可以直接将指定文件的部分或全部映射成Buffer
(4)Channel只能和Buffer进行交互,程序不能直接读写Channel中的数据
在java.nio.channels包中,提供了很多Channel接口的实现类,包括DategramChannel、FileChannel、Pipe.SinkChannel、Pipe.SourceChannel、ServerSocketChannel、SocketChannel等,其中DatagramChannel用于支持UDP网络通信,FileChannel用于从文件读写数据,Pipe.SinkChannel和Pipe.SourceChannel用于支持线程之间的通信,ServerSocketChannel和SocketChannel用于支持TCP网络通信。
如何获取Channel:
通过传统IO的getChannel()方法获取。不同流获取的Channel是不同的,例如FileInputStream和FileOutStream获取的是FileChannel,同时还可以使用RandomAccessFile获取该对象,而PipedInputStream和PipedOutputStream所获得的是Pipe.SinkChannel和Pipe.SourceChannel。
FileChannel常用方法
方法声明 | 功能描述 |
---|---|
MappedByteBuffer map(MapMode mode,long position,long size) | 将该通道文件的区域直接映射到内存中,其中第一个参数用于执行映射时的模式,包含只读、读写等模式;第二个参数表示映射区域开始的文件中的位置;第3个参数表示要映射区域的大小 |
long position() | 返回该通道的文件位置 |
int read(ByteBuffer dst) | 从这个通道读取一个字节序列到给定的缓冲区 |
int read(ByteBuffer dst,long position) | 从给定的文件位置开始,从这个通道读取一个字节序列到给定的缓冲区 |
long read(ByteBuffer[ ] dsts,int offset,int length) | 从这个通道读取一个字节序列到给定缓冲区的子序列 |
long size() | 返回该通道文件的当前大小 |
long transferTo(long position,long count,WritableByteChannel target) | 读取该通道文件中给定位置的字节数,并将他们写入目标通道 |
int write(ByteBuffer src) | 从给定的缓冲区写入这个通道的字节序列 |
long write(ByteBuffer[ ] srcs,int offset,int length) | 从给定缓冲区的子序列中写入该通道的字节序列 |
int write(ByteBuffer src ,long position) | 从给定的缓冲区开始,从给定的文件位置开始向该通道写入一个字节序列 |
用NIO来实现文件的copy:
public class ChannelDemo {
public static void main(String[] args) throws IOException {
//创建RandomAccessFile对象
RandomAccessFile infile=new RandomAccessFile("source.txt","rw");
//获取读取源文件FileChannel通道
FileChannel inChannel=infile.getChannel();
//创建RandomAccessFile对象指定目标文件
RandomAccessFile outfile=new RandomAccessFile("target.txt","rw");
FileChannel outChannel=outfile.getChannel();
//使用transferTo()方法进行整体复制
long transferTo= inChannel.transferTo(0,inChannel.size(),outChannel);
if(transferTo>0){
System.out.println("复制成功!!");
}
//关闭资源
infile.close();
inChannel.close();
outChannel.close();
outfile.close();
}
}
8. NIO.2
与NIO比NIO.2最大的改进就是提供了全面的文件输入输出以及文件系统的访问和支持,并且新增了java.nio.file包及其子包,而且还提供基于异步Channel的输入输出。
8.1 Path 接口
用来弥补File类不足,File性能比较低,大多数方法再出错时仅返回失败而不提供异常信息,而且File还不能利用文件系统的特性。
NIO.2提供了Paths和Files两个工具类,Paths类提供两个返回Path的静态方法,通过这两个方法可以创建Path对象,而Files类中提供了大量的静态方法来操作文件。
Path接口的常用方法:
方法声明 | 功能描述 |
---|---|
boolean endsWith(String other) | 判断当前路径是否以指定的字符串结尾 |
Path getName(int index) | 返回此路径的名称元素作为路径对象 |
int getNameCount() | 返回路径中名称元素的数量 |
Path getParent() | 返回父路径,如果此路径没有父路径,则返回null |
Path getRoot() | 返回该路径的根组件作为路径对象,如果此路径没有根组件,则返回null |
Path toAbsolutePath() | 返回表示此路径的绝对路径的路径对象 |
URI toUri() | 返回表示此路径的URI地址 |
使用方法如下:
public class PathDemo {
public static void main(String[] args) {
//使用Paths的get()方法创建Path对象
Path path= Paths.get("target.txt");
//输出Path对象中的信息
System.out.println("path的根路径为:"+path.getRoot());
System.out.println("path的父路径为:"+path.getParent());
System.out.println("path中的路径名称数:"+path.getNameCount());
//循环输出路径名称
for (int i=0;i<path.getNameCount();i++){
//获取指定索引处的路径名称
Path name=path.getName(i);
System.out.println("索引为"+i+"的路径的名称为:"+name);
}
System.out.println("path的URI路径为:"+path.toUri());
System.out.println("path的绝对路径为:"+path.toAbsolutePath());
}
}
结果如下图:
8.2 Files工具类
方法声明 | 功能描述 |
---|---|
static Path createDirectories(Path dir,FileAttribute<?>…attrs) | 创建多级文件目录 |
static Path createFile(Path path,FileAttribute<?>…attrs) | 创建一个新的空文件,如果文件已经存在则创建失败 |
static Path copy(Path source,Path target,CopyOption…options) | 该方法将一个文件复制到目标文件,并使用选项参数指定如何进行复制 |
static List<String> readAllLines(Path path) | 从文件中读取所有行 |
static long size(Path path) | 返回文件的大小(以字节为单位) |
static Stream<Path> list(Path dir) | 将指定路径转换为Stream流对象 |
static Path write(Path path,Iterable<?extends CharSequence> lines,OpenOption…options) | 将文本行写入文件,并传入指定的写入模式 |
使用如下:
public class FilesDemo {
public static void main(String[] args) throws IOException {
//定义一个目录路径的Path对象
Path directoryPath= Paths.get("E:/javaworkspace/sample");
//根据Path对象创建多级目录
Files.createDirectories(directoryPath);
System.out.println("目录创建成功!");
Path filePath=Paths.get("E:/javaworkspace/sample.tt.txt");
//根据Path对象创建一个文件
Files.createFile(filePath);
//创建一个List集合,并向集合中添加内容
List<String> list=new ArrayList<String>();
list.add("这是一个测试文件");
//将集合中的内容追加写入到指定的文件
Files.write(filePath,list,StandardOpenOption.APPEND);
List<String> lines= Files.readAllLines(filePath);
System.out.println("文件的大小为:"+Files.size(filePath));
System.out.println("文件内容为:"+lines);
}
}