1、流的本质
2、常见的16个流:
java语言中的流分为四大家族:InputStream、OutputStream、Reader、Writer
2.1、文件相关
- FileInputStream
- FileOutputStream
- FileReader
- FileWriter
2.2、带缓冲区的 - BufferedInputStream
- BufferedOutputStream
- BufferedReader
- BufferedWriter
2.3、数据流 - DataInputStream
- DataOutputStream
2.4、对象流 - ObjectInputStream
- ObjectOutputStream
2.5、转换流(字节流转换为字符流) - InputStreamReader
- OutputStreamWriter
2.6、标准输出流 - PrintWriter
- PrintStream// 标准的输出流(默认输出到控制台)
3、常用16个流的结构关系
- InputStream、OutputStream两家子:
- Reader、Writer两家子
4、FileInputStream常用方法及原理
应用实例及注解:
/**
* java.io.InputStram;
* java.io.FileInputStream;文件字节输入流
* 按照字节方式读取文件
*/
public class FileInputStreamTest01 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
// 1、要读取某文件,先与这个文件创建一个“输入流”
// 绝对路径,java中“\”有转义作用使用“\\”代替,如果使用相对路径,是相对于java执行文件来说的,在windows中还可以使用“/”来查找路径
String filePath01 = "E:\\learing\\temporary\\test01.txt";
String filePath02 = "E:/learing/temporary/test01.txt";
fis = new FileInputStream(filePath02);// 在windows环境下filePath01和filePath02均可执行
// 2、读操作
// 2.1 read()方法每次读取一个字节,结束返回-1。该方法将会频繁的读取磁盘文件,每字节读取一次,效率低。
// 2.1.1 测试文件内容,“aB我c”,中文占两个字节
int r1 = fis.read();
int r2 = fis.read();
int r3 = fis.read();
int r4 = fis.read();
int r5 = fis.read();
int r6 = fis.read();
System.out.println(r1);// a-->97
System.out.println(r2);// B-->96
System.out.println(r3);// “我”一半-->206
System.out.println(r4);// “我”另一半-->210
System.out.println(r5);// c-->99
System.out.println(r6);// 结束,文件的末尾-->-1
// 2.1.2 循环获取方式
System.out.println("==============================================");
fis = new FileInputStream(filePath02);
int temp = 0;
while ((temp = fis.read()) != -1) {
System.out.println(temp);
}
System.out.println("==============================================");
// 2.2 read(byte[] b)读取前再内存中创建byte[],每次读取多个字节到byte[]中,效率较高,该方法返回int值代表的是,本次读取了多少个字节,末尾返回-1。
fis = new FileInputStream(filePath02);
byte[] bts = new byte[3];// 设定初值,每次最多读3个字节
// 2.2.1 测试文件内容,“aBcdefg”,中文占两个字节,中文此处将会乱码
int i1 = fis.read(bts);
System.out.println(new String(bts));// abc
int i2 = fis.read(bts);
System.out.println(new String(bts));// def
int i3 = fis.read(bts);
System.out.println(new String(bts));// gef
System.out.println(new String(bts, 0, i3));// g(如果直接输出将输出“gef”因为最后一组只覆盖了一个字节)
int i4 = fis.read(bts);
System.out.println(i1);// 3
System.out.println(i2);// 3
System.out.println(i3);// 1
System.out.println(i4);// -1
System.out.println("==============================================");
// 2.2.2 循环获取方式1,测试内容"abcdefg"
byte[] bts1 = new byte[1024];// 设定初值,每次最多读1KB
fis = new FileInputStream(filePath02);
while (true) {
int temp1 = fis.read(bts1);
if (temp1 == -1) break;
// 将bts1中有效部分转换为字符串
System.out.print(new String(bts1, 0, temp1));// abcdefg
}
System.out.println("==============================================");
// 循环方式2,,测试内容"abcdefg"
int temp2 = 0;
fis = new FileInputStream(filePath02);
while ((temp2 = fis.read(bts1)) != -1) {
System.out.print(new String(bts1, 0, temp2));// abcdefg
}
System.out.println("==============================================");
// 2.2 int available()返回流中剩余的字节数,测试内容"abcdefg"
fis = new FileInputStream(filePath02);
System.out.println(fis.available());// 7
// 2.2 long skip(long)跳过n个字节,从第n个字节后往后读取,测试内容"abcdefg"
System.out.println(fis.skip(1));
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 为了保证流一定被关闭,finally块中执行关闭操作
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
5、FileOutputStream常用方法
/**
* java.io.OutputStream;
* java.io.FileOutputStream 文件字节输出流
* 将计算机内存的数据写入硬盘中
*/
public class FileOutputStreamTest01 {
public static void main(String[] args) {
// 绝对地址位置上生成指定类型的文件
String filePath02 = "E:/learing/temporary/test02.txt";
FileOutputStream fos = null;
try {
// 不存在则自动创建
// fos = new FileOutputStream(filePath02);// 重复调用write()方法,覆盖原文件
fos = new FileOutputStream(filePath02, true);// 重复调用write()方法,追加写入
String msg = "Hello world!";
byte[] byteMsg = msg.getBytes();
fos.write(byteMsg);// 将数组中的数据全部写入文件
// fos.write(b, off, len);// 将数组中的数据部分写入文件
// 为了保证数据完全写入硬盘,需要刷新,强制写入
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
6、FileReader简单例子
/**
* java.lang.Object
* java.io.Reader
* java.io.InputStreamReader 转换流(字节输入流-->字符输入流)
* java.io.FileReader 文件字符输入流,用于纯文本文件
*/
public class FileReaderTest01 {
public static void main(String[] args) {
String filePath = "E:\\learing\\temporary\\test03.txt";
FileReader fr = null;
try {
fr = new FileReader(filePath);// 创建文件字符输入流
char[] cbuf = new char[512];// 1KB
int temp = 0;
while ((temp = fr.read(cbuf)) != -1) {
// 将char数组有效部分输出
System.out.println(new String(cbuf, 0, temp));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭字符输入流
try {
if(fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
7、FileWriter简单例子
/**
*
* java.lang.Object
* java.io.Writer
* java.io.OutputStreamWriter 转换流(字节输出流-->字符输出流)
* java.io.FileWriter 文件字符输出流,用于纯文本文件
*
*/
public class FileWriterTest01 {
public static void main(String[] args) {
FileWriter fw = null;
String filePath = "E:\\learing\\temporary\\test04.txt";
try {
// fw = new FileWriter(filePath);// 覆盖
fw = new FileWriter(filePath, true);// 追加
fw.write("让我们荡起双桨!!");// 直接写String
char[] chars = {'小','船','儿','推','开','波','浪','。','/','n'};
fw.write(chars, 0, 8);// 写入部分char数组
fw.write(System.lineSeparator());// 换行
fw.flush();// 刷新,强制写入
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
8、BufferedReader简单例子
/**
* 带缓存区的
* 字节
* BufferedInputStream
* BufferedOutputStream
* 字符
* BufferedReader 带缓存区的字符输入流。重点读一行文本readLine()方法,返回字符串。
* BufferedWriter
*
*/
public class BufferedReaderTest01 {
public static void main(String[] args) {
BufferedReader br = null;
try {
// 1.BufferedReader(Reader in)新建BufferedReader时需要传入一个Reader,FileReader可以向上转型为Reader
// br = new BufferedReader(new FileReader("E:\\learing\\temporary\\file.java"));
// 2.如果手上有的是一个文件字节流FileInputStream,可以先把FileInputStream用转换流InputStreanReader转换为文件字符流,InputStreanReader向上转型为Reader
br = new BufferedReader(new InputStreamReader(new FileInputStream("E:\\learing\\temporary\\file.java")));
String temp = null;// 用于接收readLine()返回值
while ((temp = br.readLine()) != null) {
System.out.println(temp);// 输出一行,但是行尾不带换行符
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();// 关闭最外层的流即可(主使者模式)
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
9、BufferedWriter简例
public class BufferedWriterTest01 {
public static void main(String[] args) {
BufferedWriter bw = null;
try {
// BufferedWriter构造方法需要传入一个Reader
// 1.直接传入一个FileWriter
// bw = new BufferedWriter(new FileWriter("E:\\learing\\temporary\\test05.txt"));
// 使用OutputStreamWriter将FileOutoutStream转换为FileWriter再传入FileWriter构造方法
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:\\learing\\temporary\\test05.txt",true)));
bw.write("重庆麻辣烫!");// 写入
bw.newLine();// 写入一个换行符
bw.write("谁吃谁知道!");// 写入
bw.newLine();// 写入一个换行符
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
10、PrintStream标准的输出流
简例:
/**
* java.io.PrintStream; 标准的输出流,默认打印到控制台,以字节方式
* java.io.prinWriter; 以字符方式
*
*/
public class PrintStreamTest01 {
public static void main(String[] args) {
// 默认是输出到控制台
System.out.println("展示在控制台1!");
// 以上代码也可以这样写
PrintStream ps = System.out;
ps.println("展示在控制台2!");
try {
// 可以改变流的输出方向,如下
System.setOut(new PrintStream(new FileOutputStream("E:\\learing\\temporary\\log.txt")));
// 后面的输出将输出到log文件中,可以使用该方法记录日志
System.out.print("展示再log文件中1!");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
11、ObjectOutputStream和ObjectInputStream:序列化/反序列化流
ObjectOutputStream序列化简例:
/**
* java.io.Serializable;该接口是一个可序列化的,接口没有任何方法,是一个标识接口。像这样的接口还有java.lang.Cloneable可克隆的
*
* 标识接口,起到标识的作用
* JVM如果看到该对象实现了某个标识接口,会对他特殊待遇:
* 会给该类添加一个属性,static final long serialVersionUID = 321315465488898
* 当类改变重新编译后,序列号也会改变,将导致反序列化失败。
* 为了保证该类升级后序列号和旧版一致,可以自己写一个序列化版本号。
*/
public class User implements Serializable{
// 如果不想让属性参加序列化,需要使用transient关键字修饰
// transient String name;
String name;
User (String name) {
this.name = name;
}
public String toString() {
return "User[name="+name+"]";
}
}
/**
* java.io.ObjectOutputStream;序列化JAVA对象到硬盘(Serial)
* java.io.ObjectInputStream;将硬盘中的数据“反序列化”到JVM内存(DeSerial)
*
* Compile 编译(java-->class)
* DeCompile 反编译(class-->java)
*/
public class ObjectOutputStreamTest01 {
public static void main(String[] args) {
// 创建java对象
User u1 = new User("刘亦菲");
ObjectOutputStream oos = null;
try {
// 创建输出流(序列化流)(JVM中的java对象状态保存到硬盘中)
oos = new ObjectOutputStream(new FileOutputStream("E:\\learing\\temporary\\test07.txt"));
// 写
oos.writeObject(u1);
// 强制写出
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
对应ObjectInputStream反序列化简例:
public class ObjectInputStreamTest01 {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
// 创建反序列化流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\learing\\temporary\\test07.txt"));
// 反序列化
Object obj = ois.readObject();
System.out.println(obj);// 输出:User[name=刘亦菲]
ois.close();
}
}
12、File:抽象表示的文件和目录的路径名
常用方法简例:
/**
* java.io.File;
* 1、File类和流无关,不能通过该类完成文件的读和写
* 2、File是文件和目录路径名的抽象表示形式
* File代表的是硬盘上的Directory和file
*/
public class FileTest01 {
public static void main(String[] args) throws IOException {
// 可以是相对路径,也可以使用绝对路径
File f1 = new File("E:\\learing\\draft");
File f2 = new File("E:\\learing\\draft\\Test3.java");
// 判断是否存在exists()
System.out.println(f1.exists());
System.out.println(f2.exists());
// 创建目录mkdir()
File f3 = new File("E:\\learing\\draft\\util2");
if (!f3.exists()) {
f3.mkdir();
}
// 创建文件createNewFile()
File f4 = new File("E:\\learing\\draft\\fileTest001.txt");
if (!f4.exists()) {
f4.createNewFile();
}
// 创建多重目录mkdirs()
File f5 = new File("E:/learing/draft/a/b/c/d");
if (!f5.exists()) {
f5.mkdirs();
}
// 列出子文件
File f6 = new File("E:\\learing\\draft");
File[] fs = f6.listFiles();
for (File f : fs) {
System.out.println(f.getAbsolutePath());
// 输出以“**”结尾的
if (f.getAbsolutePath().endsWith(".java")) {
System.out.println(">>>>>>>>>>>>>>>>>>>java>>>>>>>>>>>>>>" + f.getAbsolutePath());
}
}
// 使用递归,列出所有子文件及目录
getFiles(f6);
// 常用的其它方法:
// boolean delete() 删除
// void deleteOnExit() 存在删除
// File getAbsoluteFile() 获取绝对路径
// String getName() 获取文件名
// String getParent() 获取父路径
// boolean isDirectory() 是否路径
// boolean isFile() 是否文件
// long lastModified() 最后修改时间
// long length() 获取文件大小(字节数)
}
public static void getFiles(File file) {
if (file.isFile()) {// 是文件则不往下查找
return;
}
File[] fs = file.listFiles();// 是目录:输出当前目录,并查询子目录中的文件
for (File f : fs) {
System.out.println("getFiles>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + f);
getFiles(f);// 递归查找目录
}
}
}