day31 天笔记(Io流部分)
IO 流
基本概念
IO流,什么是IO?
I : Input
O : Output
通过 IO 可以完成硬盘文件的读和写。
- IO流的分类
有多种分类方式:
一种方式是按照流的方向进行分类:
以内存作为参照物,<br /> 往内存中去,叫做输入(Input)。或者叫做读(Read)。<br /> 从内存中出来,叫做输出(Output)。或者叫做写(Write)。
另一种方式是按照读取数据方式不同进行分类:
有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频文件等….
假设文件file1.txt,采用字节流的话是这样读的:
a中国bc张三fe
第一次读:一个字节,正好读到’a’
第二次读:一个字节,正好读到’中’字符的一半。
第三次读:一个字节,正好读到’中’字符的另外一半。有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取。普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都无法读取。
假设文件file1.txt,采用字符流的话是这样读的:
a中国bc张三fe
第一次读:’a’字符(’a’字符在windows系统中占用1个字节。)
第二次读:’中’字符(’中’字符在windows系统中占用2个字节。)
注意: 空格是一个字符 Asall值是32
综上所述:流的分类
输入流、输出流
字节流、字符流
Java中的IO流
Java中的IO流都已经写好了,我们程序员不需要关心,我们最主要还是掌握,在java中已经提供了哪些流,每个流的特点是什么,每个流对象上的常用方法有哪些????
java中所有的流都是在:java.io.*;下。
java中主要还是研究:怎么new流对象 与 调用流对象的哪个方法是读、哪个方法是写。
java IO 流这块有四大家族:
四大家族的首领:
java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流java.io.Reader 字符输入流<br /> java.io.Writer 字符输出流
四大家族的首领都是抽象类。(abstract class)
所有的流都实现了:java.io.Closeable接口
都是可关闭的,都有close()方法
流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占 用)很多资源。养成好习惯,用完流一定要关闭。
- 所有的输出流都实现了:java.io.Flushable接口
都是可刷新的,都有flush()方法。
养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将 通道/管道当中剩余未输出的数据强行输出完(清空管道!)刷新的作用就是清空管道。
注意:如果没有flush()可能会导致丢失数据。
- 注意:在java中只要“类名”以Stream结尾的都是字节流。以“Reader/Writer”结尾的都是字符流。
java.io包下需要掌握的流
java.io包下需要掌握的流有16个:
文件专属:
java.io.FileInputStream(掌握)
java.io.FileOutputStream(掌握)
java.io.FileReader
java.io.FileWriter转换流:(将字节流转换成字符流)
java.io.InputStreamReader
java.io.OutputStreamWriter缓冲流专属:
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream数据流专属:
java.io.DataInputStream
java.io.DataOutputStream标准输出流:
java.io.PrintWriter
java.io.PrintStream(掌握)对象专属流:
java.io.ObjectInputStream(掌握)
java.io.ObjectOutputStream(掌握)
File(重点)
java.io.FileInputStream
构造方法:
FileInputStream(String name) 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。 |
---|
常用方法:
| int read(byte[ ] b)
从该输入流读取最多 b.length个字节的数据为字节数组
int read(byte[] b, int off, int len)
从该输入流读取最多 len字节的数据为字节数组
int available():返回流当中剩余的没有读到的字节数量
long skip(long n):跳过几个字节不读 | | —- | | |
基本概念:
1、文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。
2、字节的方式,完成输入的操作,完成读的操作(硬盘—-> 内存)Java中的文件路径:
D:\course\JavaProjects\02-JavaSE\temp (IDEA会自动把\编程\,因为java中\表示转义)
以下都是采用了:绝对路径的方式。
FileInputStream fis = new FileInputStream(“D:\course\JavaProjects\02-JavaSE\temp”);
这里的 \ 写成这个 / 也是可以的。实例(程序有缺陷):
注意:
- 读到文件末尾时 返回 -1
- 在finally语句块当中,确保流一定关闭。关闭流的前提是:流不是空。流是null的时候没必要关闭
- FileInputStream 源码中抛异常了 需要对异常进行处理
- FileInputStream 创建对象时抛异常了需要对异常进行处理
- read()方法源文件抛异常了 需要对异常进行处理
- 关闭 close()的时候也需要 异常处理
public class FileInputStreamTest01 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:/course/JavaProjects/02-JavaSE/temp");
// 开始读
int readData = fis.read(); // 这个方法的返回值是:读取到的“字节”本身。
System.out.println(readData); //97
readData = fis.read();
System.out.println(readData); //98
readData = fis.read();
System.out.println(readData); //99
// 已经读到文件的末尾了,再读的时候读取不到任何数据,返回-1.
readData = fis.read();
System.out.println(readData);
readData = fis.read();
System.out.println(readData);
readData = fis.read();
System.out.println(readData);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 在finally语句块当中确保流一定关闭。
if (fis != null) { // 避免空指针异常!
// 关闭流的前提是:流不是空。流是null的时候没必要关闭。
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
- 对上面程序的改进
对第一个程序进行改进,循环方式。
分析以下这个程序的缺点:
一次读取一个字节byte,这样内存和硬盘交互太频繁,基本上时间/资源都耗费在交互上面了。能不能一次读取多个字节呢?可以。
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\course\\JavaProjects\\02-JavaSE\\temp");
/*while(true) {
int readData = fis.read();
if(readData == -1) {
break;
}
System.out.println(readData);
}*/
// 改造while循环
int readData = 0;
while((readData = fis.read()) != -1){
System.out.println(readData);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
int read(byte[ ] b)
read (byte[] b, int off, int len)
往byte[]数组当中读:一次最多读取 b.length 个字节,减少硬盘和内存的交互,提高程序的执行效率。
将 byte 数组转换成String类型的字符串: 调用: String 类 的构造方法 传入byte数组 转换为 String类型
语法格式:
String(Byte,0,length-1)
FileInputStream fis = null;
try {
// 开始读,采用byte数组,一次读取多个字节。最多读取“数组.length”个字节。
byte[] bytes = new byte[4]; // 准备一个4个长度的byte数组,一次最多读取4个字节。
// 这个方法的返回值是:读取到的字节数量。(不是字节本身)
int readCount = fis.read(bytes);
System.out.println(readCount); // 第一次读到了4个字节。
// 将字节数组全部转换成字符串
//System.out.println(new String(bytes)); // abcd
// 不应该全部都转换,应该是读取了多少个字节,转换多少个。
System.out.println(new String(bytes,0, readCount));
readCount = fis.read(bytes); // 第二次只能读取到2个字节。
System.out.println(readCount); // 2
// 将字节数组全部转换成字符串
//System.out.println(new String(bytes)); // efcd
// 不应该全部都转换,应该是读取了多少个字节,转换多少个
//不这样处理的话输出efcd
System.out.println(new String(bytes,0, readCount));
readCount = fis.read(bytes); // 1个字节都没有读取到返回-1
System.out.println(readCount); // -1
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
文件里面的内容:abcdef
下面这个需要掌握
public class FileInputStreamTest04 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("chapter23/src/tempfile3");
// 准备一个byte数组
byte[] bytes = new byte[4];
/*while(true){
int readCount = fis.read(bytes);
if(readCount == -1){
break;
}
// 把byte数组转换成字符串,读到多少个转换多少个。
System.out.print(new String(bytes, 0, readCount));
}*/
int readCount = 0;
while((readCount = fis.read(bytes)) != -1) {
System.out.print(new String(bytes, 0, readCount));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
IDEA中的路径
相对路径的话呢? 相对路径一定是从当前所在的位置作为起点开始找!
IDEA默认的当前路径是哪里? 工程Project的根就是IDEA的默认当前路径。
如果该路径下 没有此文件会报错
fis = new FileInputStream("tempfile3");
//fis = new FileInputStream("chapter23/tempfile2");
//fis = new FileInputStream("chapter23/src/tempfile3");
fis = new FileInputStream("chapter23/src/com/bjpowernode/java/io/tempfile4");
FileInputStream类的其它常用方法
int available(): 返回 流 当中剩余的没有读到的字节数量
long skip(long n): 跳过几个字节不读
列子:
public class FileInputStreamTest05 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("tempfile");
System.out.println("总字节数量:" + fis.available());
// 读1个字节
//int readByte = fis.read();
// 还剩下可以读的字节数量是:5
//System.out.println("剩下多少个字节没有读:" + fis.available());
// 这个方法有什么用?
//byte[] bytes = new byte[fis.available()]; // 这种方式不太适合太大的文件,因为byte[]数组不能太大。
// 不需要循环了。
// 直接读一次就行了。
//int readCount = fis.read(bytes); // 6
//System.out.println(new String(bytes)); // abcdef
// skip跳过几个字节不读取,这个方法也可能以后会用!
fis.skip(3);
System.out.println(fis.read()); //100
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
FileOutputStream
文件的写入 内存———> 硬盘
文件字节输出流,负责写。
- 构造方法:
FileOutputStream(String name)
FileOutputStream(String name, true) 这个构造方法表示在文件的末尾追加
- 案例:
注意:
- 文件不存在的时候会自动新建
- 写完之后一定要刷新
- fos = new FileOutputStream("chapter23/src/tempfile3");
这种方式谨慎使用,这种方式会先将原文件清空,然后重新写入。
- fos = new FileOutputStream("chapter23/src/tempfile3", true);
以追加的方式在文件末尾写入。不会清空原文件内容。
这里的true 表示的含义是 是否以文件追加的方式 在文件末尾写入
不加 true 这个默认参数的话是 默认将文件清空的
将String类型转换为数组:
String类型的对象 . getBytes();
public class FileOutputStreamTest01 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
// myfile文件不存在的时候会自动新建!
// 这种方式谨慎使用,这种方式会先将原文件清空,然后重新写入。
//fos = new FileOutputStream("myfile");
//fos = new FileOutputStream("chapter23/src/tempfile3");
// 以追加的方式在文件末尾写入。不会清空原文件内容。
fos = new FileOutputStream("chapter23/src/tempfile3", true);
// 开始写。
byte[] bytes = {97, 98, 99, 100};
// 将byte数组全部写出!
fos.write(bytes); // abcd
// 将byte数组的一部分写出!
fos.write(bytes, 0, 2); // 再写出ab
// 字符串
String s = "我是一个中国人,我骄傲!!!";
// 将字符串转换成byte数组。
byte[] bs = s.getBytes();
// 写
fos.write(bs);
// 写完之后,最后一定要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
文件的复制
- 文件的复制原理
图
- 案例:
FileReadr
能用记事本编辑的都是普通文本文件,普通文本文件和后缀无关
字节流是 Byte 数组 字符流是 char 数组
copy1
copy2
缓冲专属
BufferedRead
1.基本概念
带有缓冲区的字符输入流。
使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组。自带缓冲。
- 构造方法与其它流不同
语法格式:
BufferedReader( Reader in )
说明:
看Api得出的:
Reader 是一个抽象类
FileReader类是Reader类的子类 它的父类是InputStreamReader类
InputStreamReader类的父类是Reader
- 特有的方法:
- readerLine()
这个方法读到文件末尾结束
作用:读取一个文本行 (读一行) 不带换行符
案例
说明:
- 当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流
- 外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流。
看源代码得出的:
- BufferedReader中有一个实例变量 : Reader in
- Reader in 就是一个节点,in 是一个属性,通过构造方法进行赋值
- bufferedReader就是一个包装
- 传入的节点的原理:
- 将传入的节点流赋值给 Reader in 这个属性
- bufferReader这个流里面有一个close(),这个close ()里面有一个in在调用close(),所以当BufferedReader流 去关闭的时候里面的流会自动关闭
得出的结论:
- 对一个包装流来说,只需要关闭最外层的就行,里面的节点流会自动关闭。 ```java public class BufferedReaderTest01 { public static void main(String[] args) throws Exception{
FileReader reader = new FileReader(“Copy02.java”); // 当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流。 // 外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流。 // 像当前这个程序来说:FileReader就是一个节点流。BufferedReader就是包装流/处理流。 BufferedReader br = new BufferedReader(reader);
// 读一行 /*String firstLine = br.readLine(); System.out.println(firstLine);
String secondLine = br.readLine(); System.out.println(secondLine);
String line3 = br.readLine(); System.out.println(line3);*/
// br.readLine()方法读取一个文本行,但不带换行符。 String s = null; while((s = br.readLine()) != null){
System.out.print(s);
}
// 关闭流 // 对于包装流来说,只需要关闭最外层流就行,里面的节点流会自动关闭。(可以看源代码。) br.close(); } } ```
转换流
BufferedReader02
通过对应的构造方法将字节流
数据专属流
标准输出流
println
logger
日志工具
File类
- 基本概念
File类和四大家族没有关系,所以File类不能完成文件的读和写。
File对象代表什么?
文件和目录路径名的抽象表示形式。
C:\Drivers 这是一个File对象
C:\Drivers\Lan\Realtek\Readme.txt 也是File对象。
一个File对象有可能对应的是目录,也可能是文件。
File只是一个路径名的抽象表示形式。需要掌握File类中常用的方法
filetest02
拷贝目录
对象专属流