一、I/O流
a. 基础知识
1. I/O流是什么
I:Input
O:Output
2. IO流的分类
输入流、输出流、字节流、字符流
输入流
以内存作为参照物,往内存中去,叫输入,或者叫——读
输出流
从内存中出来,叫输出,或者叫——写
字节流
- 按照字节的方式读取数据,一次读取一个字节byte,等同于一次读取8个二进制位。
- 这种流是万能的,什么类型的文件都可以读取,包括:文本文件,图片,声音文件,视频文件等…
字符流
- 按照字符的方式读取数据,一次读取一个字符,叫字符流。
- 这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件,只能读取存文本文件,连word文件都无法读取。
3. java中的I/O
Java中所有的流都在:java.io.*
下
4. I/O流的四大家族
java.io.InputStream
字节输入流java.io.OutputStream
字节输出流java.io.Reader
字符输入流java.io.Writer
字符输出流
四大家族的首领都是抽象类。(abstract class)
5. close()和flush()方法
所有的流都实现了:
java.io.Closeable
接口,都是可关闭的,都有==close()==方法。
流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占用)很多资源。养成好习惯,用完流一定要关闭。
所有的输出流都实现了:
java.io.Flushable
接口,都是可刷新的,都有flush()方法。
养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将通道/管道当中剩余未输出的数据,强行输出完(清空管道!)刷新的作用就是清空管道。
注意:如果没有flush()可能会导致丢失数据。
6. 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(掌握)
b. 文件流
1. 代码——输入字节流 FileInputStream
(1)创建文件字节流文件,读取单字节
FileInputStream fis = null;
fis = new FileInputStream("E:\\JAVA\\JAVAma\\lianxi1\\IOStream\\test.txt");
int readDate = fis.read();//这个方法的返回值是:读取到的宇本身。
System.out.println(readDate);//97
package com.blue.FileInput;
//创建文件字节流文件
/*以下都是采用了绝对路径的方式
文件路径:C:\Users\77\Downloads\Documents\07-JavaSE进阶每日复习与笔记 会制动把 \编程 \\,因为 java中的 \代表转义
也可以写成C:/Users/77/Downloads/Documents/07-JavaSE进阶每日复习与笔记
*/
/*
java.io.FileInputStream
1.文件字节输入流,万能的,任何类型的文件都可以采用这个流来读
2.字节的方式,完成输入操作,完成读的操作(硬盘---->内存)
*/
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamDemo1 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("E:\\JAVA\\JAVAma\\lianxi1\\IOStream\\test.txt");
// 开始读
int readDate = fis.read();//这个方法的返回值是:读取到的宇本身。
System.out.println(readDate);//97
readDate = fis.read();
System.out.println(readDate);//98
readDate = fis.read();
System.out.println(readDate);//99
readDate = fis.read();
System.out.println(readDate);//100
readDate = fis.read();
System.out.println(readDate);//101
readDate = fis.read();
System.out.println(readDate);//102
readDate = fis.read();
System.out.println(readDate);//-1
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
// 在 finally语句块当中确保流一定关闭。
if (fis == null) {//避免空指针异常
//关闭流的前提是:流不是空。流是 nuLL的时候没必要关闭。
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
(2)读取单字节–改进——循环方式
int readDate = 0;
while ((readDate = fis.read())!= -1)
package com.blue.FileInput;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
// 对第一个程序进行改进。循环方式。 FileInputStreamDemo1
public class FileInputStreamDemo2 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("E:\\JAVA\\JAVAma\\lianxi1\\IOStream\\test.txt");
/*
while (true){
int readData = fis.read();
if (readData == -1){
break;
}
System.out.println(readData);
}*/
// 改造 while 循环
int readDate = 0;
while ((readDate = fis.read())!= -1) {
System.out.println(readDate);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis == null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
(3)读取多个字节
byte[] bytes = new byte[4];
int readCount = fis.read(bytes)
package com.blue.FileInput;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
//继续改造,一次读取多个字节
/*
int read(byte[] b)
一次最多读取b.length个字节
减少硬盘和内存的交互,提高程序的执行效率
往byte[]数组当中读
*/
public class FileInputStreamDemo3 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
//使用相对路径
//IDEA当前的默认路径为,工程 Project的根就是IDEA的默认当前路径
// fis = new FileInputStream("test.txt");
fis = new FileInputStream("src/test1.txt");
//开始读,采用byte数组,一次读取多个字节,最多读取“数组.length”个字节
byte[] bytes = new byte[4];//一次最多读取四个字节
// 这个方法的返回值是:取到的宁节数量。(不是字节本身)
int readCount = fis.read(bytes);//第一次读到 4个宇
System.out.println(readCount);//4
//宇节数组全部转换成字符串
System.out.println(new String(bytes));
//不应该全部都转换,应该是读取了多少个宇节,转换多少个。
System.out.println(new String(bytes,0,readCount));
readCount = fis.read(bytes); //第二次只能读取到个字。
System.out.println(readCount);//2
System.out.println(new String(bytes));
System.out.println(new String(bytes,0,readCount));
readCount = fis.read(bytes); //1个字节都没有读取到返回-1
System.out.println(readCount);//-1
System.out.println(new String(bytes));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis == null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
(4)读取多个字节–改进
package com.blue.FileInput;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
//
public class FileInputStreamDemo4 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("src/com/test2.txt");
//准备一个byte数组
byte[] bytes = new byte[4];
/*while (true){
int readCout = fis.read(bytes);
if (readCout == -1){
break;
}
// 把 byte数组转换成字符串,读到多少个转换多少个
System.out.print(new String(bytes,0,readCout));
}*/
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();
}
}
}
}
}
(5)读取多个字节–改进–跳过几个字节不读取
package com.blue.FileInput;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
其他常用的两个方法:
int available() 返回流当中剩余的没有读到的字节数量
long skip(long n) 跳过几个字节不读
*/
public class FileInputStreamDemo5 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
//读一个字节
// int readByte = fis.read();
/*
System.out.println("剩下多少个字节没有读:" + fis.available());
byte[] bytes = new byte[fis.available()];//这种方式不太适合太大的文件,因为bytes[]数组不能太大
//这个方法有什么用
//不需要循环了,直接读一次就可以
int readCount = fis.read(bytes);
System.out.println(new String(bytes));
*/
//跳过几个字节不读取,这个方法以后可能也会用到
fis.skip(3);
System.out.println(fis.read());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis == null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2. 代码——输出字节流 FileInputStream
package com.blue.FileInput;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
文件字节输出流,负责写
从内存到硬盘
*/
public class FileOutputStreamDemo1 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
//myfile文件不存在的时候会自动新建!
//这种方式谨慎使用,这种方式会先将原文件清空,然后重新写又。
// fos = new FileOutputStream("myfile");
// 以追加的方式在文件未尾写入。不会清空原文件内容。
fos = new FileOutputStream("myfile",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();
}
}
}
}
}
3. 代码—— 完成文件的拷贝
FileInputStream fis = null;
FileOutputStream fos = null;
byte[] bytes = new byte[1024 * 1024];//1B(一次最多考贝1MB。)
while ((readCount = fis.read(bytes)) != -1){
fos.write(bytes,0,readCount);
package com.blue.Copy;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
使用 FiLeInputStream + FileOutputStream 完成文件的拷贝。
持贝的过程应该是一边读,一边写。
使用以上的字节流拷贝文件的时候,文件类型随意,万能的。什么样的文件都能考贝拷贝。
*/
public class CopyDemo01 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建一个输入流对象
fis = new FileInputStream("test.txt");
//创建一个输出流对象
fos = new FileOutputStream("src/com/blue/Copy/copy.txt");
//最核心的:一边读,一边写
byte[] bytes = new byte[1024 * 1024];//1B(一次最多考贝1MB。)
int readCount = 0;
while ((readCount = fis.read(bytes)) != -1){
fos.write(bytes,0,readCount);
}
//刷新,输出流最后要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//分开 try,不要一起 try
//一起 try的时候,其中一个出现异常,可能会影啊到另一个流的关闭。
if (fis == null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos == null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4. 代码——字符输入流FileReader
(1)while循环读
char[] chars = new char[4];//一次读取4个字符
while ((readCount = reader.read(chars)) != -1){
package com.blue.FileReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/*
FileReader:
文件字符输入流,只能读取普通文本。
读取文本内容时,比较方便,快捷。
*/
public class FileReadDemo01 {
public static void main(String[] args) {
FileReader reader = null;
try {
//创建文件字符输入流
reader = new FileReader("src/com/blue/FileReader/yeah.txt");
//开始读
char[] chars = new char[4];//一次读取4个字符
int readCount = 0;
while ((readCount = reader.read(chars)) != -1){
System.out.print(new String(chars,0,readCount));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader == null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
输出为========================
blue
空山新雨后
天气晚来秋
Process finished with exit code 0
(2)for循环读
char[] chars = new char[4];//一次读取4个字符
reader.read(chars); //按照字符的方式取:第一次e,第二次,第三次风
for (char c : chars){
System.out.println(c);
package com.blue.FileReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/*
FileReader:
文件字符输入流,只能读取普通文本。
读取文本内容时,比较方便,快捷。
*/
public class FileReadDemo02 {
public static void main(String[] args) {
FileReader reader = null;
try {
//创建文件字符输入流
reader = new FileReader("src/com/blue/FileReader/yeah.txt");
//准备一个 char数组
char[] chars = new char[4];//一次读取4个字符
//往 char数组中读
reader.read(chars); //按照字符的方式取:第一次e,第二次,第三次风
for (char c : chars){
System.out.println(c);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader == null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
输出为=============================
b
l
u
e
Process finished with exit code 0
5. 代码——字符输出流FileWriter
package com.blue.FileWriter;
import java.io.FileWriter;
import java.io.IOException;
/*
Filewriter
文件字符输出流。写。
只能输出普通文本
*/
public class FileWriterDemo01 {
public static void main(String[] args) {
FileWriter out = null;
try {
//创建文件宇符输出流对象
// out = new FileWriter("src/com/blue/FileWriter/file.txt");
out = new FileWriter("src/com/blue/FileWriter/file.txt",true);
//开始写
char[] chars = {'我','是','中','国','人'};
out.write(chars);
out.write(chars,2,3);
out.write("我是一名学生");
out.write("\n");
//刷新
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (out == null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
文件内容
c. 缓冲流
1. 代码——带有缓冲区的字符输入流BufferedReader
package com.blue.BufferedReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/*
BufferedReader:
带有缓冲区的字符输入流。
使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组。自带缓冲。
*/
public class BufferedReaderDemo01 {
public static void main(String[] args) {
FileReader reader = null;
BufferedReader br = null;
try {
reader = new FileReader("CopyDemo02.java");
// 当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流。
// 外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流。
// 像当前这个程序来说:FiLeReader就是一个节点流。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.println(s);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
//关闭流
//对于包装流来说,只需要关闭最外层流就行,里面的节点流会自动关闭。(可以看源代码。
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
package com.blue.BufferedReader;
import java.io.*;
public class BufferedReaderDemo02 {
public static void main(String[] args) {
FileInputStream in = null;
BufferedReader br = null;
InputStreamReader reader = null;
try {
/*in = new FileInputStream("CopyDemo02.java"); //字节流
// 通过转换流转换(InputStreamReader将字节流转换成字符流。
// in是节点流。reader是包装流。
reader = new InputStreamReader(in); // 通过转换流转换
// 这个构造方法只能传一个字符流。不能传字节流。
// reader是节点流。br是包装流。
br = new BufferedReader(reader);// 这个构造方法只能传一个字符流。不能传字节流。*/
// 合并
br = new BufferedReader(new InputStreamReader(new FileInputStream("CopyDemo02.java")));
String line = null;
while ((line = br.readLine())!= null){
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2. 代码——带有缓冲区的字符输出流BufferedWriter
package com.blue.BufferedWriter;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
/*
BufferWriter:带有缓存的字符输出流
*/
public class BufferedWriterDemo01 {
public static void main(String[] args) throws Exception{
//带有缓冲区的字符输出流
// BufferedWriter out = new BufferedWriter(new FileWriter("copy"));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("copy",true)));
// 开始写
out.write("hello world!");
out.write("\n");
out.write("hello world!");
// 刷新
out.flush();
// 关闭最外层
out.close();
}
}