1,IO流的概述
-
IO流,什么是IO?
I:Input O:Output 通过IO可以完成硬盘文件的读和写。
-
IO流的分类(多种分类方式:)?
- 1,按照流的方向进行分类,以内存作为参照物:
- 往内存中去:叫做输入(Input),或者叫做读(Read)。
- 从内存中出来:叫做输出(Output),或者叫做写(Write)。
- 2,按照读取数据方式不同进行分类:
有的流按照字节的方式读取数据,一次读取1一个字节byte,等同一次读取8个二进制位。 这种流是万能的,什么类型的文件都可以读取。包括:文本文件、图片、声音文件、视频文件等...
有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而
存在的,这种流不能读取:图片、声音、视频等...;只能读取纯文本文件,连word文件都无法读取。-
综上所述流的分类:
输入流、输出流; 字节流、字符流
- 1,按照流的方向进行分类,以内存作为参照物:
-
IO流的四大家族:(四大首领)
java.io.InputStream 字节输入流 java.io.OutputStream 字节输出流 java.io.Reader 字符输入流 java.io.Writer 字符输出流
- 四大首领都是抽象类。(abstract class)
-
所有的流都实现了:
java.io.Closeable接口,都是可关闭的,都有close()方法。 流毕竟是一个管道,这个是内存和硬盘支架的通道,用完之后一定要关闭, 不然会耗费(占用)很多资源。养成好习惯:用完流一定要关闭。
-
所有的输出流都实现了:
java.io.Flushable接口,都是可刷新的,都有flush()方法; 输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将通道/管道当中剩余 未输出的数据强行输出完(清空管道)!刷新的作用就是清空管道。
在java中只有类名以"Stream"结尾的都是字节流,以"Reader/Writer"结尾的都是字符流。
-
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
2,文件字节输入流(FileInputStream)
-
java.io.FileInputStream
- 文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。
- 字节的方式,完成输入的操作,完成读的操作(硬盘---> 内存)
-
java.io.FileInputStream常用方法
int read(); // 读取字节数据 int available() // 返回值当中剩余的没有读到的字节数量 long skip(long n) // 跳过几个字节不读
代码示例:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest01 {
public static void main(String[] args) {
// 创建文件字节输入流对象
FileInputStream file = null;
FileInputStream file2 = null;
FileInputStream file3 = null;
try {
// 绝对路径: /Users/a1/Desktop/Java/Simon_JavaSE/JavaTest/src/temp
// 相对路径: src/temp
file = new FileInputStream("src/temp");
// 读取流数据
// 一个字节一个字节的读取
int data = 0;
while (data != -1){ // 读取到文件的末尾了,在读的时候读取不到任何数据,返回-1
data = file.read(); // 这个方法读取的是"字节"本身
System.out.println(data); //
}
System.out.println("-----------------------------------------------------------");
file2 = new FileInputStream("src/temp");
// 采用byte数组,一次读取多个字节;最多读取"数组.length"个字节
byte[] bytes = new byte[4]; //定义一个长度为4的byte数组,一次读取4个字节
int byteData = 0;
while ((byteData = file2.read(bytes)) != -1){
// 这个方法的返回值是:读取到字节的数量(不是字节本身)
System.out.println(byteData);// 4 2
// 将字符数组全部装换成字符串
// System.out.println(new String(bytes));// abcd efcd
// 不应该全部转换应该读取多少个字符,转换多少个
System.out.println(new String(bytes,0,byteData)); //abcd ef
}
System.out.println("-----------------------------------------------------------");
file3 = new FileInputStream("src/temp");
// 先读1个字节
int readByte = file3.read();
System.out.println(readByte);
System.out.println("还剩下几个字节未读:" + file3.available());
// 跳过2个字节不读
file3.skip(2);
System.out.println("还剩下几个字节未读:" + file3.available());
// 读取字节数据
System.out.println(file3.read());
}catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 在finally语句块中确保流一定被关闭
if (file != null){ // 关闭流的前提是:流不为空;流为空没必要关闭。
try {
file.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
3,文件字节输出流(FileOutputStream)
- java.io.FileInputStream
- 文件字节输出流,负责写;从内存到硬盘
代码示例
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest01 {
public static void main(String[] args) {
FileOutputStream fos = null;
FileOutputStream fos2 = null;
try {
// myFile文件不存在的时候会自动新建!
// 这种方式谨慎使用,会将原文件内容情况再重新写入
// fos = new FileOutputStream("myFile");
// 以追加的方式在文件末尾写入,不会清空原文件内容。
fos = new FileOutputStream("myFile",true);
// 开始写入
byte[] bytes = {97,98,99,100};
//将byte数组全部写出
fos.write(bytes);// abcd
fos.write(bytes,0,2); //将byte数组的一部分写出,再写ab
// 字符串
String s = "我是一个中国人,我很骄傲!!!";
byte[] bs = s.getBytes();
// 将字符串转换成byte数组。
// 写
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();
}
}
}
}
}
4,使用FileInputStream和FileOutputStream完成文件的拷贝
- 拷贝的过程是一边读,一边写
- 使用以上的字节流拷贝文件的时候,文件类型随意,万能的;什么样的文件都能拷贝。
demo示例
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyTest01 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 创建一个输入流对象 拷贝对象地址
fis = new FileInputStream("/Users/a1/Desktop/1620637732904119.mp4");
// 创建一个输出流对象 拷贝到哪里(地址)
fos = new FileOutputStream("/Users/a1/Desktop/Java/Simon_Java/src/1620637732904119-copy.mp4");
byte[] bytes = new byte[1024 * 1024]; // 1M(一次读取1M)
int readCount = 0;
while ((readCount = fis.read(bytes)) != -1){
fos.write(bytes,0,bytes.length);
}
// 刷新输出流
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 分开try,不要一起try;
// 一起的时候,其中一个出现异常,可能会影响另一个流的关闭。
if (fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
5,FileReader和FileWriter
- FileReader:
- 文件字符输入流,只能读取普通文本。
- 读取文本内容时,比较方便,快捷。
- FileWriter:
- 文件字符输出流,写。
- 只能输出普通文本
代码示例
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileReaderWriterTest {
public static void main(String[] args) {
FileReader reader = null;
FileWriter writer = null;
FileReader readerCopy = null;
FileWriter writerCopy = null;
try {
// ---------------------------FileReader------------------------------------------------
// 创建文件字符输入流
reader = new FileReader("src/temp");
// 开始读
char[] chars = new char[4]; // 一次读取四个字符
int readCount = 0;
while ((readCount = reader.read(chars)) != -1){
System.out.print(new String(chars,0, readCount));
}
// ---------------------------FileWriter------------------------------------------------
// 创建文件字符输出流
// 这种方式会将原文件内容情况再重新写入
// writer = new FileWriter("src/temp3");
//不清空原文件写法
writer = new FileWriter("src/temp3",true);
// 开始写入
char[] chars1 = {'我','是','中','国','人'};
writer.write(chars1);
writer.write(chars1,2,3);
// 字符串写入
writer.write("我在学习java");
// 写入换行符
writer.write("\n");
writer.write("我换行了");
// 写入之后刷新
writer.flush();
// ------------------FileReader---And---FileWriter---------------------------------------
// 使用FileReader和FileWriter进行拷贝,只能拷贝普通文本文件
// 读
readerCopy = new FileReader("src/temp3");
// 写
writerCopy = new FileWriter("src/com/javase/ioflow/temp3-copy");
// 一边读一边写
char[] chars2 = new char[1024 * 512]; // 1MB
int readerCount = 0;
while ((readerCount = readerCopy.read(chars2)) != -1){
writerCopy.write(chars2,0,readerCount);
}
// 刷新
writerCopy.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
6,BufferedReader和InputStreamReader
- BufferedReader:
- 带有缓冲区的字符输入流。
- 使用这个流的时候不需要自定义char数组、byte数组;自带缓冲。
- InputStreamReader转换流:
- 把字节流转换成字符流
代码示例
import java.io.*;
public class BufferedReaderTest {
public static void main(String[] args) {
FileReader reader = null;
BufferedReader br = null;
FileInputStream fin = null;
InputStreamReader red = null;
try {
// 当一个流的构造方法中需要另一个流的时候,这个被传进来的流叫做:节点流。
// 外部负责包装的这个流,叫做:包装流 或 处理流
// --------------------------------------------------
// 只能传字符流,不能传字节流。
// reader = new FileReader("src/temp3");
// BufferedReader只能传字符流,不能传字节流
// red是节点流,br是包装流
// br = new BufferedReader(reader);
// ---------InputStreamReader转换流----------------------------------------
// 字节流
fin = new FileInputStream("src/temp3");
// 把字节流转换成字符流
red = new InputStreamReader(fin);
br = new BufferedReader(red);
// 读
String sLine = null;
// readLine方法读取一个文本行,但不带换行符。
while ((sLine = br.readLine()) != null){
System.out.println(sLine);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
// 对于包装流来说,只要关闭最外层流就行,里面的节点流会自动关闭。
if (br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
7,BufferedWriter和OutputStreamWriter
- BufferedWriter:
- 带有缓冲的字符输出流
- OutputStreamWriter转换流:
- 把字节流转换成字符流
代码示例
import java.io.*;
public class BufferedWriterTest {
public static void main(String[] args) {
BufferedWriter bw = null;
try {
// 带有缓冲区的字符输出流
// bw = new BufferedWriter(new FileWriter("temp"));
// 使用OutputStreamWriter转换流的写法
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("temp",true)));
// 写
bw.write("hello java");
bw.write("hello word");
bw.write("\n");
bw.write("hello kitty");
//刷新
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bw != null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
8,DataOutputStream和DataInputStream
-
DataOutputStream:数据专属输出流:
- 这个流可以将数据连同数据类型一并写入文件
- 注意:这个文件不是普通文本文档。(这个文件使用记事本打不开)
-
DataInputStream:数据专属输入流:
- DataOutputStream写的文件,只能使用DataInputStream去读,并且读的时候需要提前知道写入的顺序。
- 读的顺序需要和写的顺序一致,才能正常取出数据
代码示例
import java.io.*;
public class DataOutputStreamTest {
public static void main(String[] args) {
DataOutputStream dos = null;
DataInputStream dis = null;
try {
// 创建数据专属的字符输出流
dos = new DataOutputStream(new FileOutputStream("src/com/javase/ioflow/data"));
// 写入数据
byte b = 100;
short s = 200;
int i = 300;
long l = 400L;
float f = 3.0f;
double d = 3.14;
boolean sex = true;
char c = 'a';
// 写 把数据以及数据类型一并写入到文档当中
dos.writeByte(b);
dos.writeShort(s);
dos.writeInt(i);
dos.writeLong(l);
dos.writeFloat(f);
dos.writeDouble(d);
dos.writeBoolean(sex);
dos.writeChar(c);
// 刷新
dos.flush();
// -------------------------------------------------------------------------------------------
// 创建数据专属的字符输入流
dis = new DataInputStream(new FileInputStream("src/com/javase/ioflow/data"));
// 读取数据
byte bd = dis.readByte();
short sd = dis.readShort();
int id = dis.readInt();
long ld = dis.readLong();
float fd = dis.readFloat();
double dd = dis.readDouble();
boolean sexd = dis.readBoolean();
char cd = dis.readChar();
// 输出
System.out.println(bd);
System.out.println(sd);
System.out.println(id + 1000); //1300
System.out.println(ld);
System.out.println(fd);
System.out.println(dd);
System.out.println(sexd);
System.out.println(cd);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dos != null){
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dis != null){
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
9,标准的字节输出流PrintStream
- PrintStream标准的字节输出流:
- 默认输出到控制台。
- 标准输出流不需要手动close()关闭。
代码示例
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
public class PrintStreamTest {
public static void main(String[] args) throws FileNotFoundException {
// 联合起来写
System.out.println("hello PrintStream");
// 分开写
// 创建标准的字节输出流对象
PrintStream ps = System.out;
// 输出到控制台
ps.println("hello Word");
ps.println(123);
ps.println(true);
// 标准输出流不需要手动close()关闭
//---------------------------------------------------------------------------------
// 改变标准输出流的输出方向
// 标准输出流不再指向控制台,指向"Log"文件
PrintStream printStream = new PrintStream(new FileOutputStream("src/com/javase/ioflow/Log"));
// 修改输出方向,将输出方向修改到"Log"文件
System.setOut(printStream);
// 再输出
System.out.println("hello Word");
System.out.println("hello Kitty");
System.out.println("hello Java");
//---------------------------------------------------------------------------------
// 调用log工具类
LogFileUtil.log("这里打印了一个log日志");
LogFileUtil.log("这里打印了一个登录log日志");
}
}
// 定义一个log工具类
class LogFileUtil{
// 记录日志的方法
public static void log(String msg){
// 标准输出流不再指向控制台,指向一个日志文件
PrintStream printStream = null;
try {
printStream = new PrintStream(new FileOutputStream("src/com/javase/ioflow/LogFile",true));
// 改变输出方向
System.setOut(printStream);
// 获取当前时间
Date nowTime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strTime = sdf.format(nowTime);
System.out.println(strTime + ":" + msg);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 修改输出方向,将输出方向修改到"Log"文件
System.setOut(printStream);
}
}