I/O流
输入流:磁盘 -----》内存;
输出流:内存 -----》磁盘;
- 输入流:InputStream、Reader;
- 输出流:OutputStream、Writer;
一、File
1.1、常见的文件操作
-
创建文件对象相关构造器和方法;
-
new File(String pathname) //根据路径构建一个File对象 new File(File parent,String child) //根据父目录文件 + 子路径构建 new File(String parent,String child) //根据父目录 + 子路径构建
-
案例:
public class FileCreate {
public static void main(String[] args) {
FileCreate fileCreate = new FileCreate();
fileCreate.createFile1();
fileCreate.createFile2();
fileCreate.createFile3();
}
// 方式一、new File(String pathname)
public void createFile1() {
String filePath = "";
File file = new File(filePath);
// 之后搭配try-catch语句块
file.createNewFile();
System.out.println("文件创建成功");
}
// 方式二、new File(File parent,String child) 根据父目录文件 + 子路径构建
public void createFile2() {
File parentFile = new File("e:\\"); // 其中\\,头一个是转义字符,否则如果只有一个就不合法,检测不出来
String fileName = "new2.txt";
File file = new File(parentFile,fileName); //此处file对象,在java程序中,知识一个对象,尚且存在于内存中
// try-catch语句块
file.createNewFile(); // 将内存中的file写入到磁盘中
System.out.println("文件创建成功");
}
// 方式三、new File(String parent,String child) 根据父目录 + 子目录构建,可以在父目录下创建多个子文件
public void createFile3() {
String parentPath = "e:\\";
String fileName = "new3.txt";
File file = new File(parentPath,fileName);
// try-catch语句块
file.createNewFile();
System.out.println("文件创建成功")
}
}
1.2、File类的方法
序号 | 方法名 | 描述 |
---|---|---|
1 | getName() | 获取文件名 |
2 | getAbsolutePath() | 获取绝对路径 |
3 | getParent() | 获取父级目录 |
4 | length() | 获取文件内字节长度 |
5 | exists() | 判断文件是否存在 |
6 | isFile() | 判断文件是否是文件 |
7 | isDirectory() | 判断文件是否是目录 |
public class FileInformation{
public static void main(String[] args) {
}
}
1.3、目录操作以及文件删除
- mkdir-----创建一级目录;
- mkdirs—创建多级目录;
- delete----删除空白目录或文件;
在java中,目录也被当做文件;
- 判断文件“e:\new1.txt”是否存在,如果存在就删除;
- 判断目录“e:\demo2”是否存在,如果存在就删除;
// 删除文件
public void deleteFile01() {
String filePath = "e:\\new1.txt";
File file = new File(filePath);
if(file.exists){
if(file.delete()){
System.out.println("文件已经删除");
}else{
System.out.println("文件删除失败");
}
}else{
System.out.println("文件不存在");
}
}
//删除目录
public void deleteFile02() {
String filePath = "e:\\demo";
File file = new File(filePath);
if(file.exists){
if(file.delete()){
System.out.println("目录已经删除");
}else{
System.out.println("目录删除失败");
}
}else{
System.out.println("目录不存在");
}
}
// 创建多级目录
public void mkdirsDirectory() {
String directoryPath = "e:\\demo\\a\\b\\c";
File file = new File(filePath);
if(file.exists){
System.out.println("目录已经存在");
}else{
if(file.mkdirs()){ // mkdirs()创建
System.out.println("目录创建成功");
}else{
System.out.println("目录创建失败");
}
}
}
/*
疑问:
如果只有demo一级目录,却没有a/b/c这样的子目录,会怎么样呢?
是删除demo之后,从新新建;
还是在demo目录之后,再新建子级目录呢/
*/
二、I/O
- I/O(Input/Output),I/O技术处理数据传输,如读、写文件,网络通讯等;
- Java程序中,对于数据的输入、输出操作以 “流(Stream)” 的方式进行 ;
- Java.io包下,提供各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据。
2.1、I/O原理
- 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中;
- 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中;
2.2、流的分类
- 按操作数据单位不同分为:字节流(8 bit)、字符流(字符);
- 字节流适用在二进制文件,可以无损;
- 字符流适用于文本文件;
- 按流向的不同分为:输入流、输出流;
- 按流的角色不同分为:节点流、处理流、包装流
抽象类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
注意:
- InputStream、OutputStream、Reader、Writer都是抽象类,是所有流的超类(父类);
- 使用的都是他们的子类
2.3、流和文件的关系
三、字节流
InputStream:字节输入流常用子类:
- FileInputStream:文件输入流;
- BufferedInputStream:缓冲字节输入流;
- ObjectInputStrean:对象字节输入流;
此处需要各个流之间的关系图
3.1、FileInputStream
此处应该有FileInputStream的方法表
- read()方法,如果到达文件的末尾,则返回-1
- 单个 字节的读取,效果较低;
实例:读取源文件,并将文件呈现出来;
public class FileInputStreamDemo {
public static void main(String[] args){
}
public void readFile1() {
String filePath = "e:\\demo.txt";
int readDate = 0;
// 创建FileInputStream 对象,用于读取文件
// 此处应该使用try-catch语句块
FileInputStream fileInputStream
= new FileInputStream(filePath);
while((readDate = fileInputStream.read()) != -1) {
System.out.println((char)readDate); //转换成char显示
}
}
}
使用read(byte[] b)来提高读取速度
public class FileInputStreamDemo {
public static void main(String[] args){
}
public void readFile1() {
String filePath = "e:\\demo.txt";
int readDate = 0;
// 字节数组
byte[] buf = new byte[8]; //一次性读取8个字节
FileInputStream fileInputStream = null;
// 创建FileInputStream 对象,用于读取文件
// 此处应该使用try-catch语句块
fileInputStream
= new FileInputStream(filePath);
while(fileInputStream.read(buf))!= -1) {
System.out.println((char)readDate); //转换成char显示
}
}
}
3.4、FileReader
此处应该有FileReader的关系流程图,继承了谁
- FileReader和FileWriter是字符流,即按照字符来操作IO;
- FileReader相关方法:
- new FileReader(File/String)
- read:每次读取单个字符,返回该字符,如果到文件末尾则返回-1;
- read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾,则返回-1(数组就相当于是缓冲区);
- 相关API:
- new String(char[]):将char[]转换成String;
- new String(char[],off,len):将char[]的指定部分转换成String;
实例:从读取“e:\story.txt”
public class FileReaderDemo {
public static void main(String[] args){
String filePath = "e:\\story.txt";
FileReader fileReader = null;
int data = 0;
try{
// 新建FileReader对象
fileReader = new FileReader(filePath);
// 读取文件
// 使用 read()读取
while((data = fileReader.read()) != -1){
System.out.println((char) data);
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(fileReader != null){
fileReader.close();
}
}catch(){
}
}
}
}
public void readFile2(){
String filePath = "e:\\story.txt";
FileReader fileReader = null;
int readLen = 0;
char[] buf = new char[8];
try{
// 新建FileReader对象
fileReader = new FileReader(filePath);
// 读取文件
// 使用 read(char[])读取,返回的是实际读取数
while((readLen = fileReader.read(buf)) != -1){
System.out.println(new String(buf,0,readLen));
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(fileReader != null){
fileReader.close();
}
}catch(){
}
}
}
3.5、FileWriter
此处应该有关系图;
- FileWriter常用方法
- new FileWriter(File/String):覆盖模式,相当于流的指针在首端;
- new FileWriter(File/String,true):追加模式,相当于流的指针在尾端;
- write(int):写入单个字符;
- write(char[]):写入指定数组;
- write(char[],off,len):写入指定数组的指定部分;
- write(String):写入整个字符串;
- write(String,off,len):写入字符串的指定部分;
- 相关API:String类:toCharArray:将String转换成char[]
注意:FileWriter使用后,必须要关闭流,close()或者刷新–flush(),否则写入不到指定的文件;
因为还在内存中,所以刷新之后,就可以将内存中数据刷新到指定文件。
public class FileWriter{
public static void main(String[] args){
String filePath = "e:\\note.txt";
// 创建FileWriter对象
FileWriter fileWriter = null;
char[] chars = {'a','b','c'};
try{
fileWriter = new FileWriter(filePath); // 目前默认是覆盖模式写入
// 写入单个字符
fileWriter.write('H');
// 写入字符数组
fileWriter.write(chars);
// 写入指定数组的指定部分
fileWriter.write("张韬".toCharArray(),0,3);
// 写入字符串
fileWriter.write("你好");
// 写入字符串的指定部分
fileWriter.write("上海北京",0,2);
// 如果数据量大,则循环写入
}catch(IOException e){
e.printStackTrace();
}finally{
// 对于fileWriter,一定要关闭流,或者flush
try{
fileWriter.close()
}catch(IOException e){
e.printStackTrace();
}
}
}
}
疑问点:为什么这个没有覆盖,而是追加?
解释:因为都是一个对象
//close()源码
关闭文件流:等价与flush() + 关闭
四、节点流和处理流
- 节点流可以从一个特定的数据源读写数据,如:FileReader、FileWriter;
- 针对特定数据源:比如说针对文件;
- 针对字符文件:FileReader、FileWriter;
- 针对二进制文件:FileInputStream、FileOutputStream;
- 处理流(也称为包装流),是连接在已经存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,如BufferedReader、BufferedWriter;
节点流
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
访问管道 | PipedInputStream | PipledOutputStream | PipledReader | PipledWriter |
访问字符串 | StringReader | StringWriter |
处理流
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream | ||
打印流 | PrintStream | PrintWriter | ||
特殊流 | DataInputStream | DataOutputStream |
注意:BufferedReader类中,有属性Reader,即可以封装一个节点流,而节点流可以是任意的,只要Reader子类
public class BufferedReader extends Reader {
private Reader in;
}
4.1、节点流以及处理流区别
- 节点流是底层流/低级流,直接和数据源相接;
- 处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。
- 处理流对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连;
处理流的功能主要体现在以下方面:
- 性能的提高:主要以增加缓冲的方式来提高输入输出的效率;
- 操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量数据,使用更加灵活方便。
此处需要重新观看 -----节点流以及处理流的设计模式
五、处理流
-
最常见的处理流:BufferedReader、BufferedWriter;
-
BufferedReader以及BufferedWriter属于字符流,是按照字符来读取数据的;
-
关闭时,只需要关闭外层流即可;
-
BufferedReader bufferedReader = new BufferedReader(FileReader);
-
关闭外层流的时候,外层的流(包装流)会自动地将内部流(节点流)也关掉;
-
实例:演示BufferedReader
public class BufferedReaderDemo {
public static void main(String[] args) {
String filePath = "e:\\note.txt";
//创建BufferedReader对象
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
//读取
String line;//按行读取,效率高
// 当返回null,表示文件读取完毕
while((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
// 关闭流
bufferedReader.close();
// 底层源码中,包装流会自动关掉节点流
}
}
- 注意:此处应该看源码;
- 了解Thinking in java
实例:演示BufferedWriter
public class BufferedWriterDemo {
public static void main(String[] args) {
String filePath = "e:\\note.txt";
//创建BufferedWriter
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
//写入
bufferedWriter.write("hello,开始");
bufferedWriter.newLine();
bufferedWriter.write("hello2,开始");
bufferedWriter.write("hello3,开始");
bufferedWriter.close();
//
}
}
// new FileWriter(filePath,true); 表示以追加的方式写入
// new FileWriter(filePath) 表示以覆盖的方式写入
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));
注意:覆盖与追加需要深究
5.2、Buffered拷贝
public class BufferedCopyDemo {
public static void main(String[] args) {
String srcFilePath = "e:\\note.txt";
String destFilePath = "e:\\note2.txt";
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
String line;
try{
bufferedReader = new BufferedReader(new FileReader(srcFilePath));
bufferedWriter = new BufferedWriter(new FileWriter(destFilePath));
// readLine(),读取一行数据,但是没有换行
while((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line);
//换行
bufferedWriter.newLine();
}
}catch(IOException e){
e.printStackTrace();
}finally{
// 关闭流
// 加上一个try-catch语句块
if(bufferedReader != null) {
bufferedReader.close();
}
if(bufferedWriter != null) {
bufferedWriter.close();
}
}
}
}
注意:
- BufferedReader以及BufferedWriter 是字符操作;
- 不要去操作 二进制文件,可能造成文件损坏;
- 二进制文件:声音、视频、doc、pdf