I/O流(Input/Output)流,即输入/输出流,是java中实现输入/输出的基础,他可以方便实现数据的输入/输出操作。(数据的传输)
根据流操作的数据单位的不同,可以分为字节流和字符流
根据流传输方向的不同,又可以分为输入流和输出流
根据流的功能不同,可以分为节点流和处理流
java中的I/O流主要定义在java.io包中,该包下定义了很多类,其中有四个类为流的顶级类,分为InputStream和OutputStream, Reader和Writer
(1)InputStream和OutPutStream是字节流,而Reader和Writer是字符流
(2)InputStream和Reader是输入流,而OutPutStream和Writer是输出流
(3)这四个顶级类都是抽象类,并且是所有流类型的父亲。
在计算机中,无论是文本、图片、音频还是视频,所有文件都是以二进制(字节)形式存在的,I/O流中针对字节的输入/输出提供了一系列的流,统称为字节流。
字节流是程序中最常用的流
在JDK中,所有的字节输入流都继承自InputStream,所有的字节输出流都继承自OutputStream。
InputStream被看成一个输入管道,OutputStream被看成一个输出管道,数据通过InputStream从源设备输入到程序,通过OutputStream从程序输出到目标设备,从而实现数据的传输。
方法声明 功能描述
int read() 从输入流读取一个8位的字节,把它转换为0~255之间的整数,并返回这一整数。当没有可用字节时,将返回-1
int read(byte[] b)从输入流读取若干字节,把它们保存到参数b指定的字节数组中,返回的整数表示读取字节的数目
int read(byte[] b,int off,int len) 从输入流读取若干字节,把它们保存到参数b指定的字节数组中,off指定字节数组开始保存数据的起始下标,len表示读取的字节数目
void close() 关闭此输入流并释放与该流关联的所有系统资源
前三个read()方法都是用来读数据的,分按字节读取和按字节数组读取。
进行I/O流操作时,应该调用close()方法关闭流,从而释放当前I/O流所占的系统资源。
void write(int b) 向输出流写入一个字节
void write(byte[] b) 把参数b指定的字节数组的所有字节写道输出流
void write(byte[] b, int off, int len) 将指定byte数组中从偏移量off开始的len个字节写入输出流
void flush() 刷新此输出流并强制写出所有缓冲的输出字节
void close() 关闭此输出流并释放与此流相关的所有系统资源
前三个write()方法都是用来写数据的,分按字节读取和按字节数组写入。
flush()方法用来将当前输出流缓冲区(通常是字节数组)中的数据强制写入目标设备,此过程称为刷新
close()方法是用来关闭流并释放与当前IO流相关的系统资源。
(1)针对文件的读写操作,JDK专门提供了两个类,分别是FileInputStream和FileOutputStream
FileInputStream是InputStream的子集,它是操作文件的字节输入流,专门用于读取文件中的数据。
(2)从文件读取数据是重复的操作,因此需要通过循环语句来实现数据的持续读取
在读取文件数据时,必须保证文件在相应目录存在并且是可读的,否则会抛出FileNotFoundException
//假如在D盘已经有个a.txt文件,里面的内容是a,b,c
//read(): 一次读取一个字节,如果读取到了文件末尾,将会返回-1的标识
public class Demo1_FileStream{
public static void main(String[] args) throws FileNotFoundException{
//1.创建字节输入流对象
FileInputStream fis = new FileInputStream("D:\\a.txt");
//2.读取文件中的数据
int i = fis.read();
System.out.println(i); //97
//2.读取文件中的数据
int i2 = fis.read();
System.out.println((char)i2); //b
}
}
//假如在D盘已经有个a.txt文件,里面的内容是a,b,c
//read(): 一次读取一个字节,如果读取到了文件末尾,将会返回-1的标识
public class Demo2_FileStream{
public static void main(String[] args) throws FileNotFoundException{
//1.创建字节输入流对象
FileInputStream fis = new FileInputStream("D:\\a.txt");
//2.循环读取文件中的数据
int i;
//2.1 在循环中不断地调用read方法,并把读取到的数据给i赋值,只要没有读到-1,说明没有达到文件末尾
while((i = fis.read())!=-1){
System.out.println((char)i);
}
//3.关闭流释放资源
fis.close();
}
}
public class Demo3_FileStream{
//字节输出流: FileOutputStream
//输出流写出数据,关联文件的时候,如果文件不存在,则自动创建
/**
*输出流写出数据,如果关联的文件已经存在,会将原本内容清空掉之后,再次写入,
*如果不想清空原有内容,就可以在构造方法的位置,加入true的开关即可
*/
public static void main(String[] args) throws IOException{
//1.创建字节输出流对象
FileOutputStream fos = new FileOutputStream("D:\\1.txt", true);
//2.写出数据
fos.write(98);
//或者
byte[] bytes = "你好,世界".getBytes();
System.out.println(Arrays.toString(bytes));
fos.write(bytes);
//等价于
fos.write("你好,世界2".getBytes());
//3.关闭流释放资源
fos.close();
}
使用JavaIO技术完成文件的拷贝
(1)创建输入流和输出流对象
输入流对象关联要拷贝的数据源
输出流对象关联要拷贝的数据目的
(2)在读取过程中,将数据写出到目标文件当中
(3)关闭流释放资源
建议IO流的异常使用try…catch进行处理,并加入finally代码块将关闭流释放资源的代码,放在finally当中。
alt + shift + z --> try…catch
public class Test1_Copy{
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try{
//1. 创建输入流和输出流对象
FileInputStream fis = new FileInputStream("D:\\abc.txt");
FileOutputStream fos = new FileOutputStream("E:\\copy.txt");
//2. 在读取的过程中,将数据写出到目标文件当中
int i;
while((i = fis.read())! = -1){
fos.write(i);
}
//3.关闭流释放资源
fis.close();
fos.close();
} catch (IOException e){
e.printStackTrace();
} finally{
//3.关闭流释放资源
if(fis!=null){
try{
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
if(fos!=null){
try{
fos.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
}
在文件拷贝过程中,通过以字节形式逐个拷贝,效率很低,因此可以定义一个字节数组缓冲区,在拷贝文件时,就可以
一次性读取多个字节的数据。
//假如:已经在D盘创建了a,b两个文件
//read方法如果传入了数组,那么会根据数组容器大小,决定一次读取多少个字节
//read方法的返回值是: 读取到的(有效)字节个数
public class Test2_CopyFile{
public static void main(String[] args) throws IOException{
long start = System.currentTimeMillis();
//1. 创建输入输出流,关联数据源和数据目的
FileInputStream fis = new FileInputStream("D:\\a.flv");
FileOutputStream fos = new FileOutputStream("D:\\b.flv");
//创建字节缓冲区
byte[] bys = new byte[1024];
//2.在读取的过程中,将数据写出到数据目的
int len;
while((len = fis.read(bys))!=-1){
//3.写出的时候,从数组容器中取出,0-len(有效字节个数)
fos.write(bys,0,len);
}
fis.close();
fos.close();
long end = System.currentTimeMillis();
System.out.println("花费时间为:"+ (end-start) + "毫秒");
}
}
除了定义字节缓冲区来提高文件拷贝效率外,IO中还提供了两个字节缓冲流来提高文件拷贝效率:
BufferedInputStream 和 BufferedOutputStream。
他们的构造方法中分别接收InputStream和OutputStream类型的参数作为对象,在读写数据时提供缓冲功能。
由于两个流对象中,内置了字节(数组) ,从而提高IO流的读写效率。
public class Demo_BufferedStream{
/*
* BufferedInputStream 字节缓冲输入流
* BufferedOutputStream 字节缓冲输出流
*
*/
public static void main(String[] args) throws IOException{
long start = System.currentTimeMillis();
//1.创建字节缓冲,输入输出流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\a.flv"));
BufferedOutputStream bos = new BufferedOutputStream(new FileInputStream("D:\\b.flv"));
//2.读写操作
int i;
while((i=bis.read())!=-1){
bos.write(i);
}
//3.关闭流释放资源
bis.close();
bos.close();
long end = System.currentTimeMillis();
System.out.println("花费时间为:"+ (end-start) + "毫秒");
}
}
数据源(源设备)——>FileInputStream(字节流)——>BufferedInputStream(字节缓冲流)——>JAVA(应用程序)——>BufferedOutputStream(字节缓冲流)——>FileOutputStream(字节流)——>数据目的(目标设备)
除了字符流,JDK还提供了用于实现字符操作的字符流,同字节流一样,字符流也有两个抽象的顶级父类,分别是Reader 和 Writer。
(用字节流输出中文,可能会出现中文乱码问题,所以这时候便要利用到字符流)
public class Demo1{
public static void main(String[] args) throws IOException{
FileInputStream fis = new FileInputStream("b.txt");
byte[] bys = new byte[2];
int i;
while((i=fis.read(bys))!=-1){
System.out.println(new String(bys,0,i));
}
fis.close();
}
}
操作纯文本文件的时候,可以解决中文乱码问题。
(注意:字符流只能操作纯文本文件)
字符流底层实际上是通过(字节流+编码表)的形式进行读取的,在读取之后,会根据平台默认码表决定一次读取多少个字节,并在内存中转换为字符。
GBK ——> 一个中文占2个字节
UTF-8 ——> 一个中文占3个字节
字符流底层有一个判断,
如果读取到的是中文字符,一次读取2个字节(GBK),
如果读取到的是非中文字符,一次读取1个字节,
其中中文字符一般都是负数的字节,部分是第一个字节为负数,后面的字节有可能为正数,
非中文字符都是正数。
如果字符输出流没有调用close方法、flush方法的话,数据将不会写出到文件中
(1)flush方法是将数据刷出到文件中去,刷出后可以继续调用write方法写出
(2)close方法的主要功能是关闭流释放资源,同时也具有刷出数据的效果
(3)close方法调用结束后,不能再调用write方法写出数据
public static void main(String[] args) throws IOException{
FileWrite fw = new FileWriter("c.txt");
//1.写出一个字符
fw.write('a');
//2.写出一个字符数组
char[] cbs = {'1','2','3','4'};
//3.写出一个字符数组的一部分
fw.write(cbs,0,2);
//4.写出一个字符串
fw.write("你好你好");
//5.写出字符串的一部分
fw.write("你好你好",0,1);
fw.close();
}
BufferedInputStream
BufferedOutputStream
BufferedReader
readLine() -> 一次读取一整行字符串,同时结束标记是null,不会读取到回车换行符
BufferedWriter
newLine() -> 写出回车换行,但是此方法具有跨平台效果
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter br = new BufferedWriter(new FileWriter("bufferCopy.txt"));
String line;
while((line = br.readLine())!=null){
bw.write(line);
}
br.close();
bw.close();
}
转换流可以按照指定的编码表读写数据
在JDK中,提供了两个类用于实现将字节流转换为字符流,它们分别是InputStreamReader和OutputStreamWriter
(1)InputStreamReader是Reader的子类,它可以将一个字节输入流转换成字符输入流,方便直接读取字符。
(2)OutputStreamWriter是Writer的子类,它可以将一个字节输出流转换成字符输出流,方便直接写入字符。
字节流通向字符流的桥梁
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, String charsetName)
public static void main(String[] args) throws IOException{
InputStreamReader isr = new InputStreamReader(new FileInputStream("b.txt"),"utf-8");
int i;
while((i=isr.read())!=-1){
System.out.println((char)i);
}
isr.close();
}
或者
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("b.txt"),"utf-8"));
String line = br.readLine();
System.out.println(line);
br.close();
}
字符流通向字节流的桥梁
public static void main(String[] args) throws IOException{
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("e.txt"),"utf-8");
osw.write("你好你好");
osw.close();
}
File类用于封装一个路径,这个路径可以是从系统盘符开始的绝对路径,也可以是相对于当前目录而言的相对路径。封装的路径可以指向一个文件,也可以指向一个目录,在File类中提供了针对这些文件或目录的一些常规操作。
/**
*File: Java中的File类可以将文件或文件夹的路径,封装成对象。并通过代码,对这些文件或文件夹对象,进行操作。
*相对路径:相对于当前项目下的文件或文件夹。
*绝对路径:从盘符的根目录开始,一直指向到某个具体的文件。
*/
public static void main(String[] args){
File file = new File("D:\\c.flv");
System.out.println(file.exists());
File file2 = new File("bbb");
System.out.println(file2.exists());
}
方法声明 功能描述
File(String pathname) 通过指定的一个字符串类型的文件路径来创建一个新的File对象
File(String parent,String child) 根据指定的一个字符串类型的父路径和一个字符串类型的子路径(包括文件名称)创建一个File对象
File(File parent,String child) 根据指定的File类的父路径和字符串类型的子路径(包括文件名称)创建一个File对象
public static void main(String[] args){
File f1 = new File(“D:”,“a.flv”);
System.out.println(f1.exists());
//File(String parent,String child)
File f2 = new File(new File("D:"),"a.flv");
System.out.println(f2.exists());
}
public class Demo2_FileMethod{
public static void main(String[] args){
}
private static void method4(){
File f = new File("D:\\a.flv");
//boolean isFile() 判断当前对象是否是文件
System.out.println(f.isFile());
//boolean isDirectory() 判断当前对象是否是文件夹
System.out.println(f.isDirectory());
System.out.println(f.isAbsolute());
//long lastModified() 获取最后修改时间的毫秒值
long time = f.lastModified();
System.out.println(new Date(time));
//long length() 返回文件大小
long length = f.length();
System.out.println(length);
}
private static void method3(){
//boolean canRead()
File f = new File("D:\\a.flv");
System.out.println(f.canRead());
//boolean canWrite()
System.out.println(f.canWrite());
}
private static void method2(){
File f = new File("D:\\a.flv");
//1.getName() 获取文件\文件夹名称
System.out.println(f.getName());
//2.getPath() 获取对象构造方法中封装的路径
System.out.println(f.getPath());
//3.getAbsolutePath() 获取绝对路径
System.out.println(f.getAbsolutePath());
//4.getParent() 获取父级路径
System.out.println(f.getParent());
}
public static void method1() throws IOException{
//1.delete方法,删除文件或文件夹
File f1 = new File("D:\\b.flv");
System.out.println(f1.delete());
//2.createNewFile(); 创建一个文件,返回是否创建成功
System.out.println(f1.createNewFile());
}
}
public class demo2_FileMethod{
/**
* String[] list() 返回当前文件夹下所有的文件和文件夹名称
*
* String[] list(FilenameFilter filter) 返回当前文件夹下所有的文件和文件夹名称,带有筛选效果
*
* File[] listFiles() 返回当前文件夹下所有的文件和文件夹对象
*/
public static void main(String[] args) throws IOException{
File f = new File("D");
File[] listFiles = f.listFiles();
for(File file : listFiles){
if(file.isDirectory()){
System.out.println(file.toString());
}
}
private static void method5(){
File f = new File("D:");
String[] sArr = f.list(new FilenameFilter(){
@Override
public boolean accept(File dir, String name){
File ff = new File(dir,name);
return ff.isDirectory();
}
});
for(String s : sArr){
System.out.println(string);
}
}
}
File类中提供了一个重载的list(FilenameFilter filter)方法,该方法接收一个FilenameFilter接口类型的参数,其中定义了一个抽象方法accept(File dir,String name)用于依次对指定File的所有子目录进行迭代。
/**
* String[] list() 返回当前文件夹下所有的文件和文件夹名称
*
* String[] list(FilenameFilter filter) 返回当前文件夹下所有的文件和文件夹名称,带有筛选效果
*
* File[] listFiles() 返回当前文件夹下所有的文件和文件夹对象
*/
public class Demo3_FileMethod{
public static void main(String[] args){
}
public static void printFile(File dir){
//1.获取传入文件夹下的所有文件和文件夹对象
File[] files = dir.listFiles();
//2.遍历数组,获取到每一个文件和文件夹对象
for(File file : files){
//3.如果是文件就打印该文件的名称
if(file.isFile())
{
System.out.println(file.getName());
}else if(file.isDirectory()){
//4.如果是文件夹,就递归调用该方法
if(file.listFiles()!=null){
printFile(file);
}
}
}
}
private static void method2(){
//筛选遍历扩展名“.txt”文件
File f = new File("D:");
if(f.isDirectory()){
String[] sArr = f.list((dir,name)->name.endsWith(".txt"));
Arrays.stream(sArr).forEach(System.out::println);
}
}
private static void method1(){
File f = new File("D:");
if(f.isDirectory()){
String[] sArr = f.list();
Arrays.stream(sArr).forEach(System.out::println);
}
}
}
/**
*
* delete : 该方法只能删除文件,或者空文件夹
*
*/
public class Demo_DelDir{
public static void main(String[] args){
File f = new File("F:\\测试数据");
System.out.println(f.delete());
}
}
//Java中的delete方法是不走回收站的,不要使用重要的数据进行测试
public class Demo_DelDir{
public static void main(String[] args){
del(new File("F:\\测试数据"));
}
public static void del(File dir){
File[] listFiles = dir.listFiles();
for(File file : listFiles){
if(file.isFile()){
//如果是文件,就可以直接删除
file.delete();
}else if(file.isDirectory()){
//递归调用该方法
if(file.listFiles()!=null){
del(file);
}
}
}
//当所有的文件都删除后,单独删除空文件夹
dir.delete();
}
}
RandomAccessFile对象包含了一个记录指针来标识当前读写处的位置。
(1)当新建RandomAccessFile对象时,该对象的文件记录指针会在文件开始处(即标识为0的位置)
(2)当读写了n个字节后,文件记录指针会向后移动n个字节
(3)除了按顺序读写外,RandomAccessFile对象还可以自由的移动记录指针、即可以向前移动,也可以向后移动。
方法声明 功能描述
long getFilePointer() 返回当前读写指针所处的位置
void seek(long pos) 设定读写指针的位置,与文件开头相隔pos个字节数
int skipBytes(int n) 使读者指针从当前位置开始,跳过n个字节
void write(byte[] b) 将指定的字节数组写入到这个文件,并从当前文件指针开始
void setLength(long newLength) 设置此文件的长度
final String readLine() 从指定文件当前指针读取下一行内容
说明:seek(long pos)方法可以使RandomAccessFile对象中的记录指针向前、向后自由移动,通过getFilePointer()方法,便可获取文件当前记录指针的位置。
//RandomAccessFile : 默认带有尾部追加的效果
public class Test_RandomAccessFile{
public static void main(String[] args) throws IOException{
RandomAccessFile raf = new RandomAccessFile("config.txt","rw");
int num = Integer.parseInt(raf.readLine()) - 1;
if(num>0){
//说明还有机会
System.out.println("您还有" + num + "次试用机会");
raf.seek(0); //将记录指针重新指向文件开头
raf.write((num + " ").getBytes());
}else{
System.out.println("您的试用次数已到达上限,请购买正版");
}
raf.close();
}
}
程序在运行过程中,可能需要将一些数据永久的保存到磁盘上,而数据在Java中都是保存在对象当中的,那么想要保存到磁盘上,则需要使用Java中的对象序列化。
对象的序列化(Serializable)是指将一个Java对象转换成一个I/O流中的字节序列的过程
为了将对象保存到磁盘中,或允许在网络中直接传输对象。
对象序列化可以使内存中的Java对象转换成与平台无关的二进制流
即可以将这种二进制流持久地保存在磁盘上,又可以通过网络将这种二进制流传输到另一个网络节点
其他程序在获得了这种二进制流后,还可以将它恢复成原来地Java对象
这种将I/O流中的字节序列恢复为Java对象的过程被称之为反序列化(Deserialize)
public class Demo_ObjectStream{
private static void readObj() throws IOException, FileNotFoundException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStrea("obj.txt"));
Object object = ois.readObject();
System.out.println(object);
}
public static void main(String[] args) throws IOException{
//1. 创建对象输出流,用于将对象写出到文件中去
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
Person p = new Person("张三",23);
//2. 使用对象输出流写出对象
oos.writeObject(p);
//3. 关闭流释放资源
oos.close();
}
}
从JDK1.4开始,Java提供了一系列改进的用于处理输入/输出的新功能
这些功能被称之为NIO(New I/O)
(1)NIO采用内存映射文件的方式来处理输入/输出,它将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了。
(2)在NIO中,使用的是Channel(通道)和Buffer(缓冲器)
(3)数据总是从通道读入缓冲器,或从缓冲器写入通道。
(1)Buffer(Buffer缓冲器)
Buffer本质是一个数组缓冲区,读入或写出到Channel中的所有对象都会先放到Buffer中。
(2)Channel(通道)
Channel是对传统的输入/输出的模拟,在NIO中,所有的数据都需要通过通道流的形式传输。
(3)Selecter用于监听多个通道的事件(例如:连续打电话、数据到达等),主要用于多线程处理。
java NIO中的Buffer用于和NIO中的Channel进行交互,交互时数据会从Channel读取到Buffer中,或从Buffer写入到Channel中
Buffer类似于一个数组,它可以保存多个类型相同的数据。
Buffer是一个抽象类,其子类有ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和ShortBuffer。
Buffer子类中最常用的是ByteBuffer和CharBuffer
Buffer类的子类中并没有提供构造方法,因此不能通过构造方法来创建对象。
创建Buffer对象,通常会通过子类中的static XxxBuffer allocate(int capacity)方法来实现(其中Xxx表示不同的数据类型,而capacity表示容量)。
例子
charBuffer buffer = CharBuffer.allocate(6);
public class Demo1_Buffer{
/**
*Buffer(缓冲器)
*底层就是一个数组,主要用于和Channel通道配合,完成数据的传输
*Buffer是一个抽象类,抽象类不能直接new对象,需要使用其子类
*
*注意:
* 子类不能使用new对象,需要通过allocate方法去创建
* capacity(): 容量
* limit(): 可以操作到哪个索引(界限)
* position():当前准备操作的索引
* mark(): 标记,用来记录当前position的值
* reset(): 如果position的值发生变化了,那么通道随reset可以返馈mark记录的那个值。
* put(): 向缓冲器中添加数据
* get(): 获取缓冲器中的数据
*/
public class static void main(String[] args){
//1. 创建一个缓冲器
ByteBuffer buffer = ByteBuffer.allocate(1024);
System.out.println("缓冲器的容量:" + buffer.capacity());
System.out.println("界限:" + buffer.limit());
System.out.println("索引:" + buffer.position());
//2. 向容器中存储数据
buffer.put("abcde".getBytes());
System.out.println("缓冲器的容量:" + buffer.capacity());
System.out.println("界限:" + buffer.limit());
System.out.println("索引:" + buffer.position());
//3. 切换到读写模式
buffer.flip();
System.out.println("缓冲器的容量:" + buffer.capacity());
System.out.println("界限:" + buffer.limit());
System.out.println("索引:" + buffer.position());
buffer.mark(); //读取之前加入标记
//4. 读取数据
byte[] bys = new byte[2];
buffer.get(bys);
System.out.println(new String(bys));
System.out.println("缓冲器的容量:" + buffer.capacity());
System.out.println("界限:" + buffer.limit());
System.out.println("索引:" + buffer.position());
buffer.reset(); //将索引归为之前的标记处
byte[] bys = new byte[2];
buffer.get(bys);
System.out.println(new String(bys));
System.out.println("缓冲器的容量:" + buffer.capacity());
System.out.println("界限:" + buffer.limit());
System.out.println("索引:" + buffer.position());
byte[] bys = new byte[2];
buffer.get(bys);
System.out.println(new String(bys));
System.out.println("缓冲器的容量:" + buffer.capacity());
System.out.println("界限:" + buffer.limit());
System.out.println("索引:" + buffer.position());
}
}
Channel可以异步的执行I/O的读写操作
Channel的读写操作是双向的,既可以从Channel中读取数据,又可以写数据到Channel,而流的读写操作通常都是单向的。
Channel可以直接将指定文件的部分或者全部直接映射成Buffer
Channel只能与Buffer进行交互,程序不能直接读写Channel中的数据
主要包括:DatagramChannel、FileChannel、Pipe.SinkChannel、Pipe.SourceChannel、ServerSocketChannel、SocketChannel等
(1)DatagramChannel用于支持UDP网络通信
(2)FileChannel用于从文件中读写数据
(3)Pipe.SinkChannel和Pipe.SourceChannel用于支持线程之间的通信
(4)ServerSocketChannel和SocketChannel用于支持TCP网络通信
(1)Channel对象并不是通过构造方法来创建的,而是通过传统I/O的getChannel()方法来获取对应的Channel
(2)不同的流所获取的Channel是不同的,例如FileInputStream和FileOutputStream获取的是FileChannel,同时还可以使用RandomAccessFile获取该对象。
(3)PipedInputStream和PipedOutputStream所获得的是Pipe.SinkChannel和Pipe.SourceChannel.
public class Demo2_Channel{
//使用NIO完成文件的拷贝
public static void main(String[] args) throws IOException{
//1. 创建输入输出流对象
FileInputStream fis = new FileInputStream("D:\\a.flv");
FileOutputStream fos = new FileOutputStream("E:\\a.flv");
//2. 获取输入和输出的通道
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
//3. 创建缓冲器
ByteBuffer buffer = ByteBuffer.allocate(1024);
while((inChannel.read(buffer))!=-1){
//切换读写模式
buffer.flip();
outChannel.write(buffer);
buffer.clear();
}
inChannel.close();
outChannel.close();
fis.close();
fos.close();
}
}
public class Demo2_Channel{
//使用NIO完成文件的拷贝
public static void main(String[] args) throws IOException{
RandomAccessFile inFile = new RandomAccessFile("D:\\a.flv","rw");
RandomAccessFile outFile = new RandomAccessFile("E:\\a.flv","rw");
//1. 获取通道
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
long num = inChannel.transferTo(0, inChannel.size(), outChannel);
if(num>0){
System.out.println("复制成功!!");
}
inFile.close();
outFile.close();
inChannel.close();
outChannel.close();
}
}
Path接口是一个共用在文件系统中定位文件的对象,通常表示一个依赖于系统的文件路径
NIO.2还提供了Paths和Files两个工具类,
Paths类中提供了两个返回Path的静态方法,通过这两个方法可以创建Path对象。
Files类中提供了大量的静态方法来操作文件。
public class Demo1_Path{
public static void main(String[] args){
//1. 获取Path对象
Path path = Paths.get("E:\\abc\\test");
//2.createDirectories 创建多级文件夹
Files.createDirectories(path);
//3.createFile 创建文件
Path filePath = Paths.get("E:\\abc\\test\\aaaa.txt");
Files.createFile(filePath);
//4. write(Path path, Iterable extends CharSequence> lines, OpenOption... options )
//将文本写入文件,并传入指定的写入模式
ArrayList list = new ArrayList<>();
list.add("这是一行文本1");
list.add("这是一行文本2");
list.add("这是一行文本3");
Files.write(filePath,list,StandardOpenOption.APPEND);
//static List readAllLines(Path path) 从文件中读取所有行
List list2 = Files.readAllLines(filePath);
System.out.println(list2);
//static long size(Path path) 返回文件的大小,以字节为单位
long size = Files.size(filePath);
System.out.println(size);
}
}
public class Demo2_File{
public static void main(String[] args){
//1. 获取Path对象
Path path = Paths.get("D:\\a.flv");
//2. 获取Path对象中的信息
System.out.println(path.getRoot()); //获取根路径
System.out.println(path.getParent()); //获取父路径
System.out.println(path.getNameCount()); //path中的路径名称数
for(int i=0;i 获取路径名称
Path name = path.getName(i);
System.out.println(name);
}
System.out.println(path.toAbsolutePath());
System.out.println(path.toUri());
}
}