目录
一、 I/O(Input/Output)流是什么?
什么是流?
流定义:
流是一组有顺序
的,有起点和终点的字节集合,是对数据传输的总称或抽象。
即
数据在两设备间的传输称为流
,
流的本质是数据传输
。
输入输出如何理解?
I/O 流定义:I/O流 即 输入流和输出流。
分析:输入就是将数据从各种输入设备(包括文件、键盘等)读取到内存中。
输出就是将数据写入到各种输出设备(如文件、显示器、磁盘)中.
键盘为标准的输入设备,显示器为标准的输出设备,文件既是输入设备、也是输出设备。
流的分类?
流的方向:
输入流:程序可以中读取数据的流。
输出流:程序能向其中写入数据的流。
流的单位:
字节流:以字节为单位传输数据的流
字符流:以字符为单位传输数据的流
流的功能:
节点流:直接和文件进行交互
处理流:不是直接作用在文件上
详解:
1. 一种方式是以
按照流的方向
进行分类
输入流:以内存为参照物:往内存中去,叫做输入(Input),或者叫做读(Read)。
输出流:从内存中出来,叫做输出(Output),或者叫做写(Write)
2.另一种方式是以按照
读取数据方式
不同进行分类
字节流:按照
字节的方式读取数据
,称为字节流。一次读取1个字节,等同于一次读取8个二进制位。这种
流什么类型的文件都可以读取
。如文本文件、图片、声音、文件、视频文件。
字符流:按照
字符的方式读取数据
,称为字符流、
一次读取一个字符
,这种流是为了方便读取普通的文件文件而存在的,这种流不能读取:图片、声音、视频等文件,
只能读取纯文本文件
,连word文件都可以读取。
二、 字节流、字符流、缓冲流。
字节流、字符流能做什么?
字节流图解:
输入流
输出流
字节流读取文件?
public static void main(String[] args)throws IOException {
// 创建输入流对象
FileInputStream a = new FileInputStream("a.txt");
// 定义临时变量,每次读取数据让变量记录
int i;
// 读取到-1的时候说明读取结束,跳出循环
while ((i=a.read())!=-1){
System.out.print((char) i+" ");
}
// 关闭流释放资源
a.close();
}
字节流写出文件?
public static void main(String[] args)throws IOException {
// 创建字节输出流对象 不清楚原有内容加上true
FileOutputStream a = new FileOutputStream("a.txt",true);
// 写入的字符串返回字节数组写入
a.write("Hello,world".getBytes());
// 关闭流释放资源
a.close();
}
字节流缓冲区拷贝文件?
public static void main(String[] args) throws IOException {
// 创建字节输入输出流对象
FileInputStream a = new FileInputStream("a.txt");
FileOutputStream b = new FileOutputStream("b.txt");
byte [] arr = new byte[1024];
// 创建临时变量
int i;
while ((i=a.read(arr))!=-1){
// 读取的数据写入进去 完成文件拷贝
b.write(arr,0,i); // 数组 从0开始 到i结束写入
}
// 关闭流释放资源
a.close();b.close();
}
字节流缓冲流拷贝文件?
public static void main(String[] args) throws IOException {
// 创建字节输入输出缓冲流对象
BufferedInputStream a = new BufferedInputStream(new FileInputStream("a.txt"));
BufferedOutputStream b = new BufferedOutputStream(new FileOutputStream("b.txt"));
// 创建临时变量
int i;
while ((i = a.read()) != -1) {
// 读取的数据写入进去 完成文件拷贝
b.write(i); //
}
// 关闭流释放资源
a.close();
b.close();
}
字符流图解:
输入流
输出流
字符流读取文件?
public static void main(String[] args) throws IOException {
// 创建字符流对象
FileReader fileReader = new FileReader("E:\\a.txt");
// 创建临时变量 存储数据
int i;
while ((i=fileReader.read())!=-1){
System.out.println((char) i);
}
// 关闭流释放资源
fileReader.close();
}
字符流写出文件?
public static void main(String[] args) throws IOException {
// 创建字符输出流对象 写入文件
FileWriter fileWriter = new FileWriter("E:\\b.txt");
// 写入
fileWriter.write("你好,世界");
// 关闭流释放系统资源
fileWriter.close();
}
字符流拷贝文件?
public static void main(String[] args) throws IOException {
// 创建输入输出流对象
FileReader a = new FileReader("E:\\a.txt");
FileWriter b = new FileWriter("E:\\b.txt");
// 定义临时变量
int i ;
// 读取到的写入进去
while ((i=a.read())!=-1){
b.write(i);
}
// 关闭流释放系统资源
a.close();b.close();
}
字符缓冲区拷贝文件?
public static void main(String[] args) throws IOException {
// 创建输入输出流对象
FileReader a = new FileReader("E:\\a.txt");
FileWriter b = new FileWriter("E:\\b.txt");
// 定义字符数组
char[] chars = new char[1024];
// 定义临时变量
int i ;
// 读取到的存储到数组在写入数据
while ((i=a.read(chars))!=-1){
b.write(i);
}
// 关闭流释放系统资源
a.close();b.close();
}
字符缓冲流拷贝文件?
public static void main(String[] args) throws IOException {
// 创建缓冲流对象
BufferedReader a = new BufferedReader(new FileReader("a.txt"));
BufferedWriter b = new BufferedWriter(new FileWriter("b.txt"));
// 定义临时变量
String c = null;
// 循环每次读取一行文本
// readLine不会读取到回车换行符 new Line可以读取到回车换行符
while ((c=a.readLine())!=null){
b.write(c);
b.newLine();
}
// 关闭流释放系统资源
a.close();b.close();
}
字符流底层是什么??
解决问题:字符流底层通过字节流 + 编号表的形式读取。
编号表: GBK-> 一个中文占2个字符
UTF-8-> 一个中文占3个字符
例如windows txt文件默认是utf-8,java编译时也应该是utf-8,否则会出现乱码问题。
转换流
当文件含有中文、英文、数字时,使用字节流将文件内容在内存中显示
,英文和数字显示正常,中文却现实乱码,可以使用转换流将其转化为字符流显示在内存中
。
转换流:InputStreamReader: 将InputStream转换为Reader
OutputStreamWriter: 将Writer转换为OutputStream
作用:
文本文件在硬盘中以
字节流的形式存储时
,
通过InputStreamReader读取后转化为字符流给程序处理,程序处理的字符流通过OutputStramWriter转化为字节流保存。
特点:
读取到的字节数据经过指定编码转换为字符。
可对读取到的字符数据经过指定编码转换成字节。
何时使用转换流?
当字节和字符之间有转换动作时;
流操作的数据需要编码或解码时;
作用:提供字节流与字符流之间的转换,很多时候使用转换流来处理文件乱码问题,实现编码和解码的功能。
解码:字节,字节数组->字符、字符数组
编码:字符,字符数组->字节、字节数组
public static void main(String[] args) throws IOException {
// 创建缓冲流对象 指定编码格式
InputStreamReader a = new InputStreamReader(new FileInputStream("a.txt"), "utf-8");
OutputStreamWriter b = new OutputStreamWriter(new FileOutputStream("b.txt"), "utf-8");
// 创建 字符缓冲流
BufferedReader c = new BufferedReader(a);
BufferedWriter d = new BufferedWriter(b);
String e;
while ((e=c.readLine())!=null){
d.write(e);
d.newLine();
}
// 关闭流释放系统资源
c.close();d.close();
}
三、File类
File类可以做什么?
定义:File类是I/O包中唯一代表磁盘文件本身的对象。向文件名、路径、目录等等
作用:用于封装一个路径,提供了一系列的方法用于操作该路径所指向的文件。
File类的构造方法
public static void main(String[] args) throws IOException {
// 指定路径创建文件夹对象
File file = new File("E:\\a.txt");
// 父路径 子路径 创建文件夹对象
File file2 = new File("E:","a.txt");
// File类的父路径 子路径
File file3 = new File(new File("E:"),"a.txt");
}
File类的常用方法
public static void main(String[] args)throws IOException {
// 创建目录对象
File file = new File("E:\\a.txt");
// 判断目录或文件是否存在,存在true,反之false
System.out.println(file.exists());
// 删除目录或文件夹
System.out.println("E:\\a.txt");
// 当File对应的文件或目录不存在时,创建一个新的文件,成功true,反之false。
System.out.println(file.createNewFile());
// 返回文件夹或文件名称
System.out.println(file.getName());
// 返回file对象对应的路径
System.out.println(file.getPath());
// 返回file对象对应的绝对路径
System.out.println(file.getAbsoluteFile());
// 返回路file对象对应的父目录
System.out.println(file.getParent());
//判断文件是否可读
System.out.println(file.canRead());
//判断文件是否可写
System.out.println(file.canWrite());
// 判断是否是文件
System.out.println(file.isFile());
// 判断是否是文件夹
System.out.println(file.isDirectory());
// 判断对应的文件是否是绝对路径
System.out.println(file.isAbsolute());
//返回1970年1月1日0时0分0秒最后修改时间的毫秒值
System.out.println(new Date(file.lastModified()));
// 返回文件的长度
System.out.println(file.length());
}
File遍历文件夹
public static void main(String[] args)throws IOException {
// String [ ] list : 列出指定目录的全部内容,只是列出名称
File file = new File("E:");
String[] list = file.list();
for (String a:list){
System.out.println(a);
}
// String [] list FilenameFilterfilter 接受一个FilenameFilter参数,通过该参数可以列出符合条件的文件
File file2 = new File("E:");
String[] list1 = file2.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
File file1 = new File(dir,name);
return name.endsWith("txt");
}
});
// File [] listFiles 返回一个包含了File对象所有子文件和子目录的File数组
System.out.println(Arrays.toString(list1));
File file3 = new File("E:");
File[] files = file3.listFiles();
System.out.println(Arrays.toString(files));
}
public static void main(String[] args) throws IOException {
// 遍历文件夹
File file = new File("E:");
// 判断是否是文件夹
if (file.isDirectory()) {
// 创建数组
String[] list = file.list();
// 转换流循环遍历
Arrays.stream(list).forEach((s -> System.out.println(s)));
}
// 筛选文件夹
File file2 = new File("E:");
// 判断是否是文件夹
if (file2.isDirectory()) {
String[] list2 = file.list((dir, name) -> name.endsWith("txt"));
Arrays.stream(list2).forEach((s -> System.out.println(s)));
}
// 遍历指定目录下的文件名称
bian(new File("E:"));
}
public static void bian(File dir){
File[] files = dir.listFiles();
for (File a:files){
if(a.isFile()){
System.out.println(a.getName());
} else if (a.isDirectory()) {
if((a.listFiles())!=null){
bian(a);
}
}
}
}
递归删除文件及目录
public static void main(String[] args) throws IOException {
//在使用该方法时需要判断当前目录下是否存在文件,如果存在则需要先删除内部文件然后在删除空的文件夹
shan(new File("E:"));
}
public static void shan(File dir){
// 创建File数组
File[] files = dir.listFiles();
// 循环遍历
for (File a:files){
// 判断是否为文件
if(a.isFile()){
a.delete();
// 判断是否为文件夹
}else if(a.isDirectory()){
// 判断文件夹是否为空
if ((a.listFiles())!=null){
shan(a);
}
}
a.delete();
}
}
RandomAccesseFile
定义:不属于流类,但具有读写文件数据的功能。
作用:可以随机从文件的任何位置开始并以指定的操作权限(只读、写入)执行读取数据的操作。
实现原理:
(1) 新建RandomAccessFile对象时,该对象的文件记录指针会在文件开始出(表示为0的位置)
(2)读写的n个字节后,文件记录指针会向后移动n个字节。
(3)除了按顺序读写外,RandomAccseeFile对象还可以自由的移动记录指针,既可以向前移动,也可以向后移动。
public static void main(String[] args) throws IOException {
// 创建对象, 写入的方式写入。
RandomAccessFile c = new RandomAccessFile("a.txt", "rw");
// ReadLine 从指针文件当去指针读取下一行内容
String s = c.readLine();
// 字符串转换为int类型 -1
int i = Integer.parseInt(s) - 1;
if (i > 0) {
System.out.println("剩余" + i + "次");
// seek,设定读写指针的位置,与文件开头相隔pos个字节数
c.seek(2); // 与开头相隔2个
// 转换为字节数组写入
c.write((i + "").getBytes());
} else {
System.out.println("没了");
}
c.close();
}
对象序列化
定义:java对象转换成一个I/O流中字节序列的过程
作用:可以将对象中的数据保存到磁盘上。
功能类
public class Day_01 implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Day_01(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Day_01{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
public static void main(String[] args) throws Exception {
write();
read();
}
public static void write() throws IOException {
ObjectOutputStream b = new ObjectOutputStream(new FileOutputStream("a.txt"));
Day_01 day_01 = new Day_01("a", 15);
b.writeObject(day_01);
b.close();
}
public static void read() throws IOException, ClassNotFoundException {
ObjectInputStream c = new ObjectInputStream(new FileInputStream("a.txt"));
Object o = c.readObject();
System.out.println(o);
c.close();
}
NIO
NIO了解
定义:NIO即new n/o, 处理输入输出的新功能。
NIO的三大核心
Buffer(缓冲器): 是一个数组缓冲器,读取或写出到channnel中的对象都会先放在Buffer中(它是双向的)。
Channel(通道):对传统的输入/输出的模拟,在NIO中,所有的数据都需要通过通道流的形式传输。
Selecter(选择器):用于监听多个通道的时间,主要作用于线程(多线程进行讲解)。
注意:通道本身不能完成传输,需要依赖于缓冲器,两者是并存的。
Buffer缓冲器
作用:主要用于和Channel通道配合,完成数据的传输。
说明:Buffer是一个抽象类,它需要使用其子类:ByteBuffer、charBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和shortBuffer。
方法:
Capacity() 容量
Limit() 可以操作到哪个索引(界限)
Position() 当前准备操作的索引
Mark() 标记,用来记录当前position 的值
Reset() 如果position的值发生了变化,那么通道随reset可以反馈mark记录的那个值
Put() 向缓冲器中添加数据
Get() 获取缓冲器中的数据
public static void main(String[] args) throws Exception {
// 写入模式,缓冲器放入2个字节,容量为5,界限为5,准备索引为2
ByteBuffer allocate = ByteBuffer.allocate(5); // 分配新的字节缓冲区
allocate.put("a".getBytes());
allocate.put("b".getBytes());
System.out.println(allocate.capacity()); // 容量
System.out.println(allocate.limit()); // 可以操作到哪个索引
System.out.println(allocate.position()); // 准备操作的索引
// 切换读取模式
allocate.flip();
System.out.println(allocate.capacity());
System.out.println(allocate.limit());
System.out.println(allocate.position());
// 标记
allocate.mark();
// 放入字节数组,转为字符串读取
byte[] bytes = new byte[2];
allocate.get(bytes);
System.out.println(new String(bytes));
System.out.println(allocate.capacity());
System.out.println(allocate.limit());
System.out.println(allocate.position());
// mark 反馈记录的值
allocate.reset();
allocate.get(bytes);
System.out.println(new String(bytes));
System.out.println(allocate.capacity());
System.out.println(allocate.limit());
System.out.println(allocate.position());
}
channel通道
定义:Channel是一个接口对象,从Channel中读取数据,也可以将数据写道Channel中。
方法:
Int write() 从给定的缓冲区写入这个通道的字节序列
Long size() 返回该通道文件的当前大小
Int read() 从这个通道读取一个字节序列到给定的缓冲区
Long transferTo() 读取该通道文件中给定位置的字节数,将它们写入目标通道中
案例:使用通道 缓冲器 实现对文件的拷贝
public static void main(String[] args) throws Exception {
// 创建对象
FileInputStream a = new FileInputStream("a.txt");
FileOutputStream b = new FileOutputStream("b.txt");
// 创建通道
FileChannel c = a.getChannel();
FileChannel d = b.getChannel();
//创建缓冲器
ByteBuffer allocate = ByteBuffer.allocate(1024);
// 读取到的数据放进通道中,切换读取模式,写入通道,清楚缓冲器数据。
while ((c.read(allocate)) != -1) {
allocate.flip();
d.write(allocate);
allocate.clear();
}
// 关闭流释放系统资源
a.close();
b.close();
c.close();
d.close();
}
案例:使用RandomAccessFile创建通道拷贝文件
public static void main(String[] args) throws Exception {
// 创建对象
RandomAccessFile a = new RandomAccessFile("a.txt","rw");
RandomAccessFile b = new RandomAccessFile("a.txt","rw");
// 创建通道
FileChannel c= a.getChannel();
FileChannel d = b.getChannel();
// 读取该通道文件中给定位置的字节数,将它们写入目标通道中。
long l = c.transferTo(0, c.size(), d);
if(l>0){
System.out.println("拷贝成功");
}
}
NIO.2 path接口和Files工具类
Files工具类
常用方法:
createDirectories( ) 创建多级文件夹
createFile( ) 创建文件
write( ) 将文本写入文件,并以传入指定的写入方式。
readllLines( ) 从文件中读取所有行
size( ) 返回文件的大小,以字节为单位
public static void main(String[] args) throws Exception {
// 创建多级文件夹
Path c = Paths.get("E:\\DD\\CC");
Files.createDirectories(c);
// 创建多级文件
Path path = Paths.get("E:\\a.txt");
Files.createFile(path);
// 从文件中读取所有行,并传入指定的写入方式
ArrayList<String> d = new ArrayList<>();
d.add("D行");
d.add("李S");
Files.write(path, d, StandardOpenOption.APPEND); // 路径 内容 枚举
// 从文件中读取所有行
List<String> strings = Files.readAllLines(path);
System.out.println(strings);
// 返回文件的大小,以字节为单位。
long size = Files.size(path);
System.out.println(size);
}