IO流
IO流
1 IO
1.1 I
- input
- 输入
1.2 O
- output
- 输出
2 IO流的分类
2.1 、按照IO流的数据流动方向分
- 输入流
- 输出流
2.2 、按照IO流的数据处理的最小单位分
- 字节流
- 字符流
2.3 、根据IO流的作用分
-
节点流
-
例如:文件IO流
- 连接文件节点
-
-
处理流
- 在节点流的基础上增加其他功能,例如缓冲,编码解码,序列化等
3 IO流的四个抽象基类,超级父类
3.1 InputStream
- 字节输入流
3.2 OutputStream
- 字节输出流
3.3 Reader
- 字符输入流
3.4 Writer
- 字符输出流
4 和文件相关的IO流
4.1 类型
-
FileInputStream
- 文件字节输入流
- 读取任意类型的文件
-
FileOutputStream
- 文件字节输出流
- 写数据到任意类型的文件
-
FileReader
-
文件字符输入流
-
只能读取纯文本文件
- .java
- .txt
- .html
- .js
- .css
- ….
-
-
FileWriter
- 文件字符输出流
- 只能把数据保存到纯文本文件中
4.2 读取
-
(1)读取一个纯文本文件
形式一:
//(1)指定要读取的文件
File file = new File(“upload/exam.txt”);
//(2)创建文本文件的输入流
FileReader fr = null;
try{
fr = new FileReader(file);
//(3)在当前程序中创建一个字符数组,用来保存每一次读取的文本信息
char[] data = new char[10];
//(4)用来记录每一次读取的字符个数
int len;
//(5)用来拼接从文件读取的信息
StringBuilder sb = new StringBuilder();
//(6)循环读取
while((len = fr.read(data))!=-1){
sb.append(new String(data,0,len));
}
System.out.println(sb);
}catch(Exception e){
//….
}finally{
//(7)释放资源
try{
if(fr!=null){ fr.close(); }
}catch(Exception e){
}
}
形式二:
File file = new File(“upload/exam.txt”);
try(
FileReader fr = new FileReader(file);
){
char[] data = new char[10];
int len;
StringBuilder sb = new StringBuilder();
while((len = fr.read(data))!=-1){
sb.append(new String(data,0,len));
}
System.out.println(sb);
}catch(Exception e){
//….
}
-
(2)读取任意类型的文件
//(1)指定文件
File file = new File("…..");
//(2)创建字节输入流
try(
FileInputStream fis = new FileInputStream(file);
){
//(3)创建字节数组,用来存储每次读取的内容
byte[] data = new byte[1024];
//(4)用len记录每次读取的字节数
int len;
//(5)循环读取
while( (len = fis.read(data)) !=-1){
//......
}
}catch(Exception e){
//…
}
4.3 保存
-
(1)把数据保存到一个纯文本文件
//(1)指定要保存的文件
File file = new File("….");
try(
FileWriter fw = new FileWriter(file);
){
String info = “…..”; //要写入到文件的数据内容
fw.write(info);
//或
char[] data = new char[1024];
//…把数据保存到data中
fw.write(data,0,len);
}catch(Exception e){
//….
}
-
(2)把数据保存到一个任意类型的文件
//(1)指定要保存的文件
File file = new File("….");
try(
FileOutputSream fos = new FileOutputSream(file);
){
byte[] data = ….; //用来存储要输出到文件的内容
fos.write(data,0 ,len);
}catch(Exception e){
//….
}
4.4 复制
-
一边读一边写
-
纯文本文件
public static void main(String[] args) {
//(1)创建源文件对象 File src = new File("1.txt"); //(2)创建目标文件对象 File dest = new File("2.txt"); //(3)创建输入流 FileReader fr = null; //(4)创建输出流 FileWriter fw = null; try { fr = new FileReader(src);
// fw = new FileWriter(dest);//覆盖模式
fw = new FileWriter(dest,true);//追加模式 //(5)一边读一边写 //从fr读一些,就写入fw一些 char[] data = new char[6];//1024 while(true){ int len = fr.read(data); if(len == -1){ break; } fw.write(data,0,len);//本次读了几个字符,就写几个字符 } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally{ try { if(fr!=null){ fr.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(fw!=null){ fw.close(); } } catch (IOException e) { e.printStackTrace(); } }
}
-
任意类型文件
public static void main(String[] args) {
// (1)创建源文件对象 File src = new File("2.jpeg");// 完整的描述:路径+文件名+后缀名 // (2)创建目标文件对象 File dest = new File("3.jpg"); // (3)创建输入流 // (4)创建输出流 try ( FileInputStream fis = new FileInputStream(src); FileOutputStream fos = new FileOutputStream(dest); ) { byte[] data = new byte[10]; int len; while ((len = fis.read(data)) != -1) { fos.write(data, 0, len); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
}
-
4.5 File
-
用来表示一个文件或者一个目录
- 实际上是一个抽象的路径名
-
获取文件或目录的一些信息
-
(1)获取文件的大小
-
long length()
-
如果要获取目录的大小,必须编写递归
public long getDirLength(File dir){
if(dir.isFile()){//如果是文件,直接返回文件的大小 return dir.length(); }else if(dir.isDirectory()){ long sum = 0; File[] listFiles = dir.listFiles(); for (File sub : listFiles) {
// sum += 下一级的大小;
sum += getDirLength(sub); } return sum; } return 0;//既不是文件又不是文件夹,不存在
}
-
如果文件不存在,返回0
-
-
(2)获取文件或目录的名称
- String getName()
-
(3)获取文件或目录的路径
- String getPath():获取路径 String getAbsolutePath():获取绝对路径 String getCanonicalPath():获取规范路径,例如:../ /
-
(4)获取文件的后缀名
- String name = file.getName();//得到文件名 包含扩展名
- String ext = name.substring(name.lastIndexOf(’.’));
-
(5)获取文件的最后修改时间
-
long lastModified()
- 毫秒数
-
如果文件不存在,返回0
-
-
(6)获取上一级目录
- String getParent()
- File getParentFile()
-
-
判断
-
(1)是否是文件
-
isFile()
- 仅当file代表的文件存在,并且是个文件,才返回true
-
如果文件不存在,返回false
-
-
(2)是否是目录
-
isDirectory()
- 仅当file对象代表的目录存在,并且是个文件夹目录,才返回true
-
如果对应的不存在,返回false
-
-
(3)是否存在
- exists()
-
(4)是否隐藏
- isHidden()
-
(5)文件是否可读
- canRead()
-
(6)文件是否可写
- canWrite()
-
-
操作
-
(1)创建文件
- createNewFile()
-
(2)创建目录
-
mkdir()
- 如果父目录不存在,那么创建失败
-
mkdirs()
- 如果父目录不存在,也一并创建
-
-
(3)删除文件或目录
-
delete()
-
只能删空目录
-
如果要删除有内容的目录,需要使用递归
public void delDir(File file){
//如果是目录 if(file.isDirectory()){ //(2)先获取下一级,并删除下一级 //a:获取下一级 File[] listFiles = file.listFiles(); //b:遍历并删除下一级 for (File sub : listFiles) { //这是一个重复的过程 delDir(sub);//调用自己 } } //删除自己 file.delete();
}
-
-
(4)重命名
- renameTo(File newFile)
-
-
操作文件夹
-
获取它的下一级
- String[] list();
- File[] listFiles()
-
5 处理流
5.1 缓冲流
-
作用:增加缓冲区,提供效率
-
类型
-
BufferedInputStream
-
包装InputStream
- 例如:FileInputStream、DataInputStream、ObjectInputStream等
-
-
BufferedOutputStream
-
包装OutputStream
- 例如:FileOutputStream、DataOutputStream、ObjectOutputStream等
-
-
BufferedReader
-
包装Reader
- 例如:FileReader、InputStreamReader等
-
String readLine()
- 判断是否读完,使用 ==null
-
-
BufferedWriter
-
包装Writer
- 例如:FileWriter,OutputStreamWriter等
-
write(String) + newLine()
-
-
缓冲区的大小
-
字节流
- 8192字节
-
字符流
- 8192字符
-
-
5.2 数据流
-
作用:可以处理Java的基本数据类型+字符串(UTF-8修改版)
-
类型
-
DataOutputStream
-
writeXxx()
- writeInt(int)
- writeDouble(double)
- writeChar(char)
- writeUTF(String)
-
-
DataInputStream
-
readXxx()
- int readInt()
- double readDouble()
- char readChar()
- String readUTF()
-
-
-
注意:
-
(1)DataOutputStream写,用DataInputStream读取
-
(2)写的顺序和读的顺序要一致
- 写与读之间需要配置文件等形式进行沟通顺序和类型
-
5.3 对象流
-
作用:可以处理Java对象等
-
类型
-
ObjectOutputStream
- writeObject(Object)
- 对象的序列化
-
ObjectInputStream
- Object readObject()
- 对象的反序列化
-
-
注意
-
(1)凡是要序列化的对象,它的类型必须实现java.io.Serializable接口
- 否则会报:NotSerializableExecption
-
(2)如果属性涉及到其他的引用数据类型,那么这个类型也必须实现java.io.Serializable接口
-
(3)如果某个属性不想要序列化,那么可以在属性之前加transient
- 一旦加了这个关键字修饰,该属性的值会在序列化的过程中,被忽略
- 一旦加了这个关键字修饰,该属性在反序列化的过程中,它的值就赋默认值
-
(4)在实现java.io.Serializable接口时,最好加一个常量:序列化版本ID
- private static final long serialVersionUID = 1L;
-
(5)静态的属性不能序列化
-
5.4 打印流
-
作用:可以打印各种类型的数据,最终都是以字符的形式打印,如果是引用数据类型,就调用它的toString()
-
类型
-
PrintStream
-
代表
- System.out
-
方法
- print(xxx)
- println(xxx)
-
-
PrintWriter
-
方法
- print(xxx)
- println(xxx)
-
-
6 NIO(了解)
6.1 NIO
-
Non - Blocking IO
- 非阻塞式IO
6.2 NIO和IO的区别
-
区别一
-
IO是面向流,是单向的,从某个流中要么只能读,要么只能写
-
例如:要读文件
- FileInputStream
- FileReader
-
类型即决定可以进行的操作
-
-
NIO是面向通道+缓冲区,即可以是单向的,又可以是双向的
-
例如:ByteBuffer
-
put
- 往里写
-
get
- 往外读
-
-
例如:FileChannel
- 既可以指定为只读
- 又可以指定为可读可写
-
-
-
区别二
- IO是阻塞式的,一旦某个线程在读,此时没有可读的数据,会一直等待
- NIO是非阻塞式
-
区别三
- NIO可以使用选择器
6.3 和新的IO的API相关的
-
Path
- 是一个接口
-
Paths
- 用来获取Path的对象
- Paths.get(URI)
- Paths.get(String first, String… others)
-
Files
-
工具类
- 静态方法
-
和Path用来替代原来的File
-
方法
-
创建文件
-
createFile
- 如果文件已存在,直接报异常
-
和File类的createNewFile()区别
- 如果文件已存在,不提示
-
-
创建目录
-
createDirectory
- 替代原来的File的mkdir
- 不同的是,如果目录已存在,就会报异常
-
createDirectories
- 替代原来的File的mkdirs
- 不同的是,如果目录已存在,就会报异常
-
-
复制文件
-
copy
-
区别
- 如果目标文件不存在,直接创建
- 如果目标文件已存在,要看是覆盖模式吗
- 默认情况下,已存在,会报异常
-
-
读取文件
-
readAllLines(Path path)
-
读取文件,返回List
-
默认是StandardCharsets.UTF_8
-
可以自己指定字符编码方式
- Charset.forName(字符集名称)
-
-
-
….
-
-
6.4 通道
-
主要是四种类型
-
和文件读取和存储相关的
- FileChannel
-
和TCP服务器端使用
- ServerSocketChannel
-
和TCP的客户端使用
- SocketChannel
-
和UDP的两端使用
- DatagramChannel
-
-
必须和缓冲区结合才能使用
-
它的对象的创建
-
例如:
- FileChannel.open(xxx)
-
6.5 缓冲区
-
主要是7大类型
-
ByteBuffer
- MappedByteBuffer
-
ShortBuffer
-
IntBuffer
-
LongBuffer
-
FloatBuffer
-
DoubleBuffer
-
CharBuffer
-
除了boolean
-
-
属性
-
(1)capacity:容量
- 总大小,一旦创建就固定
-
(2)limit:限制
- 可读或可写的最大索引的位置
-
(3)position:当前位置
- 当前正在读或写的位置
-
(4)mark:标记的位置
-
0<=mark<=position<=limit<=capacity
-
-
方法
-
(1)put
-
往缓冲区写
-
或者调用通道.read(xx)
- 也相当于往缓冲区写
-
-
(2)get
-
从缓冲区取
-
或者调用通道.write(xx)
- 也相当于从缓冲区取数据
-
-
(3)flip()
- 切换读写模式
-
(4)clear()
- 重新使用缓冲区
-
-
示例
-
(1)读文件
@Test
public void test() throws IOException{
Path path = Paths.get("1.txt"); FileChannel fc = FileChannel.open(path, StandardOpenOption.READ);//打开通道 ByteBuffer bb = ByteBuffer.allocate(1024); StringBuilder sb = new StringBuilder(); while(true){ //把数据放到缓冲区 int len = fc.read(bb);//把数据装到缓冲区 对于缓冲区来说是存储,相当于put if(len<=0){ break; } //切换 bb.flip(); //从缓冲区读取数据 byte[] data = new byte[10]; bb.get(data,0,bb.limit()); // System.out.println(new String(data,0,bb.limit())); sb.append(new String(data,0,bb.limit())); bb.clear(); } System.out.println(sb);
}
-
(2)复制文件
@Test
public void testCopy()throws Exception{
long start = System.currentTimeMillis(); FileChannel fc = FileChannel.open(Paths.get("software/ideaIU-Ultimate-2017.1.4.exe"), StandardOpenOption.READ); FileChannel to = FileChannel.open(Paths.get("2.exe"), StandardOpenOption.WRITE,StandardOpenOption.CREATE_NEW); ByteBuffer bb = ByteBuffer.allocate(10);//定义缓冲区大小 while(fc.read(bb)!=-1){//读取数据到缓冲区,即往缓冲区写 相当于put bb.flip();//修改limit为position 然后position为0 没有这个,就从position开始读到limit,limit=capacity,position为写完的位置 to.write(bb); bb.clear();//limit变成capicity position=0 没有这个,那么就会重复写第一次读取的内容,一会文件大小就很大,爆了 } fc.close(); to.close(); long end = System.currentTimeMillis(); System.out.println("ByteBuffer:"+ (end-start));
}
-
(3)物理映射复制文件(速度超快)
@Test
public void test2()throws Exception{
long start = System.currentTimeMillis(); FileChannel from = FileChannel.open(Paths.get("software/ideaIU-Ultimate-2017.1.4.exe"), StandardOpenOption.READ); FileChannel to = FileChannel.open(Paths.get("3.exe"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE_NEW);//如果CREAD,如果文件已经存在不会报错,但是会从文件头开始写 MappedByteBuffer fbb = from.map(MapMode.READ_ONLY, 0, from.size()); MappedByteBuffer tbb = to.map(MapMode.READ_WRITE, 0, from.size()); tbb.put(fbb); from.close(); to.close(); long end = System.currentTimeMillis(); System.out.println("ByteBuffer:"+ (end-start));
}
-
7 length
7.1 数组
-
数组的长度
-
int len = arr.length;
- 属性
-
7.2 字符串的长度
- int len = str.length();
7.3 文件的长度
- long len = file.length();