IO
流的概念: java中数据的传输以流的形式体现(向水在管道中流动一样)
流的分类
流按流向分为:输入流,输出流。
输入流:程序从外部读取数据
输出流:程序向外部写出数据 流按操作数据分为两种:字节流与字符流。
字节流:以字节为单位操作数据,可以操作任何数据,如文本,图片,视频
字符流:专门用来处理字符数据的流对象,处理字符比较方便(有行的概念),其实内部使用的还是字节流 流按功能分为两种: 基本流(节点流) 和 过滤流(处理流)
基本流 : 直接读取或写入对象,提供基本功能
过滤流 : 将基本流包装起来,提供一些额外功能
File类
用来描述文件或目录,可以对文件或目录进行操作
构造方法 File(String pathname) 通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例。
File(String parent, String child) 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。中间有没有分隔符无所谓。
File(File parent, String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
常用字段 static String separator 与系统有关的默认名称分隔符。
windows下为\,Linux下为/ static String pathSeparator与系统有关的路径分隔符字符。
windows下为;,Linux下为:
常用方法 文件和文件夹共有操作 boolean delete() 删除此抽象路径名表示的文件或目录。
如果此路径名表示一个目录,则此目录必须为空才能删除. 彻底删除,不会移动到回收站 boolean exists() 测试此抽象路径名表示的文件或目录是否存在。 String getAbsolutePath() 返回抽象路径名的绝对路径名字符串 String getCanonicalPath() 返回抽象路径名的规范路径名字符串。 会经过解析,把..去掉 String getName() 返回由此抽象路径名表示的文件或目录的名称。
String getParent() 返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null。
String getPath() 将此抽象路径名转换为一个路径名字符串。
boolean isAbsolute() 测试此抽象路径名是否为绝对路径名。
注意:toString方法返回路径名 (构造方法传什么路径,就显示什么路径,不一定是绝 对路径).
文件操作: boolean isFile() 测试此抽象路径名表示的文件是否是一个标准文件。
long lastModified() 返回此抽象路径名表示的文件最后一次被修改的时间。
long length() 返回由此抽象路径名表示的文件的长度。
boolean renameTo(File dest) 重新命名此抽象路径名表示的文件。如果文件路径修改,带有剪切功能
boolean canRead() 测试应用程序是否可以读取此抽象路径名表示的文件。
boolean canWrite() 测试应用程序是否可以修改此抽象路径名表示的文件。
boolean createNewFile() 当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽 象路径名指定的一个新的空文件。
文件夹操作 boolean isDirectory() 测试此抽象路径名表示的文件是否是一个目录。
String[] list() 返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。
String[] list(FilenameFilter filter) 返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的。
File[] listFiles() 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。
File[] listFiles(FileFilter filter) 返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组, 这些路径名满足特定过滤器。
static File[] listRoots() 列出可用的文件系统根目录。 windows为所有盘符,Linux为/ boolean mkdir() 创建此抽象路径名指定的目录。
boolean mkdirs() 创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。
注意:
ist方法返回的是文件名,listFiles返回的是文件,包含全路径名.
后者更常用FileFilter为一个接口,有一个方法 boolean accept(File pathname)
测试指定抽象路径名是否应该包含在某个路径名列表中。
特点:
字节流 InputStream * 字节输入流的抽象父类
FileInputStream * 文件输入流(基本流,用于对文件的读取)
FilterInputStream * 过滤流的父类
BufferedInputSteam * 缓冲流(过滤流,提供缓冲功能)
ByteArrayInputStream * 字节数组输入流(基本流,可以读取字节数组中的数据)
OutputStream * 字节输出流的抽象父类
FileOutputStream * 文件输出流(基本流,用于对文件的写入)
FilterOutputStream * 过滤流的父类
BufferedOutputStream * 缓冲流(过滤流,提供缓冲功能)
PrintStream * 打印流(过滤流,方便打印各种类型的数据,不会抛异常,可指定自动刷新,不能追加内容)
ByteArrayOutputStream * 字节数组输出流(基本流,可以将数据写入到字节数组中)
* 字符流 Reader * 字符输入流的抽象父类
InputStreamReader * 字节字符转换流(过滤流,可以将字节流转换为字符流,以字符读取,比较方便)
FileReader * 字符文件输入流(基本流,用于对字符文件的读取,以当前项目编码)
BufferedReader * 缓冲流(过滤流,提供缓冲功能,可以读一行)
Writer * 字符输出流的抽象父类
OutputStreamWriter * 字节字符转换流(过滤流,可以将字符流转换为字节流,以字符写入,比较方便)
FileWriter * 字符文件输出流(基本流,用于对字符文件的写入,以当前项目编码)
BufferedWriter * 缓冲流(过滤流,提供缓冲功能,可以写一个新行)
PrintWriter * 字符打印流(过滤流,方便打印各种类型的数据,不会抛异常,某些方法可指定自动刷新 println、printf 或 format,有换行方法,可直接跟字节流打交道,不能追加内容)
NIO
NIO是为了弥补IO操作的不足而诞生的,NIO的一些新特性有:非阻塞I/O,选择器,缓冲以及管道。
NIO中的几个基础概念
1.Channel
2.Buffer
3.Selector
管道(Channel),缓冲(Buffer) ,选择器( Selector)是其主要特征。
在NIO中有几个比较关键的概念:Channel(通道),Buffer(缓冲区),Selector(选择器)。
首先从Channel说起吧,通道,顾名思义,就是通向什么的道路,为某个提供了渠道。
而Channel是双向的,既可用来进行读操作,又可用来进行写操作。
基于缓冲区对数据进行读取或者是写入
可以异步的读取与写入
以下是常用的几种通道:
FileChannel:可以从文件读或者向文件写入数据
SocketChanel:以TCP来向网络连接的两端读写数据
ServerSocketChannel:能够监听客户端发起的TCP连接,并为每个TCP连接创建一个新的
SocketChannel来进行数据读写
DatagramChannel:以UDP协议来向网络连接的两端读写数据
Buffer(缓冲区),是NIO中非常重要的一个东西,在NIO中所有数据的读和写都离不开Buffer。比如上面的一段代码中,读取的数据时放在byte数组当中,而在NIO中,读取的数据只能放在Buffer中。同样地,写入数据也是先写入到Buffer中。
Buffer,故名思意,缓冲区,实际上是一个容器,是一个连续数组。Channel提供从文件、网络读取数据的渠道,但是读取或写入的数据都必须经由Buffer
Buffer是一个顶层父类,它是一个抽象类,常用的Buffer的子类有:
ByteBuffer
IntBuffer
CharBuffer
LongBuffer
DoubleBuffer
FloatBuffer
ShortBuffer
如果是对于文件读写,上面几种Buffer都可能会用到。但是对于网络读写来说,用的最多的是
ByteBuffer。
栗子:
缓冲区与管道
package cn.Fileoperation; import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.Scanner; public class TheConduit { static Scanner input=new Scanner(System.in); public static void main(String[] args) { //创建 //establish(); //复制转移 //transfer(); } //复制转移 private static void transfer() { System.out.println("文件的路径+文件名"); String one=input.next(); System.out.println("想要文件信息的文件的路径+文件名"); String two=input.next(); //创建file对象 ,两个路径 File onefile=new File(one); File twofile=new File(two); //创建 输入 输出流 FileInputStream fileInputStream=null;//输入 FileOutputStream fileOutputStream=null;//输出 //创建管道 用于 输入 输出 FileChannel onechannel=null;//输入 FileChannel twochannel=null;//输出 //实例化 输入 输出 try { fileInputStream=new FileInputStream(onefile); fileOutputStream=new FileOutputStream(twofile); //实例化管道 onechannel=fileInputStream.getChannel(); twochannel=fileOutputStream.getChannel(); //创建缓冲区 ByteBuffer buffer= ByteBuffer.allocate(1024); //定义变量接去a文件的数据 int num=0; while ((num=onechannel.read(buffer))!=-1){ //切换模式 buffer.flip(); twochannel.write(buffer);//真实写入 //清除缓冲 buffer.clear(); } } catch (IOException e) { e.printStackTrace(); }finally { try { twochannel.close(); onechannel.close(); fileOutputStream.close(); fileInputStream.close(); System.out.println("完事!!!!"); } catch (IOException e) { e.printStackTrace(); } } } //创建 private static void establish() { //写模式 System.out.println("需要一个路径+文件名"); String name=input.next(); //创建一个文件对象 File file=new File(name); //创建一个输出流对象 FileOutputStream fileOutputStream=null; //创建一管道对应的实体类 FileChannel fileChannel=null; try { fileOutputStream=new FileOutputStream(file);//封装 fileChannel=fileOutputStream.getChannel();//获取到管道 ByteBuffer buffer=ByteBuffer.allocate(1024);//创建一个1024的缓冲区 //创建一个数组来为缓冲区赋值 String [] nams={"你","我","它","他","她"}; //因为缓冲区是ByteBuffer 所以这里需要转化下 for (String s:nams){ buffer.put(s.getBytes());//把数组中的值循环添加到缓冲区中 } //重置缓冲区 切换读模式 buffer.flip(); //真正的写入到文件中 try { fileChannel.write(buffer); } catch (IOException e) { e.printStackTrace(); }finally { try { //关闭 fileChannel.close(); fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } catch (FileNotFoundException e) { e.printStackTrace(); } } }
内存映射
就是把文件映射到电脑中的内存中,通过操作内存从而达到操作文件的目的
文件读取文件方式
RandomAccessFile:随机读取,速度最慢
FileInputStream:流的方式读取
BufferReader:缓存的方式读取
MappedByteBuffer:内存映射,速度最快
内存映射的三种模式:MapMode
READ_ONLY:对缓冲区的内容只读
READ_WRITE:对缓冲区的内容读写
PRIVATE:只会对缓冲区的内容进行修改,不会影响到真实的文件
栗子:
package cn.Fileoperation; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.util.Scanner; public class Memorymappings { static Scanner input=new Scanner(System.in); public static void main(String[] args) { mappings(); } private static void mappings() { //创建一个管道 FileChannel fileChannel=null; System.out.println("给个地址:"); String file=input.next(); try { RandomAccessFile randomAccessFile=new RandomAccessFile(file,"rw"); //实例化一个管道 fileChannel=randomAccessFile.getChannel(); try { //创建一个内存文件映射 MappedByteBuffer buffer=fileChannel.map(FileChannel.MapMode.READ_ONLY,0,fileChannel.size()); //创建一个缓冲区 ByteBuffer byteBuffer=ByteBuffer.allocate(1024); //创建一个byte数组,便于后续获取数据 byte [] bytes=new byte[1024]; //获取文件的大小 long length=randomAccessFile.length(); //设置开始时间 long bageTime=System.currentTimeMillis(); //循环 for (int i=0;i<length;i+=1024){ if(length-i>1024){ buffer.get(bytes); }else{ byteBuffer.get(new byte[(int)length-i]); } } //设置结束时间 long endTime=System.currentTimeMillis(); System.out.println("使用内存映射的时间"+(bageTime-endTime)); System.out.println("----------------------------------------------"); System.out.println(); bageTime=System.currentTimeMillis();//开始时间 int num=0; while ((num=fileChannel.read(byteBuffer))!=-1){ byteBuffer.flip(); //重置缓冲区 byteBuffer.clear();//清空缓冲区 } endTime=System.currentTimeMillis();//结束时间 System.out.println("使用io的时间"+(bageTime-endTime)); } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } } }
文件锁
目的:安全
FileLock:基于FileChannel对文件提供锁的功能
分为两种:
共享锁:可以一起读,只有一个写,共享锁的目的是为了防止别人获取独占锁。
独占锁:只能有一个读或写,读写不能同时
栗子:
package cn.Fileoperation; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.Scanner; public class Lock { static Scanner input=new Scanner(System.in); public static void main(String[] args) { lock(); } private static void lock() { FileChannel channel=null; FileLock lock=null; //获取文件 System.out.println("路径:"); String file=input.next(); try { RandomAccessFile randomAccessFile=new RandomAccessFile(file,"rw"); //获取管道 channel=randomAccessFile.getChannel(); try { lock=channel.lock();//独占锁 lock=channel.lock(0,channel.size(),true);//共享锁 System.out.println(lock.isShared()); System.out.println(lock.isValid()); //创建缓冲区 ByteBuffer byteBuffer=ByteBuffer.allocate(1024); System.out.println("写:"); String name=input.next(); //向缓冲区写入数据 byteBuffer.put(name.getBytes()); //切换模式 byteBuffer.flip(); //通道写入数据 channel.write(byteBuffer); } catch (IOException e) { e.printStackTrace(); }finally { try { lock.close(); channel.close(); System.out.println("完事!!!!"); } catch (IOException e) { e.printStackTrace(); } } } catch (FileNotFoundException e) { e.printStackTrace(); } } }