Java加强--2.IO流
Java加强--2.IO流
- IO概述
- IO的分类
- 字节流
- 字符流
- 缓冲流
- 转换流
- 序列化
- 打印流
- 关系图
- 源码
- 拓展
- Java加强--2.IO流
- IO概述
- IO的分类
- 字节流
- 字符流
- 缓冲流
- 转换流
- 序列化
- 打印流
- 关系图
- 源码
- 拓展
- Java加强--2.IO流
IO概述
我们把这种数据的传输,可以看做是⼀种数据的流动,按照流动的⽅向,以内存为基准,分为 输⼊
input 和 输出output ,即流向内存是输⼊流,流出内存的输出流
Java中I/O操作主要是指使⽤ java.io 包下的内容,进⾏输⼊、输出操作。输⼊也叫做读取数据,输
出也叫做作写出数据
IO的分类
根据数据的流向分为:输⼊流和输出流。
输⼊流 :把数据从 其他设备 上读取到 内存 中的流。
输出流 :把数据从 内存 中写出到 其他设备 上的流。
根据数据的类型分为:字节流和字符流。
字节流 :以字节为单位,读写数据的流。
字符流 :以字符为单位,读写数据的流。
父类:
输⼊流 | 输出流 | |
---|---|---|
字节流 | 字节输⼊流 InputStream | 字节输出流OutputStream |
字符流 | 字符输⼊流Reader | 字符输出流Writer |
字节流
数据本质
⼀切⽂件数据(⽂本、图⽚、视频等)在存储时,都是以⼆进制数字的形式保存,都⼀个⼀个的字节,
那么传输时⼀样如此。所以,字节流可以传输任意⽂件数据。在操作流的时候,我们要时刻明确,⽆
论使⽤什么样的流对象,底层传输的始终为⼆进制数据。
任意类型的数据在计算机中都是以⼆进制形式存在。数据的本质就是⼆进制
字节输出流【OutputStream】
java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到⽬的
地。它定义了字节输出流的基本共性功能⽅法
public void close() :关闭此输出流并释放与此流相关联的任何系统资源
public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出
public void write(byte[] b) :将 b.length字节从指定的字节数组写⼊此输出流
public void write(byte[] b, int off, int len) :从指定的字节数组写⼊ len字节,从偏移量 offff开始输出到此输出流
public abstract void write(int b) :将指定的字节输出流
备注: close⽅法,当完成流的操作时,必须调⽤此⽅法,释放系统资源
FileOutputStream类
java.io.FileOutputStream 类是⽂件输出流,⽤于将数据写出到⽂件
public FileOutputStream(File file) :创建⽂件输出流以写⼊由指定的 File对象表示的⽂件
public FileOutputStream(String name) : 创建⽂件输出流以指定的名称写⼊⽂件
构造函数
public class OutputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
static void test1() throws FileNotFoundException {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//使用文件名创建流对象
OutputStream os1 = new FileOutputStream("C:/Users/lighter/Desktop/b.txt");
}
}
write(int b)
写出字节: write(int b) ⽅法,每次可以写出⼀个字节数据
public class OutputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//第一个字节,ASCII十进制对应字符
os.write(97);
os.write(98);
os.write(99);
//关闭资源
os.close();
}
}
//a.txt文件中
abc
**备注:**流操作完毕后,必须释放系统资源,调⽤close⽅法,千万记得
写出字节数组: write(byte[] b) ,每次可以写出数组中的数据
public class OutputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串转换为字节数组
byte[] bytes = "好好学习,天天向上".getBytes();
//输入字节数组
os.write(bytes);
//关闭资源
os.close();
}
}
//文件内容,之前的被覆盖掉了
好好学习,天天向上
write(byte[] b, int off, int len)
写出指定⻓度字节数组: write(byte[] b, int off, int len) ,每次写出从offff索引开始,len个字节
public class OutputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串转换为字节数组
byte[] bytes = "好好学习,天天向上".getBytes();
//输入字节数组,从索引2开始,3个字节
os.write(bytes,6,3);
//关闭资源
os.close();
}
}
//文件内容,之前的被覆盖掉了
//三个字节转一个汉字,如果是中文,这里要注意算3的倍数
学
数据追加续写
public FileOutputStream(File file, boolean append) : 创建⽂件输出流以写⼊由指定的File对象表示的⽂件。
public FileOutputStream(String name, boolean append) : 创建⽂件输出流以指定的名称写⼊⽂件。
这两个构造⽅法,参数中都需要传⼊⼀个boolean类型的值, true 表示追加数据, false 表示清空原有数据。这样创建的输出流对象,就可以指定是否追加续写了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串转换为字节数组
byte[] bytes = "好好学习,天天向上".getBytes();
//输入字节数组
os.write(bytes);
//关闭资源
os.close();
}
}
//文件内容
学好好学习,天天向上
换行
Windows系统⾥,换⾏符号是 \r\n 。把以指定是否追加续写了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串转换为字节数组
byte[] bytes = "已经换行".getBytes();
//换行
os.write("\r\n".getBytes());
//输入字节数组
os.write(bytes);
//关闭资源
os.close();
}
}
//文件内容,包含之前(已换行)
学好好学习,天天向上
已经换行
回⻋符 \r 和换⾏符 \n :
回⻋符:回到⼀⾏的开头(return)。
换⾏符:另起⼀⾏(newline)。
系统中的换⾏:
Windows系统⾥,每⾏结尾是 回⻋+换⾏ ,即 \r\n ;
Unix系统⾥,每⾏结尾只有 换⾏ ,即 \n ;
Mac系统⾥,每⾏结尾是 回⻋ ,即 \r 。从 Mac OS X开始与Linux统⼀。
字节输⼊流【InputStream】
java.io.InputStream 抽象类是表示字节输⼊流的所有类的超类,可以读取字节信息到内存中。它定义了字节输⼊流的基本共性功能⽅法。
public void close() :关闭此输⼊流并释放与此流相关联的任何系统资源。
public abstract int read() : 从输⼊流读取数据的下⼀个字节。
public int read(byte[] b) : 从输⼊流中读取⼀些字节数,并将它们存储到字节数组 b中 。
备注:close⽅法,当完成流的操作时,必须调⽤此⽅法,释放系统资源
FileInputStream类
java.io.FileInputStream 类是⽂件输⼊流,从⽂件中读取字节
构造函数
FileInputStream(File file) : 通过打开与实际⽂件的连接来创建⼀个 FileInputStream ,该⽂件由⽂件系统中的 File对象 fifile命名。
FileInputStream(String name) : 通过打开与实际⽂件的连接来创建⼀个 FileInputStream ,该⽂件由⽂件系统中的路径名 name命名。
当你创建⼀个流对象时,必须传⼊⼀个⽂件路径。该路径下,如果没有该⽂件,会抛出FileNotFoundException
public class InputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos1 = new FileInputStream(file);
// 使⽤⽂件名称创建流对象
FileInputStream fos2 = new FileInputStream("C:/Users/lighter/Desktop/a.txt");
}
}
read()
读取字节: read (),每次可以读取⼀个字节的数据,提升为int类型,读取到⽂件末尾,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
int b;
//读取每一个字节数据,= -1 读完
while ((b = fis.read()) != -1){
System.out.println(b +">>"+(char) b);
}
//释放资源
fis.close();
}
}
//文件中内容:abcdefg
//输出:
97>>a
98>>b
99>>c
100>>d
101>>e
102>>f
103>>g
read(byte[] b)
使⽤字节数组读取: read(byte[] b) ,每次读取b的⻓度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字节个数
int len;
//定义读取到的字节数组,作为装字节数据的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字节数组转化成字符串打印
System.out.println(len +">>"+new String(b));
}
fis.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>学
3>>习
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>klj
读取有效字节
错误数据 j ,是由于最后⼀次读取时,只读取2个字节kl ,数组中,上次读取的数据没有被完全替换,所以要通过 len ,获取有效的字节,
public class InputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字节个数
int len;
//定义读取到的字节数组,作为装字节数据的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字节数组转化成字符串打印,打印有效的字符串
System.out.println(len +">>"+new String(b,0,len));
}
fis.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>学
3>>习
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>kl
字符流
当使⽤字节流读取⽂本⽂件时,可能会有⼀个⼩问题。就是遇到中⽂字符时,可能不会显示完整的字符,那是因为⼀个中⽂字符可能占⽤多个字节存储。所以Java提供⼀些字符流类,以字符为单位读写数据,专⻔⽤于处理⽂本⽂件
字符输⼊流【Reader】
java.io.Reader 抽象类是表示⽤于读取字符流的所有类的超类,可以读取字节信息到内存中。它定义了字节输⼊流的基本共性功能⽅法。
public void close() :关闭此流并释放与此流相关联的任何系统资源。
public int read() : 从输⼊流读取⼀个字符。
public int read(char[] cbuf) : 从输⼊流中读取⼀些字符,并将它们存储到字符数组 cbuf中 。
FileReader类
构造函数
FileReader(File file) : 创建⼀个新的 FileReader ,给定要读取的File对象。
FileReader(String fileName) : 创建⼀个新的 FileReader ,给定要读取的⽂件的名称。
当你创建⼀个流对象时,必须传⼊⼀个⽂件路径。类似于FileInputStream 。
public class FileReaderTest {
public static void main(String[] args) {
try {
Test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test1() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr1 = new FileReader(file);
// 使⽤⽂件名称创建流对象
FileReader fr2 = new FileReader("C:/Users/lighter/Desktop/a.txt");
}
}
read()
读取字符: read ⽅法,每次可以读取⼀个字符的数据,提升为int类型,读取到⽂件末尾,返
回 -1 ,循环读取
public class FileReaderTest {
public static void main(String[] args) {
try {
Test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test2() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定义变量,保存数据
int b;
// 循环读取
while ((b = fr.read())!=-1) {
System.out.println((char)b);
}
// 关闭资源
fr.close();
}
}
//文件文本
//abcdefg
//好好学习天天向上hijkl
//输出
a
b
c
d
e
f
g
好
好
学
习
天
天
向
上
h
i
j
k
l
read(char[] cbuf)
使⽤字符数组读取: read(char[] cbuf) ,每次读取b的⻓度个字符到数组中,返回读取到的有
效字符个数,读取到末尾时,返回 -1
public class FileReaderTest {
public static void main(String[] args) {
try {
Test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test3() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定义变量,保存数据
int len;
char[] cbuf = new char[3];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf));
}
// 关闭资源
fr.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好好学
3>>习天天
3>>向上h
3>>ijk
1>>ljk
读取有效字符
public class FileReaderTest {
public static void main(String[] args) {
try {
Test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test4() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定义变量,保存数据
int len;
char[] cbuf = new char[3];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf,0,len));
}
// 关闭资源
fr.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好好学
3>>习天天
3>>向上h
3>>ijk
1>>l
字符输出流【Writer】
java.io.Writer 抽象类是表示⽤于写出字符流的所有类的超类,将指定的字符信息写出到⽬的地。它定义了字节输出流的基本共性功能⽅法。
public abstract void close() :关闭此输出流并释放与此流相关联的任何系统资源。
public abstract void flush() :刷新缓冲区,将缓冲区中的数据输出到⽬标⽂件中。
public void write(int b) :写出⼀个字符。
public void write(char[] cbuf) :将 b.length字符从指定的字符数组写出此输出流。
public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 offff开始输出到此输出流。
public void write(String str) :写出⼀个字符串。
FileWriter类
FileWriter(File file) : 创建⼀个新的 FileWriter,给定要读取的File对象。
FileWriter(String fileName) : 创建⼀个新的 FileWriter,给定要读取的⽂件的名称。
构造函数
public class FileWriterTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileWriter fw1 = new FileWriter(file);
// 使⽤⽂件名称创建流对象
FileWriter fw2 = new FileWriter("C:/Users/lighter/Desktop/a.txt");
}
}
write(int b)
写出字符: write(int b) ⽅法,每次可以写出⼀个字符数据
public class FileWriterTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//写一个字符
fw.write(97);
//第二个字符
fw.write('a');
fw.write("好");
fw.write(30000);
fw.close();
}
}
//文件内容
aa好田
关闭与刷新
因为内置缓冲区的原因,如果不关闭输出流,⽆法写出字符到⽂件中。但是关闭的流对象,是⽆法继续写出数据的。如果我们既想写出数据,⼜想继续使⽤流,就需要 flush ⽅法了。
flush :刷新缓冲区,流对象可以继续使⽤。
close :关闭流,释放系统资源。关闭前会刷新缓冲区,流对象不可以继续使⽤。
public class FileWriterTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//写一个字符
fw.write(97);
//第二个字符
fw.write('a');
fw.flush();
fw.write("好");
fw.close();
fw.write(30000);
fw.close();
}
}
//文件内容
aa好
//输出
java.io.IOException: Stream closed
at sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:45)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:118)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:113)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:194)
at cn.gdmcmc.esi.IO.FileWriterTest.test3(FileWriterTest.java:32)
at cn.gdmcmc.esi.IO.FileWriterTest.main(FileWriterTest.java:16)
write(char[] cbuf)
public class FileWriterTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好学习,天天向上".toCharArray();
fw.write(chars);
fw.close();
}
}
//输出
好好学习,天天向上
write(char[] cbuf, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好学习,天天向上".toCharArray();
fw.write(chars,2,3);
fw.close();
}
}
//输出
学习,
write(String str)
public class FileWriterTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好学习,天天向上";
fw.write(str);
fw.close();
}
}
//输入
好好学习,天天向上
write(String str, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test7();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test7() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好学习,天天向上";
fw.write(str,3,4);
fw.close();
}
}
//输出
习,天天
缓冲流
字节缓冲流
构造函数
public BufferedInputStream(InputStream in) :创建⼀个 新的缓冲输⼊流。
public BufferedOutputStream(OutputStream out) : 创建⼀个新的缓冲输出流。
public class BufferedTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
//创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//创建字节缓冲输入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
}
}
读写数据
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//创建字节缓冲输入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
int b ;
while ((b = bis.read()) != -1){
bos.write(b);
}
bis.close();
bos.close();
}
}
字符缓冲流
构造函数
public BufferedReader(Reader in) :创建⼀个 新的缓冲输⼊流。
public BufferedWriter(Writer out) : 创建⼀个新的缓冲输出流
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//创建字符缓冲输入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
}
}
特有⽅法
BufferedReader: public String readLine() : 读⼀⾏⽂字。
BufferedWriter: public void newLine() : 输出⼀个换⾏符,由系统属性定义符号
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//创建字符缓冲输入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
String line = null;
int b ;
while((line = br.readLine()) != null){
/*while ((b = br.read()) != -1){
bw.write(b);
}*/
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
}
**备注:**缓冲流比字节输入流效率高很多;
转换流
字符编码:
计算机中储存的信息都是⽤⼆进制数表示的,⽽我们在屏幕上看到的数字、英⽂、标点符号、汉字等
字符是⼆进制数转换之后的结果。
按照某种规则,将字符存储到计算机中,称为编码 。
将存储在计算机中的⼆进制数按照某种规则解析显示出来,称为解码 。
字符编码 Character Encoding
字符编码 Character Encoding : 就是⼀套⾃然语⾔的字符与⼆进制数之间的对应规则。
编码表概述:
计算机存储字符时将字符查询码表,然后存储对应的⼆进制。
计算机取出字符时将⼆进制查询码表,然后转换成对应的字符显示。
ASCII:
* 美国码表,码表中只有英⽂⼤⼩写字⺟、数字、美式标点符号等。每个字符占⽤1个字节,所有字符映射的⼆进制都为正数,因此有128个字符映射关系。
GB2312:
* 兼容ASCII码表,并加⼊了中⽂字符,码表中英⽂⼤⼩写字⺟、数字、美式标点符号占⼀个字节,中⽂占两个字节,中⽂映射的⼆进制都是负数,因此有128× 128 = 16384个字符映射关系。
GBK/GB18030:
* 兼容GB2312码表,英⽂⼤⼩写字⺟、数字、美式标点符号,占⼀个字节。中⽂占两个字节,第⼀个字节为负数,第⼆个字节为正数和负数,因为有128× 256 = 32768个字符映射关系。
Unicode码表:
* 国际码表,包含各国⼤多数常⽤字符,每个字符都占2个字节,因此有65536个字符映射关系。Java语⾔使⽤的就是Unicode码表。
* Java中的char类型⽤的就是这个码表。char c = 'a';占两个字节。
UTF-8码表:
* 是基于Unicode码表的,但更智能,会根据字符的内容选择使⽤多个字节存储。英⽂占⼀个字节,中⽂占3个字节。
乱码的原因
* 因为⽂本在存储时使⽤的码表和读取时使⽤的码表不⼀致造成的。
InputStreamReader类
构造函数
InputStreamReader(InputStream in) : 创建⼀个使⽤默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName) : 创建⼀个指定字符集的字符流
public class switchTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//创建一个默认编码的转换字符输入流对象,utf-8
InputStreamReader isr = new InputStreamReader(fis);
//创建一个指定编码的转换字符输入流对象,gbk
InputStreamReader isr2 = new InputStreamReader(fis,"GBK");
}
}
读取数据
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//创建一个默认编码的转换输入流对象,utf-8
InputStreamReader isr = new InputStreamReader(fis,"gbk");
int b;
//对于gbk编码的文件输入
while ((b = isr.read()) != -1){
System.out.println((char)b);
}
isr.close();
}
}
OutputStreamWriter类
构造方法
OutputStreamWriter(OutputStream in) : 创建⼀个使⽤默认字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName) : 创建⼀个指定字符集的字符流。
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个默认编码的转换字符输出流对象,utf-8
OutputStreamWriter osw = new OutputStreamWriter(fos);
//创建一个指定编码的转换字符输出流对象,gbk
OutputStreamWriter osw2 = new OutputStreamWriter(fos,"gbk");
}
}
写出数据
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个指定编码的转换字符输出流对象,gbk
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
//按照指定编码输出字符,一个汉字占2个字节
//utf-8,一个汉字占3个字节
osw.write("你好");
osw.close();
}
}
序列化
概述
对象序列化概念
将对象转换为字节并保持到⽂件中的过程。
对象反序列化概念
将保持在⽂件中的字节读取出来并转换为对象的过程。
序列化
java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到⽂件,实现对象的持久存储。
满足条件:
1.该类必须实现 java.io.Serializable 接⼝, Serializable 是⼀个标记接⼝,不实现此接⼝的类的对象在序列化过程中会抛出 NotSerializableException 。
构造函数
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个序列化输出对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
writeObject()
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个序列化输出对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
Student s = new Student();
s.name = "张三";
s.age = 25;
oos.writeObject(s);
oos.close();
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个序列化输出对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
transient
transient 关键字作⽤
⽤来修饰成员变量的,能够保证该成员变量的值不会被序列化到⽂件中
transient 使⽤格式
修饰符 transient 数据类型 变量名
反序列化
ObjectInputStream反序列化流,将之前使⽤ObjectOutputStream序列化的原始数据恢复为对象。
构造方法
public ObjectInputStream(InputStream in) : 创建⼀个指定InputStream的ObjectInputStream。
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//创建一个序列化输出对象
ObjectInputStream ois = new ObjectInputStream(fos);
}
}
readObject ()
public class SerializableTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//创建一个序列化输出对象
ObjectInputStream ois = new ObjectInputStream(fos);
Student s = (Student)ois.readObject();
System.out.println(s.name);
System.out.println(s.age);
s.vivw();
ois.close();
}
}
打印流
平时我们在控制台打印输出,是调⽤ print ⽅法和 println ⽅法完成的,这两个⽅法都来⾃于 java.io.PrintStream 类,该类能够⽅便地打印各种数据类型的值,是⼀种便捷的输出⽅式。
PrintStream类
构造函数
public PrintStream(String fileName) : 使⽤指定的⽂件名创建⼀个新的打印流。
public class PrintStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
}
}
输出
public class PrintStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
// 设置系统的打印流流向,输出到a.txt
System.setOut(ps);
//调用系统的打印流,再a.txt输出97
System.out.println(97);
}
}
关系图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BX44YS3n-1592293192803)(E:\博客文档\Java加强\img\IO1.jpg)]
源码
FileInputStream
public class FileInputStream extends InputStream{
private final FileDescriptor fd;
private final String path;
private FileChannel channel = null;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//构造函数
//用文件名创建字节输入流
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
//用File创建字节输入流,主要创建函数
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
//创建一个安全管理器
//在我们要测试一个未知的可能有风险的程序时需要开启安全管理器,这样保证这个未知程序启动的时候不会损害到我们的系统
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
//文件描述符
fd = new FileDescriptor();
fd.attach(this);
path = name;
open(name);
}
//native 方法
private native void open0(String name) throws FileNotFoundException;
private void open(String name) throws FileNotFoundException {
open0(name);
}
//读取
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;
private native int readBytes(byte b[], int off, int len) throws IOException;
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileDescriptor
public final class FileDescriptor {
private int fd;
private long handle;
private Closeable parent;
private List<Closeable> otherParents;
private boolean closed;
/**
* Constructs an (invalid) FileDescriptor
* object.
*/
public /**/ FileDescriptor() {
fd = -1;
handle = -1;
}
synchronized void attach(Closeable c) {
if (parent == null) {
// first caller gets to do this
parent = c;
} else if (otherParents == null) {
otherParents = new ArrayList<>();
otherParents.add(parent);
otherParents.add(c);
} else {
otherParents.add(c);
}
}
}
FileOutputStream
public class FileOutputStream extends OutputStream{
private final FileDescriptor fd;
private final boolean append;
private FileChannel channel;
private final String path;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//文件名构造函数
public FileOutputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null, false);
}
//文件名构造函数,true
public FileOutputStream(String name, boolean append)
throws FileNotFoundException
{
this(name != null ? new File(name) : null, append);
}
public FileOutputStream(File file) throws FileNotFoundException {
this(file, false);
}
//都是用这个文件,boolean 来创建的
public FileOutputStream(File file, boolean append)
throws FileNotFoundException
{
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
this.fd = new FileDescriptor();
fd.attach(this);
this.append = append;
this.path = name;
open(name, append);
}
private native void open0(String name, boolean append)
throws FileNotFoundException;
private void open(String name, boolean append)
throws FileNotFoundException {
open0(name, append);
}
private native void write(int b, boolean append) throws IOException;
public void write(int b) throws IOException {
write(b, append);
}
private native void writeBytes(byte b[], int off, int len, boolean append)
throws IOException;
public void write(byte b[]) throws IOException {
writeBytes(b, 0, b.length, append);
}
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, append);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileReader
public class FileReader extends InputStreamReader {
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}
}
InputStreamReader
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
//调用的是StreamDecoder.read()方法
public int read() throws IOException {
return sd.read();
/*
StreamDecoder.class
public int read() throws IOException {
return this.read0();
}
private int read0() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.haveLeftoverChar) {
this.haveLeftoverChar = false;
return this.leftoverChar;
} else {
char[] var2 = new char[2];
int var3 = this.read(var2, 0, 2);
switch(var3) {
case -1:
return -1;
case 0:
default:
assert false : var3;
return -1;
case 2:
this.leftoverChar = var2[1];
this.haveLeftoverChar = true;
case 1:
return var2[0];
}
}
}
}
*/
}
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
public boolean ready() throws IOException {
return sd.ready();
}
public void close() throws IOException {
sd.close();
}
}
Reader
public abstract class Reader implements Readable, Closeable {
protected Object lock;
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
FileWriter
public class FileWriter extends OutputStreamWriter {
public FileWriter(String fileName) throws IOException {
super(new FileOutputStream(fileName));
}
public FileWriter(String fileName, boolean append) throws IOException {
super(new FileOutputStream(fileName, append));
}
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}
public FileWriter(File file, boolean append) throws IOException {
super(new FileOutputStream(file, append));
}
}
OutputStreamWriter
public class OutputStreamWriter extends Writer {
private final StreamEncoder se;
public OutputStreamWriter(OutputStream out) {
super(out);
try {
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
public void write(int c) throws IOException {
se.write(c);
/*StreamEncoder.class
public void write(int var1) throws IOException {
char[] var2 = new char[]{(char)var1};
this.write((char[])var2, 0, 1);
}
public void write(char[] var1, int var2, int var3) throws IOException {
Object var4 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
if (var2 >= 0 && var2 <= var1.length && var3 >= 0 && var2 + var3 <= var1.length && var2 + var3 >= 0) {
if (var3 != 0) {
this.implWrite(var1, var2, var3);
}
} else {
throw new IndexOutOfBoundsException();
}
}
}
*/
}
public void write(char cbuf[], int off, int len) throws IOException {
se.write(cbuf, off, len);
}
public void write(String str, int off, int len) throws IOException {
se.write(str, off, len);
}
public void flush() throws IOException {
se.flush();
/* StreamEncoder.class
public void flush() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
this.implFlush();
}
}
*/
}
public void close() throws IOException {
se.close();
/* StreamEncoder.class
public void close() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.isOpen) {
this.implClose();
this.isOpen = false;
}
}
}
*/
}
}
Writer
public abstract class Writer implements Appendable, Closeable, Flushable {
private char[] writeBuffer;
private static final int WRITE_BUFFER_SIZE = 1024;
protected Object lock;
protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
拓展
字符流和字节流的区别
字符流操作文件先经过缓冲区(内存)然后再通过缓冲区再操作文件
字节流操作文件不会经过缓冲区(内存直接操作文件本身)
缓冲区的作用
缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就显著提升了性能
对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作
字符流和字节流的选择
**选择字节流:**大多数时候 IO 操作都是直接操作磁盘文件,所以这些流在传输时都是以字节的方式进行的(图片等都是按字节存储的)
**选择字符流:**通过 IO 在内存中频繁处理字符串的情况使用字符流会好些,因为字符流具备缓冲区,提高了性能
序列化及实现
序列化就是一种用来处理对象流的机制,将对象的内容进行流化。可以对流化后的对象进行读写操作,可以将流化后的对象传输于网络之间。序列化是为了解决在对象流读写操作时所引发的问题
将需要被序列化的类实现Serialize接口,没有需要实现的方法,此接口只是为了标注对象可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,再使用ObjectOutputStream对象的write(Object obj)方法就可以将参数obj的对象写出
PrintStream/BufferedWriter/PrintWriter
PrintStream类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成PrintStream后进行输出。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;
BufferedWriter类将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须通过调用flush方法才能将其刷出去。并且BufferedWriter只能对字符流进行操作。
PrintWriter类的println方法自动添加换行,不会抛异常,若关心异常,需要调用checkError方法看是否有异常发生,PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush)
节点流/处理流定义及作用
节点流: 直接与数据源相连,用于输入或者输出(字节流)
**处理流:**在节点流的基础上对之进行加工,进行一些功能的扩展; 处理流的构造器必须要传入节点流的子类(字节缓冲流)
流的关闭及位置处理
流一旦打开就必须关闭,使用close方法;放入finally语句块中(finally 语句一定会执行);多个流互相调用只关闭最外层的流
Java加强–2.IO流
IO概述
我们把这种数据的传输,可以看做是⼀种数据的流动,按照流动的⽅向,以内存为基准,分为 输⼊
input 和 输出output ,即流向内存是输⼊流,流出内存的输出流
Java中I/O操作主要是指使⽤ java.io 包下的内容,进⾏输⼊、输出操作。输⼊也叫做读取数据,输
出也叫做作写出数据
IO的分类
根据数据的流向分为:输⼊流和输出流。
输⼊流 :把数据从 其他设备 上读取到 内存 中的流。
输出流 :把数据从 内存 中写出到 其他设备 上的流。
根据数据的类型分为:字节流和字符流。
字节流 :以字节为单位,读写数据的流。
字符流 :以字符为单位,读写数据的流。
父类:
输⼊流 | 输出流 | |
---|---|---|
字节流 | 字节输⼊流 InputStream | 字节输出流OutputStream |
字符流 | 字符输⼊流Reader | 字符输出流Writer |
字节流
数据本质
⼀切⽂件数据(⽂本、图⽚、视频等)在存储时,都是以⼆进制数字的形式保存,都⼀个⼀个的字节,
那么传输时⼀样如此。所以,字节流可以传输任意⽂件数据。在操作流的时候,我们要时刻明确,⽆
论使⽤什么样的流对象,底层传输的始终为⼆进制数据。
任意类型的数据在计算机中都是以⼆进制形式存在。数据的本质就是⼆进制
字节输出流【OutputStream】
java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到⽬的
地。它定义了字节输出流的基本共性功能⽅法
public void close() :关闭此输出流并释放与此流相关联的任何系统资源
public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出
public void write(byte[] b) :将 b.length字节从指定的字节数组写⼊此输出流
public void write(byte[] b, int off, int len) :从指定的字节数组写⼊ len字节,从偏移量 offff开始输出到此输出流
public abstract void write(int b) :将指定的字节输出流
备注: close⽅法,当完成流的操作时,必须调⽤此⽅法,释放系统资源
FileOutputStream类
java.io.FileOutputStream 类是⽂件输出流,⽤于将数据写出到⽂件
public FileOutputStream(File file) :创建⽂件输出流以写⼊由指定的 File对象表示的⽂件
public FileOutputStream(String name) : 创建⽂件输出流以指定的名称写⼊⽂件
构造函数
public class OutputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
static void test1() throws FileNotFoundException {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//使用文件名创建流对象
OutputStream os1 = new FileOutputStream("C:/Users/lighter/Desktop/b.txt");
}
}
write(int b)
写出字节: write(int b) ⽅法,每次可以写出⼀个字节数据
public class OutputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//第一个字节,ASCII十进制对应字符
os.write(97);
os.write(98);
os.write(99);
//关闭资源
os.close();
}
}
//a.txt文件中
abc
**备注:**流操作完毕后,必须释放系统资源,调⽤close⽅法,千万记得
写出字节数组: write(byte[] b) ,每次可以写出数组中的数据
public class OutputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串转换为字节数组
byte[] bytes = "好好学习,天天向上".getBytes();
//输入字节数组
os.write(bytes);
//关闭资源
os.close();
}
}
//文件内容,之前的被覆盖掉了
好好学习,天天向上
write(byte[] b, int off, int len)
写出指定⻓度字节数组: write(byte[] b, int off, int len) ,每次写出从offff索引开始,len个字节
public class OutputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串转换为字节数组
byte[] bytes = "好好学习,天天向上".getBytes();
//输入字节数组,从索引2开始,3个字节
os.write(bytes,6,3);
//关闭资源
os.close();
}
}
//文件内容,之前的被覆盖掉了
//三个字节转一个汉字,如果是中文,这里要注意算3的倍数
学
数据追加续写
public FileOutputStream(File file, boolean append) : 创建⽂件输出流以写⼊由指定的File对象表示的⽂件。
public FileOutputStream(String name, boolean append) : 创建⽂件输出流以指定的名称写⼊⽂件。
这两个构造⽅法,参数中都需要传⼊⼀个boolean类型的值, true 表示追加数据, false 表示清空原有数据。这样创建的输出流对象,就可以指定是否追加续写了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串转换为字节数组
byte[] bytes = "好好学习,天天向上".getBytes();
//输入字节数组
os.write(bytes);
//关闭资源
os.close();
}
}
//文件内容
学好好学习,天天向上
换行
Windows系统⾥,换⾏符号是 \r\n 。把以指定是否追加续写了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串转换为字节数组
byte[] bytes = "已经换行".getBytes();
//换行
os.write("\r\n".getBytes());
//输入字节数组
os.write(bytes);
//关闭资源
os.close();
}
}
//文件内容,包含之前(已换行)
学好好学习,天天向上
已经换行
回⻋符 \r 和换⾏符 \n :
回⻋符:回到⼀⾏的开头(return)。
换⾏符:另起⼀⾏(newline)。
系统中的换⾏:
Windows系统⾥,每⾏结尾是 回⻋+换⾏ ,即 \r\n ;
Unix系统⾥,每⾏结尾只有 换⾏ ,即 \n ;
Mac系统⾥,每⾏结尾是 回⻋ ,即 \r 。从 Mac OS X开始与Linux统⼀。
字节输⼊流【InputStream】
java.io.InputStream 抽象类是表示字节输⼊流的所有类的超类,可以读取字节信息到内存中。它定义了字节输⼊流的基本共性功能⽅法。
public void close() :关闭此输⼊流并释放与此流相关联的任何系统资源。
public abstract int read() : 从输⼊流读取数据的下⼀个字节。
public int read(byte[] b) : 从输⼊流中读取⼀些字节数,并将它们存储到字节数组 b中 。
备注:close⽅法,当完成流的操作时,必须调⽤此⽅法,释放系统资源
FileInputStream类
java.io.FileInputStream 类是⽂件输⼊流,从⽂件中读取字节
构造函数
FileInputStream(File file) : 通过打开与实际⽂件的连接来创建⼀个 FileInputStream ,该⽂件由⽂件系统中的 File对象 fifile命名。
FileInputStream(String name) : 通过打开与实际⽂件的连接来创建⼀个 FileInputStream ,该⽂件由⽂件系统中的路径名 name命名。
当你创建⼀个流对象时,必须传⼊⼀个⽂件路径。该路径下,如果没有该⽂件,会抛出FileNotFoundException
public class InputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos1 = new FileInputStream(file);
// 使⽤⽂件名称创建流对象
FileInputStream fos2 = new FileInputStream("C:/Users/lighter/Desktop/a.txt");
}
}
read()
读取字节: read (),每次可以读取⼀个字节的数据,提升为int类型,读取到⽂件末尾,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
int b;
//读取每一个字节数据,= -1 读完
while ((b = fis.read()) != -1){
System.out.println(b +">>"+(char) b);
}
//释放资源
fis.close();
}
}
//文件中内容:abcdefg
//输出:
97>>a
98>>b
99>>c
100>>d
101>>e
102>>f
103>>g
read(byte[] b)
使⽤字节数组读取: read(byte[] b) ,每次读取b的⻓度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字节个数
int len;
//定义读取到的字节数组,作为装字节数据的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字节数组转化成字符串打印
System.out.println(len +">>"+new String(b));
}
fis.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>学
3>>习
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>klj
读取有效字节
错误数据 j ,是由于最后⼀次读取时,只读取2个字节kl ,数组中,上次读取的数据没有被完全替换,所以要通过 len ,获取有效的字节,
public class InputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字节个数
int len;
//定义读取到的字节数组,作为装字节数据的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字节数组转化成字符串打印,打印有效的字符串
System.out.println(len +">>"+new String(b,0,len));
}
fis.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>学
3>>习
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>kl
字符流
当使⽤字节流读取⽂本⽂件时,可能会有⼀个⼩问题。就是遇到中⽂字符时,可能不会显示完整的字符,那是因为⼀个中⽂字符可能占⽤多个字节存储。所以Java提供⼀些字符流类,以字符为单位读写数据,专⻔⽤于处理⽂本⽂件
字符输⼊流【Reader】
java.io.Reader 抽象类是表示⽤于读取字符流的所有类的超类,可以读取字节信息到内存中。它定义了字节输⼊流的基本共性功能⽅法。
public void close() :关闭此流并释放与此流相关联的任何系统资源。
public int read() : 从输⼊流读取⼀个字符。
public int read(char[] cbuf) : 从输⼊流中读取⼀些字符,并将它们存储到字符数组 cbuf中 。
FileReader类
构造函数
FileReader(File file) : 创建⼀个新的 FileReader ,给定要读取的File对象。
FileReader(String fileName) : 创建⼀个新的 FileReader ,给定要读取的⽂件的名称。
当你创建⼀个流对象时,必须传⼊⼀个⽂件路径。类似于FileInputStream 。
public class FileReaderTest {
public static void main(String[] args) {
try {
Test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test1() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr1 = new FileReader(file);
// 使⽤⽂件名称创建流对象
FileReader fr2 = new FileReader("C:/Users/lighter/Desktop/a.txt");
}
}
read()
读取字符: read ⽅法,每次可以读取⼀个字符的数据,提升为int类型,读取到⽂件末尾,返
回 -1 ,循环读取
public class FileReaderTest {
public static void main(String[] args) {
try {
Test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test2() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定义变量,保存数据
int b;
// 循环读取
while ((b = fr.read())!=-1) {
System.out.println((char)b);
}
// 关闭资源
fr.close();
}
}
//文件文本
//abcdefg
//好好学习天天向上hijkl
//输出
a
b
c
d
e
f
g
好
好
学
习
天
天
向
上
h
i
j
k
l
read(char[] cbuf)
使⽤字符数组读取: read(char[] cbuf) ,每次读取b的⻓度个字符到数组中,返回读取到的有
效字符个数,读取到末尾时,返回 -1
public class FileReaderTest {
public static void main(String[] args) {
try {
Test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test3() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定义变量,保存数据
int len;
char[] cbuf = new char[3];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf));
}
// 关闭资源
fr.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好好学
3>>习天天
3>>向上h
3>>ijk
1>>ljk
读取有效字符
public class FileReaderTest {
public static void main(String[] args) {
try {
Test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test4() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定义变量,保存数据
int len;
char[] cbuf = new char[3];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf,0,len));
}
// 关闭资源
fr.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好好学
3>>习天天
3>>向上h
3>>ijk
1>>l
字符输出流【Writer】
java.io.Writer 抽象类是表示⽤于写出字符流的所有类的超类,将指定的字符信息写出到⽬的地。它定义了字节输出流的基本共性功能⽅法。
public abstract void close() :关闭此输出流并释放与此流相关联的任何系统资源。
public abstract void flush() :刷新缓冲区,将缓冲区中的数据输出到⽬标⽂件中。
public void write(int b) :写出⼀个字符。
public void write(char[] cbuf) :将 b.length字符从指定的字符数组写出此输出流。
public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 offff开始输出到此输出流。
public void write(String str) :写出⼀个字符串。
FileWriter类
FileWriter(File file) : 创建⼀个新的 FileWriter,给定要读取的File对象。
FileWriter(String fileName) : 创建⼀个新的 FileWriter,给定要读取的⽂件的名称。
构造函数
public class FileWriterTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileWriter fw1 = new FileWriter(file);
// 使⽤⽂件名称创建流对象
FileWriter fw2 = new FileWriter("C:/Users/lighter/Desktop/a.txt");
}
}
write(int b)
写出字符: write(int b) ⽅法,每次可以写出⼀个字符数据
public class FileWriterTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//写一个字符
fw.write(97);
//第二个字符
fw.write('a');
fw.write("好");
fw.write(30000);
fw.close();
}
}
//文件内容
aa好田
关闭与刷新
因为内置缓冲区的原因,如果不关闭输出流,⽆法写出字符到⽂件中。但是关闭的流对象,是⽆法继续写出数据的。如果我们既想写出数据,⼜想继续使⽤流,就需要 flush ⽅法了。
flush :刷新缓冲区,流对象可以继续使⽤。
close :关闭流,释放系统资源。关闭前会刷新缓冲区,流对象不可以继续使⽤。
public class FileWriterTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//写一个字符
fw.write(97);
//第二个字符
fw.write('a');
fw.flush();
fw.write("好");
fw.close();
fw.write(30000);
fw.close();
}
}
//文件内容
aa好
//输出
java.io.IOException: Stream closed
at sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:45)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:118)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:113)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:194)
at cn.gdmcmc.esi.IO.FileWriterTest.test3(FileWriterTest.java:32)
at cn.gdmcmc.esi.IO.FileWriterTest.main(FileWriterTest.java:16)
write(char[] cbuf)
public class FileWriterTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好学习,天天向上".toCharArray();
fw.write(chars);
fw.close();
}
}
//输出
好好学习,天天向上
write(char[] cbuf, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好学习,天天向上".toCharArray();
fw.write(chars,2,3);
fw.close();
}
}
//输出
学习,
write(String str)
public class FileWriterTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好学习,天天向上";
fw.write(str);
fw.close();
}
}
//输入
好好学习,天天向上
write(String str, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test7();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test7() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好学习,天天向上";
fw.write(str,3,4);
fw.close();
}
}
//输出
习,天天
缓冲流
字节缓冲流
构造函数
public BufferedInputStream(InputStream in) :创建⼀个 新的缓冲输⼊流。
public BufferedOutputStream(OutputStream out) : 创建⼀个新的缓冲输出流。
public class BufferedTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
//创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//创建字节缓冲输入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
}
}
读写数据
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//创建字节缓冲输入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
int b ;
while ((b = bis.read()) != -1){
bos.write(b);
}
bis.close();
bos.close();
}
}
字符缓冲流
构造函数
public BufferedReader(Reader in) :创建⼀个 新的缓冲输⼊流。
public BufferedWriter(Writer out) : 创建⼀个新的缓冲输出流
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//创建字符缓冲输入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
}
}
特有⽅法
BufferedReader: public String readLine() : 读⼀⾏⽂字。
BufferedWriter: public void newLine() : 输出⼀个换⾏符,由系统属性定义符号
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//创建字符缓冲输入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
String line = null;
int b ;
while((line = br.readLine()) != null){
/*while ((b = br.read()) != -1){
bw.write(b);
}*/
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
}
**备注:**缓冲流比字节输入流效率高很多;
转换流
字符编码:
计算机中储存的信息都是⽤⼆进制数表示的,⽽我们在屏幕上看到的数字、英⽂、标点符号、汉字等
字符是⼆进制数转换之后的结果。
按照某种规则,将字符存储到计算机中,称为编码 。
将存储在计算机中的⼆进制数按照某种规则解析显示出来,称为解码 。
字符编码 Character Encoding
字符编码 Character Encoding : 就是⼀套⾃然语⾔的字符与⼆进制数之间的对应规则。
编码表概述:
计算机存储字符时将字符查询码表,然后存储对应的⼆进制。
计算机取出字符时将⼆进制查询码表,然后转换成对应的字符显示。
ASCII:
* 美国码表,码表中只有英⽂⼤⼩写字⺟、数字、美式标点符号等。每个字符占⽤1个字节,所有字符映射的⼆进制都为正数,因此有128个字符映射关系。
GB2312:
* 兼容ASCII码表,并加⼊了中⽂字符,码表中英⽂⼤⼩写字⺟、数字、美式标点符号占⼀个字节,中⽂占两个字节,中⽂映射的⼆进制都是负数,因此有128× 128 = 16384个字符映射关系。
GBK/GB18030:
* 兼容GB2312码表,英⽂⼤⼩写字⺟、数字、美式标点符号,占⼀个字节。中⽂占两个字节,第⼀个字节为负数,第⼆个字节为正数和负数,因为有128× 256 = 32768个字符映射关系。
Unicode码表:
* 国际码表,包含各国⼤多数常⽤字符,每个字符都占2个字节,因此有65536个字符映射关系。Java语⾔使⽤的就是Unicode码表。
* Java中的char类型⽤的就是这个码表。char c = 'a';占两个字节。
UTF-8码表:
* 是基于Unicode码表的,但更智能,会根据字符的内容选择使⽤多个字节存储。英⽂占⼀个字节,中⽂占3个字节。
乱码的原因
* 因为⽂本在存储时使⽤的码表和读取时使⽤的码表不⼀致造成的。
InputStreamReader类
构造函数
InputStreamReader(InputStream in) : 创建⼀个使⽤默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName) : 创建⼀个指定字符集的字符流
public class switchTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//创建一个默认编码的转换字符输入流对象,utf-8
InputStreamReader isr = new InputStreamReader(fis);
//创建一个指定编码的转换字符输入流对象,gbk
InputStreamReader isr2 = new InputStreamReader(fis,"GBK");
}
}
读取数据
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//创建一个默认编码的转换输入流对象,utf-8
InputStreamReader isr = new InputStreamReader(fis,"gbk");
int b;
//对于gbk编码的文件输入
while ((b = isr.read()) != -1){
System.out.println((char)b);
}
isr.close();
}
}
OutputStreamWriter类
构造方法
OutputStreamWriter(OutputStream in) : 创建⼀个使⽤默认字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName) : 创建⼀个指定字符集的字符流。
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个默认编码的转换字符输出流对象,utf-8
OutputStreamWriter osw = new OutputStreamWriter(fos);
//创建一个指定编码的转换字符输出流对象,gbk
OutputStreamWriter osw2 = new OutputStreamWriter(fos,"gbk");
}
}
写出数据
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个指定编码的转换字符输出流对象,gbk
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
//按照指定编码输出字符,一个汉字占2个字节
//utf-8,一个汉字占3个字节
osw.write("你好");
osw.close();
}
}
序列化
概述
对象序列化概念
将对象转换为字节并保持到⽂件中的过程。
对象反序列化概念
将保持在⽂件中的字节读取出来并转换为对象的过程。
序列化
java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到⽂件,实现对象的持久存储。
满足条件:
1.该类必须实现 java.io.Serializable 接⼝, Serializable 是⼀个标记接⼝,不实现此接⼝的类的对象在序列化过程中会抛出 NotSerializableException 。
构造函数
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个序列化输出对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
writeObject()
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个序列化输出对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
Student s = new Student();
s.name = "张三";
s.age = 25;
oos.writeObject(s);
oos.close();
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个序列化输出对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
transient
transient 关键字作⽤
⽤来修饰成员变量的,能够保证该成员变量的值不会被序列化到⽂件中
transient 使⽤格式
修饰符 transient 数据类型 变量名
反序列化
ObjectInputStream反序列化流,将之前使⽤ObjectOutputStream序列化的原始数据恢复为对象。
构造方法
public ObjectInputStream(InputStream in) : 创建⼀个指定InputStream的ObjectInputStream。
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//创建一个序列化输出对象
ObjectInputStream ois = new ObjectInputStream(fos);
}
}
readObject ()
public class SerializableTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//创建一个序列化输出对象
ObjectInputStream ois = new ObjectInputStream(fos);
Student s = (Student)ois.readObject();
System.out.println(s.name);
System.out.println(s.age);
s.vivw();
ois.close();
}
}
打印流
平时我们在控制台打印输出,是调⽤ print ⽅法和 println ⽅法完成的,这两个⽅法都来⾃于 java.io.PrintStream 类,该类能够⽅便地打印各种数据类型的值,是⼀种便捷的输出⽅式。
PrintStream类
构造函数
public PrintStream(String fileName) : 使⽤指定的⽂件名创建⼀个新的打印流。
public class PrintStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
}
}
输出
public class PrintStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
// 设置系统的打印流流向,输出到a.txt
System.setOut(ps);
//调用系统的打印流,再a.txt输出97
System.out.println(97);
}
}
关系图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6asoYU7S-1592293193461)(E:\博客文档\Java加强\img\IO1.jpg)]
源码
FileInputStream
public class FileInputStream extends InputStream{
private final FileDescriptor fd;
private final String path;
private FileChannel channel = null;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//构造函数
//用文件名创建字节输入流
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
//用File创建字节输入流,主要创建函数
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
//创建一个安全管理器
//在我们要测试一个未知的可能有风险的程序时需要开启安全管理器,这样保证这个未知程序启动的时候不会损害到我们的系统
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
//文件描述符
fd = new FileDescriptor();
fd.attach(this);
path = name;
open(name);
}
//native 方法
private native void open0(String name) throws FileNotFoundException;
private void open(String name) throws FileNotFoundException {
open0(name);
}
//读取
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;
private native int readBytes(byte b[], int off, int len) throws IOException;
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileDescriptor
public final class FileDescriptor {
private int fd;
private long handle;
private Closeable parent;
private List<Closeable> otherParents;
private boolean closed;
/**
* Constructs an (invalid) FileDescriptor
* object.
*/
public /**/ FileDescriptor() {
fd = -1;
handle = -1;
}
synchronized void attach(Closeable c) {
if (parent == null) {
// first caller gets to do this
parent = c;
} else if (otherParents == null) {
otherParents = new ArrayList<>();
otherParents.add(parent);
otherParents.add(c);
} else {
otherParents.add(c);
}
}
}
FileOutputStream
public class FileOutputStream extends OutputStream{
private final FileDescriptor fd;
private final boolean append;
private FileChannel channel;
private final String path;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//文件名构造函数
public FileOutputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null, false);
}
//文件名构造函数,true
public FileOutputStream(String name, boolean append)
throws FileNotFoundException
{
this(name != null ? new File(name) : null, append);
}
public FileOutputStream(File file) throws FileNotFoundException {
this(file, false);
}
//都是用这个文件,boolean 来创建的
public FileOutputStream(File file, boolean append)
throws FileNotFoundException
{
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
this.fd = new FileDescriptor();
fd.attach(this);
this.append = append;
this.path = name;
open(name, append);
}
private native void open0(String name, boolean append)
throws FileNotFoundException;
private void open(String name, boolean append)
throws FileNotFoundException {
open0(name, append);
}
private native void write(int b, boolean append) throws IOException;
public void write(int b) throws IOException {
write(b, append);
}
private native void writeBytes(byte b[], int off, int len, boolean append)
throws IOException;
public void write(byte b[]) throws IOException {
writeBytes(b, 0, b.length, append);
}
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, append);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileReader
public class FileReader extends InputStreamReader {
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}
}
InputStreamReader
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
//调用的是StreamDecoder.read()方法
public int read() throws IOException {
return sd.read();
/*
StreamDecoder.class
public int read() throws IOException {
return this.read0();
}
private int read0() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.haveLeftoverChar) {
this.haveLeftoverChar = false;
return this.leftoverChar;
} else {
char[] var2 = new char[2];
int var3 = this.read(var2, 0, 2);
switch(var3) {
case -1:
return -1;
case 0:
default:
assert false : var3;
return -1;
case 2:
this.leftoverChar = var2[1];
this.haveLeftoverChar = true;
case 1:
return var2[0];
}
}
}
}
*/
}
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
public boolean ready() throws IOException {
return sd.ready();
}
public void close() throws IOException {
sd.close();
}
}
Reader
public abstract class Reader implements Readable, Closeable {
protected Object lock;
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
FileWriter
public class FileWriter extends OutputStreamWriter {
public FileWriter(String fileName) throws IOException {
super(new FileOutputStream(fileName));
}
public FileWriter(String fileName, boolean append) throws IOException {
super(new FileOutputStream(fileName, append));
}
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}
public FileWriter(File file, boolean append) throws IOException {
super(new FileOutputStream(file, append));
}
}
OutputStreamWriter
public class OutputStreamWriter extends Writer {
private final StreamEncoder se;
public OutputStreamWriter(OutputStream out) {
super(out);
try {
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
public void write(int c) throws IOException {
se.write(c);
/*StreamEncoder.class
public void write(int var1) throws IOException {
char[] var2 = new char[]{(char)var1};
this.write((char[])var2, 0, 1);
}
public void write(char[] var1, int var2, int var3) throws IOException {
Object var4 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
if (var2 >= 0 && var2 <= var1.length && var3 >= 0 && var2 + var3 <= var1.length && var2 + var3 >= 0) {
if (var3 != 0) {
this.implWrite(var1, var2, var3);
}
} else {
throw new IndexOutOfBoundsException();
}
}
}
*/
}
public void write(char cbuf[], int off, int len) throws IOException {
se.write(cbuf, off, len);
}
public void write(String str, int off, int len) throws IOException {
se.write(str, off, len);
}
public void flush() throws IOException {
se.flush();
/* StreamEncoder.class
public void flush() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
this.implFlush();
}
}
*/
}
public void close() throws IOException {
se.close();
/* StreamEncoder.class
public void close() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.isOpen) {
this.implClose();
this.isOpen = false;
}
}
}
*/
}
}
Writer
public abstract class Writer implements Appendable, Closeable, Flushable {
private char[] writeBuffer;
private static final int WRITE_BUFFER_SIZE = 1024;
protected Object lock;
protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
拓展
字符流和字节流的区别
字符流操作文件先经过缓冲区(内存)然后再通过缓冲区再操作文件
字节流操作文件不会经过缓冲区(内存直接操作文件本身)
缓冲区的作用
缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就显著提升了性能
对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作
字符流和字节流的选择
**选择字节流:**大多数时候 IO 操作都是直接操作磁盘文件,所以这些流在传输时都是以字节的方式进行的(图片等都是按字节存储的)
**选择字符流:**通过 IO 在内存中频繁处理字符串的情况使用字符流会好些,因为字符流具备缓冲区,提高了性能
序列化及实现
序列化就是一种用来处理对象流的机制,将对象的内容进行流化。可以对流化后的对象进行读写操作,可以将流化后的对象传输于网络之间。序列化是为了解决在对象流读写操作时所引发的问题
将需要被序列化的类实现Serialize接口,没有需要实现的方法,此接口只是为了标注对象可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,再使用ObjectOutputStream对象的write(Object obj)方法就可以将参数obj的对象写出
PrintStream/BufferedWriter/PrintWriter
PrintStream类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成PrintStream后进行输出。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;
BufferedWriter类将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须通过调用flush方法才能将其刷出去。并且BufferedWriter只能对字符流进行操作。
PrintWriter类的println方法自动添加换行,不会抛异常,若关心异常,需要调用checkError方法看是否有异常发生,PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush)
节点流/处理流定义及作用
节点流: 直接与数据源相连,用于输入或者输出(字节流)
**处理流:**在节点流的基础上对之进行加工,进行一些功能的扩展; 处理流的构造器必须要传入节点流的子类(字节缓冲流)
流的关闭及位置处理
流一旦打开就必须关闭,使用close方法;放入finally语句块中(finally 语句一定会执行);多个流互相调用只关闭最外层的流
Java加强–2.IO流
IO概述
我们把这种数据的传输,可以看做是⼀种数据的流动,按照流动的⽅向,以内存为基准,分为 输⼊
input 和 输出output ,即流向内存是输⼊流,流出内存的输出流
Java中I/O操作主要是指使⽤ java.io 包下的内容,进⾏输⼊、输出操作。输⼊也叫做读取数据,输
出也叫做作写出数据
IO的分类
根据数据的流向分为:输⼊流和输出流。
输⼊流 :把数据从 其他设备 上读取到 内存 中的流。
输出流 :把数据从 内存 中写出到 其他设备 上的流。
根据数据的类型分为:字节流和字符流。
字节流 :以字节为单位,读写数据的流。
字符流 :以字符为单位,读写数据的流。
父类:
输⼊流 | 输出流 | |
---|---|---|
字节流 | 字节输⼊流 InputStream | 字节输出流OutputStream |
字符流 | 字符输⼊流Reader | 字符输出流Writer |
字节流
数据本质
⼀切⽂件数据(⽂本、图⽚、视频等)在存储时,都是以⼆进制数字的形式保存,都⼀个⼀个的字节,
那么传输时⼀样如此。所以,字节流可以传输任意⽂件数据。在操作流的时候,我们要时刻明确,⽆
论使⽤什么样的流对象,底层传输的始终为⼆进制数据。
任意类型的数据在计算机中都是以⼆进制形式存在。数据的本质就是⼆进制
字节输出流【OutputStream】
java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到⽬的
地。它定义了字节输出流的基本共性功能⽅法
public void close() :关闭此输出流并释放与此流相关联的任何系统资源
public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出
public void write(byte[] b) :将 b.length字节从指定的字节数组写⼊此输出流
public void write(byte[] b, int off, int len) :从指定的字节数组写⼊ len字节,从偏移量 offff开始输出到此输出流
public abstract void write(int b) :将指定的字节输出流
备注: close⽅法,当完成流的操作时,必须调⽤此⽅法,释放系统资源
FileOutputStream类
java.io.FileOutputStream 类是⽂件输出流,⽤于将数据写出到⽂件
public FileOutputStream(File file) :创建⽂件输出流以写⼊由指定的 File对象表示的⽂件
public FileOutputStream(String name) : 创建⽂件输出流以指定的名称写⼊⽂件
构造函数
public class OutputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
static void test1() throws FileNotFoundException {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//使用文件名创建流对象
OutputStream os1 = new FileOutputStream("C:/Users/lighter/Desktop/b.txt");
}
}
write(int b)
写出字节: write(int b) ⽅法,每次可以写出⼀个字节数据
public class OutputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//第一个字节,ASCII十进制对应字符
os.write(97);
os.write(98);
os.write(99);
//关闭资源
os.close();
}
}
//a.txt文件中
abc
**备注:**流操作完毕后,必须释放系统资源,调⽤close⽅法,千万记得
写出字节数组: write(byte[] b) ,每次可以写出数组中的数据
public class OutputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串转换为字节数组
byte[] bytes = "好好学习,天天向上".getBytes();
//输入字节数组
os.write(bytes);
//关闭资源
os.close();
}
}
//文件内容,之前的被覆盖掉了
好好学习,天天向上
write(byte[] b, int off, int len)
写出指定⻓度字节数组: write(byte[] b, int off, int len) ,每次写出从offff索引开始,len个字节
public class OutputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file);
//字符串转换为字节数组
byte[] bytes = "好好学习,天天向上".getBytes();
//输入字节数组,从索引2开始,3个字节
os.write(bytes,6,3);
//关闭资源
os.close();
}
}
//文件内容,之前的被覆盖掉了
//三个字节转一个汉字,如果是中文,这里要注意算3的倍数
学
数据追加续写
public FileOutputStream(File file, boolean append) : 创建⽂件输出流以写⼊由指定的File对象表示的⽂件。
public FileOutputStream(String name, boolean append) : 创建⽂件输出流以指定的名称写⼊⽂件。
这两个构造⽅法,参数中都需要传⼊⼀个boolean类型的值, true 表示追加数据, false 表示清空原有数据。这样创建的输出流对象,就可以指定是否追加续写了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串转换为字节数组
byte[] bytes = "好好学习,天天向上".getBytes();
//输入字节数组
os.write(bytes);
//关闭资源
os.close();
}
}
//文件内容
学好好学习,天天向上
换行
Windows系统⾥,换⾏符号是 \r\n 。把以指定是否追加续写了
public class OutputStreamTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
//使用File对向创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
OutputStream os = new FileOutputStream(file,true);
//字符串转换为字节数组
byte[] bytes = "已经换行".getBytes();
//换行
os.write("\r\n".getBytes());
//输入字节数组
os.write(bytes);
//关闭资源
os.close();
}
}
//文件内容,包含之前(已换行)
学好好学习,天天向上
已经换行
回⻋符 \r 和换⾏符 \n :
回⻋符:回到⼀⾏的开头(return)。
换⾏符:另起⼀⾏(newline)。
系统中的换⾏:
Windows系统⾥,每⾏结尾是 回⻋+换⾏ ,即 \r\n ;
Unix系统⾥,每⾏结尾只有 换⾏ ,即 \n ;
Mac系统⾥,每⾏结尾是 回⻋ ,即 \r 。从 Mac OS X开始与Linux统⼀。
字节输⼊流【InputStream】
java.io.InputStream 抽象类是表示字节输⼊流的所有类的超类,可以读取字节信息到内存中。它定义了字节输⼊流的基本共性功能⽅法。
public void close() :关闭此输⼊流并释放与此流相关联的任何系统资源。
public abstract int read() : 从输⼊流读取数据的下⼀个字节。
public int read(byte[] b) : 从输⼊流中读取⼀些字节数,并将它们存储到字节数组 b中 。
备注:close⽅法,当完成流的操作时,必须调⽤此⽅法,释放系统资源
FileInputStream类
java.io.FileInputStream 类是⽂件输⼊流,从⽂件中读取字节
构造函数
FileInputStream(File file) : 通过打开与实际⽂件的连接来创建⼀个 FileInputStream ,该⽂件由⽂件系统中的 File对象 fifile命名。
FileInputStream(String name) : 通过打开与实际⽂件的连接来创建⼀个 FileInputStream ,该⽂件由⽂件系统中的路径名 name命名。
当你创建⼀个流对象时,必须传⼊⼀个⽂件路径。该路径下,如果没有该⽂件,会抛出FileNotFoundException
public class InputStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos1 = new FileInputStream(file);
// 使⽤⽂件名称创建流对象
FileInputStream fos2 = new FileInputStream("C:/Users/lighter/Desktop/a.txt");
}
}
read()
读取字节: read (),每次可以读取⼀个字节的数据,提升为int类型,读取到⽂件末尾,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
int b;
//读取每一个字节数据,= -1 读完
while ((b = fis.read()) != -1){
System.out.println(b +">>"+(char) b);
}
//释放资源
fis.close();
}
}
//文件中内容:abcdefg
//输出:
97>>a
98>>b
99>>c
100>>d
101>>e
102>>f
103>>g
read(byte[] b)
使⽤字节数组读取: read(byte[] b) ,每次读取b的⻓度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回 -1 ,
public class InputStreamTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字节个数
int len;
//定义读取到的字节数组,作为装字节数据的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字节数组转化成字符串打印
System.out.println(len +">>"+new String(b));
}
fis.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>学
3>>习
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>klj
读取有效字节
错误数据 j ,是由于最后⼀次读取时,只读取2个字节kl ,数组中,上次读取的数据没有被完全替换,所以要通过 len ,获取有效的字节,
public class InputStreamTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//有效字节个数
int len;
//定义读取到的字节数组,作为装字节数据的容器
byte[] b = new byte[3];
while ((len = fis.read(b)) != -1){
//把字节数组转化成字符串打印,打印有效的字符串
System.out.println(len +">>"+new String(b,0,len));
}
fis.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好
3>>好
3>>学
3>>习
3>>天
3>>天
3>>向
3>>上
3>>hij
2>>kl
字符流
当使⽤字节流读取⽂本⽂件时,可能会有⼀个⼩问题。就是遇到中⽂字符时,可能不会显示完整的字符,那是因为⼀个中⽂字符可能占⽤多个字节存储。所以Java提供⼀些字符流类,以字符为单位读写数据,专⻔⽤于处理⽂本⽂件
字符输⼊流【Reader】
java.io.Reader 抽象类是表示⽤于读取字符流的所有类的超类,可以读取字节信息到内存中。它定义了字节输⼊流的基本共性功能⽅法。
public void close() :关闭此流并释放与此流相关联的任何系统资源。
public int read() : 从输⼊流读取⼀个字符。
public int read(char[] cbuf) : 从输⼊流中读取⼀些字符,并将它们存储到字符数组 cbuf中 。
FileReader类
构造函数
FileReader(File file) : 创建⼀个新的 FileReader ,给定要读取的File对象。
FileReader(String fileName) : 创建⼀个新的 FileReader ,给定要读取的⽂件的名称。
当你创建⼀个流对象时,必须传⼊⼀个⽂件路径。类似于FileInputStream 。
public class FileReaderTest {
public static void main(String[] args) {
try {
Test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test1() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr1 = new FileReader(file);
// 使⽤⽂件名称创建流对象
FileReader fr2 = new FileReader("C:/Users/lighter/Desktop/a.txt");
}
}
read()
读取字符: read ⽅法,每次可以读取⼀个字符的数据,提升为int类型,读取到⽂件末尾,返
回 -1 ,循环读取
public class FileReaderTest {
public static void main(String[] args) {
try {
Test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test2() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定义变量,保存数据
int b;
// 循环读取
while ((b = fr.read())!=-1) {
System.out.println((char)b);
}
// 关闭资源
fr.close();
}
}
//文件文本
//abcdefg
//好好学习天天向上hijkl
//输出
a
b
c
d
e
f
g
好
好
学
习
天
天
向
上
h
i
j
k
l
read(char[] cbuf)
使⽤字符数组读取: read(char[] cbuf) ,每次读取b的⻓度个字符到数组中,返回读取到的有
效字符个数,读取到末尾时,返回 -1
public class FileReaderTest {
public static void main(String[] args) {
try {
Test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test3() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定义变量,保存数据
int len;
char[] cbuf = new char[3];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf));
}
// 关闭资源
fr.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好好学
3>>习天天
3>>向上h
3>>ijk
1>>ljk
读取有效字符
public class FileReaderTest {
public static void main(String[] args) {
try {
Test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Test4() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileReader fr = new FileReader(file);
//定义变量,保存数据
int len;
char[] cbuf = new char[3];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(len +">>"+new String(cbuf,0,len));
}
// 关闭资源
fr.close();
}
}
//原文
//abcdefg
//好好学习天天向上hijkl
//输出
3>>abc
3>>def
3>>g
3>>好好学
3>>习天天
3>>向上h
3>>ijk
1>>l
字符输出流【Writer】
java.io.Writer 抽象类是表示⽤于写出字符流的所有类的超类,将指定的字符信息写出到⽬的地。它定义了字节输出流的基本共性功能⽅法。
public abstract void close() :关闭此输出流并释放与此流相关联的任何系统资源。
public abstract void flush() :刷新缓冲区,将缓冲区中的数据输出到⽬标⽂件中。
public void write(int b) :写出⼀个字符。
public void write(char[] cbuf) :将 b.length字符从指定的字符数组写出此输出流。
public abstract void write(char[] b, int off, int len) :从指定的字符数组写出 len字符,从偏移量 offff开始输出到此输出流。
public void write(String str) :写出⼀个字符串。
FileWriter类
FileWriter(File file) : 创建⼀个新的 FileWriter,给定要读取的File对象。
FileWriter(String fileName) : 创建⼀个新的 FileWriter,给定要读取的⽂件的名称。
构造函数
public class FileWriterTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileWriter fw1 = new FileWriter(file);
// 使⽤⽂件名称创建流对象
FileWriter fw2 = new FileWriter("C:/Users/lighter/Desktop/a.txt");
}
}
write(int b)
写出字符: write(int b) ⽅法,每次可以写出⼀个字符数据
public class FileWriterTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//写一个字符
fw.write(97);
//第二个字符
fw.write('a');
fw.write("好");
fw.write(30000);
fw.close();
}
}
//文件内容
aa好田
关闭与刷新
因为内置缓冲区的原因,如果不关闭输出流,⽆法写出字符到⽂件中。但是关闭的流对象,是⽆法继续写出数据的。如果我们既想写出数据,⼜想继续使⽤流,就需要 flush ⽅法了。
flush :刷新缓冲区,流对象可以继续使⽤。
close :关闭流,释放系统资源。关闭前会刷新缓冲区,流对象不可以继续使⽤。
public class FileWriterTest {
public static void main(String[] args) {
try {
test3();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
//写一个字符
fw.write(97);
//第二个字符
fw.write('a');
fw.flush();
fw.write("好");
fw.close();
fw.write(30000);
fw.close();
}
}
//文件内容
aa好
//输出
java.io.IOException: Stream closed
at sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:45)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:118)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:113)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:194)
at cn.gdmcmc.esi.IO.FileWriterTest.test3(FileWriterTest.java:32)
at cn.gdmcmc.esi.IO.FileWriterTest.main(FileWriterTest.java:16)
write(char[] cbuf)
public class FileWriterTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好学习,天天向上".toCharArray();
fw.write(chars);
fw.close();
}
}
//输出
好好学习,天天向上
write(char[] cbuf, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test5();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test5() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
char[] chars = "好好学习,天天向上".toCharArray();
fw.write(chars,2,3);
fw.close();
}
}
//输出
学习,
write(String str)
public class FileWriterTest {
public static void main(String[] args) {
try {
test6();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test6() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好学习,天天向上";
fw.write(str);
fw.close();
}
}
//输入
好好学习,天天向上
write(String str, int off, int len)
public class FileWriterTest {
public static void main(String[] args) {
try {
test7();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test7() throws Exception {
// 使⽤File对象创建流对象
File file = new File("C:/Users/lighter/Desktop/b.txt");
FileWriter fw = new FileWriter(file);
String str = "好好学习,天天向上";
fw.write(str,3,4);
fw.close();
}
}
//输出
习,天天
缓冲流
字节缓冲流
构造函数
public BufferedInputStream(InputStream in) :创建⼀个 新的缓冲输⼊流。
public BufferedOutputStream(OutputStream out) : 创建⼀个新的缓冲输出流。
public class BufferedTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
//创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//创建字节缓冲输入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
}
}
读写数据
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
//创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:/Users/lighter/Desktop/a.txt"));
//创建字节缓冲输入流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:/Users/lighter/Desktop/a.txt"));
int b ;
while ((b = bis.read()) != -1){
bos.write(b);
}
bis.close();
bos.close();
}
}
字符缓冲流
构造函数
public BufferedReader(Reader in) :创建⼀个 新的缓冲输⼊流。
public BufferedWriter(Writer out) : 创建⼀个新的缓冲输出流
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
//创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//创建字符缓冲输入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
}
}
特有⽅法
BufferedReader: public String readLine() : 读⼀⾏⽂字。
BufferedWriter: public void newLine() : 输出⼀个换⾏符,由系统属性定义符号
public class BufferedTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
//创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("C:/Users/lighter/Desktop/a.txt"));
//创建字符缓冲输入流
BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/lighter/Desktop/a.txt"));
String line = null;
int b ;
while((line = br.readLine()) != null){
/*while ((b = br.read()) != -1){
bw.write(b);
}*/
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
}
**备注:**缓冲流比字节输入流效率高很多;
转换流
字符编码:
计算机中储存的信息都是⽤⼆进制数表示的,⽽我们在屏幕上看到的数字、英⽂、标点符号、汉字等
字符是⼆进制数转换之后的结果。
按照某种规则,将字符存储到计算机中,称为编码 。
将存储在计算机中的⼆进制数按照某种规则解析显示出来,称为解码 。
字符编码 Character Encoding
字符编码 Character Encoding : 就是⼀套⾃然语⾔的字符与⼆进制数之间的对应规则。
编码表概述:
计算机存储字符时将字符查询码表,然后存储对应的⼆进制。
计算机取出字符时将⼆进制查询码表,然后转换成对应的字符显示。
ASCII:
* 美国码表,码表中只有英⽂⼤⼩写字⺟、数字、美式标点符号等。每个字符占⽤1个字节,所有字符映射的⼆进制都为正数,因此有128个字符映射关系。
GB2312:
* 兼容ASCII码表,并加⼊了中⽂字符,码表中英⽂⼤⼩写字⺟、数字、美式标点符号占⼀个字节,中⽂占两个字节,中⽂映射的⼆进制都是负数,因此有128× 128 = 16384个字符映射关系。
GBK/GB18030:
* 兼容GB2312码表,英⽂⼤⼩写字⺟、数字、美式标点符号,占⼀个字节。中⽂占两个字节,第⼀个字节为负数,第⼆个字节为正数和负数,因为有128× 256 = 32768个字符映射关系。
Unicode码表:
* 国际码表,包含各国⼤多数常⽤字符,每个字符都占2个字节,因此有65536个字符映射关系。Java语⾔使⽤的就是Unicode码表。
* Java中的char类型⽤的就是这个码表。char c = 'a';占两个字节。
UTF-8码表:
* 是基于Unicode码表的,但更智能,会根据字符的内容选择使⽤多个字节存储。英⽂占⼀个字节,中⽂占3个字节。
乱码的原因
* 因为⽂本在存储时使⽤的码表和读取时使⽤的码表不⼀致造成的。
InputStreamReader类
构造函数
InputStreamReader(InputStream in) : 创建⼀个使⽤默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName) : 创建⼀个指定字符集的字符流
public class switchTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//创建一个默认编码的转换字符输入流对象,utf-8
InputStreamReader isr = new InputStreamReader(fis);
//创建一个指定编码的转换字符输入流对象,gbk
InputStreamReader isr2 = new InputStreamReader(fis,"GBK");
}
}
读取数据
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fis = new FileInputStream(file);
//创建一个默认编码的转换输入流对象,utf-8
InputStreamReader isr = new InputStreamReader(fis,"gbk");
int b;
//对于gbk编码的文件输入
while ((b = isr.read()) != -1){
System.out.println((char)b);
}
isr.close();
}
}
OutputStreamWriter类
构造方法
OutputStreamWriter(OutputStream in) : 创建⼀个使⽤默认字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName) : 创建⼀个指定字符集的字符流。
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个默认编码的转换字符输出流对象,utf-8
OutputStreamWriter osw = new OutputStreamWriter(fos);
//创建一个指定编码的转换字符输出流对象,gbk
OutputStreamWriter osw2 = new OutputStreamWriter(fos,"gbk");
}
}
写出数据
public class switchTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个指定编码的转换字符输出流对象,gbk
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
//按照指定编码输出字符,一个汉字占2个字节
//utf-8,一个汉字占3个字节
osw.write("你好");
osw.close();
}
}
序列化
概述
对象序列化概念
将对象转换为字节并保持到⽂件中的过程。
对象反序列化概念
将保持在⽂件中的字节读取出来并转换为对象的过程。
序列化
java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到⽂件,实现对象的持久存储。
满足条件:
1.该类必须实现 java.io.Serializable 接⼝, Serializable 是⼀个标记接⼝,不实现此接⼝的类的对象在序列化过程中会抛出 NotSerializableException 。
构造函数
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个序列化输出对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
writeObject()
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student implements Serializable{
public String name;
public Integer age;
public void vivw(){
System.out.println(name + ">>>>" + age);
}
}
static void test2() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个序列化输出对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
Student s = new Student();
s.name = "张三";
s.age = 25;
oos.writeObject(s);
oos.close();
}
static void test1() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileOutputStream fos = new FileOutputStream(file);
//创建一个序列化输出对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
}
}
transient
transient 关键字作⽤
⽤来修饰成员变量的,能够保证该成员变量的值不会被序列化到⽂件中
transient 使⽤格式
修饰符 transient 数据类型 变量名
反序列化
ObjectInputStream反序列化流,将之前使⽤ObjectOutputStream序列化的原始数据恢复为对象。
构造方法
public ObjectInputStream(InputStream in) : 创建⼀个指定InputStream的ObjectInputStream。
public class SerializableTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test3() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//创建一个序列化输出对象
ObjectInputStream ois = new ObjectInputStream(fos);
}
}
readObject ()
public class SerializableTest {
public static void main(String[] args) {
try {
test4();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test4() throws Exception {
File file = new File("C:/Users/lighter/Desktop/a.txt");
FileInputStream fos = new FileInputStream(file);
//创建一个序列化输出对象
ObjectInputStream ois = new ObjectInputStream(fos);
Student s = (Student)ois.readObject();
System.out.println(s.name);
System.out.println(s.age);
s.vivw();
ois.close();
}
}
打印流
平时我们在控制台打印输出,是调⽤ print ⽅法和 println ⽅法完成的,这两个⽅法都来⾃于 java.io.PrintStream 类,该类能够⽅便地打印各种数据类型的值,是⼀种便捷的输出⽅式。
PrintStream类
构造函数
public PrintStream(String fileName) : 使⽤指定的⽂件名创建⼀个新的打印流。
public class PrintStreamTest {
public static void main(String[] args) {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test1() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
}
}
输出
public class PrintStreamTest {
public static void main(String[] args) {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
static void test2() throws Exception {
PrintStream ps = new PrintStream("C:/Users/lighter/Desktop/a.txt");
// 设置系统的打印流流向,输出到a.txt
System.setOut(ps);
//调用系统的打印流,再a.txt输出97
System.out.println(97);
}
}
关系图
源码
FileInputStream
public class FileInputStream extends InputStream{
private final FileDescriptor fd;
private final String path;
private FileChannel channel = null;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//构造函数
//用文件名创建字节输入流
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
//用File创建字节输入流,主要创建函数
public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
//创建一个安全管理器
//在我们要测试一个未知的可能有风险的程序时需要开启安全管理器,这样保证这个未知程序启动的时候不会损害到我们的系统
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
//文件描述符
fd = new FileDescriptor();
fd.attach(this);
path = name;
open(name);
}
//native 方法
private native void open0(String name) throws FileNotFoundException;
private void open(String name) throws FileNotFoundException {
open0(name);
}
//读取
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException;
private native int readBytes(byte b[], int off, int len) throws IOException;
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileDescriptor
public final class FileDescriptor {
private int fd;
private long handle;
private Closeable parent;
private List<Closeable> otherParents;
private boolean closed;
/**
* Constructs an (invalid) FileDescriptor
* object.
*/
public /**/ FileDescriptor() {
fd = -1;
handle = -1;
}
synchronized void attach(Closeable c) {
if (parent == null) {
// first caller gets to do this
parent = c;
} else if (otherParents == null) {
otherParents = new ArrayList<>();
otherParents.add(parent);
otherParents.add(c);
} else {
otherParents.add(c);
}
}
}
FileOutputStream
public class FileOutputStream extends OutputStream{
private final FileDescriptor fd;
private final boolean append;
private FileChannel channel;
private final String path;
private final Object closeLock = new Object();
private volatile boolean closed = false;
//文件名构造函数
public FileOutputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null, false);
}
//文件名构造函数,true
public FileOutputStream(String name, boolean append)
throws FileNotFoundException
{
this(name != null ? new File(name) : null, append);
}
public FileOutputStream(File file) throws FileNotFoundException {
this(file, false);
}
//都是用这个文件,boolean 来创建的
public FileOutputStream(File file, boolean append)
throws FileNotFoundException
{
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(name);
}
if (name == null) {
throw new NullPointerException();
}
if (file.isInvalid()) {
throw new FileNotFoundException("Invalid file path");
}
this.fd = new FileDescriptor();
fd.attach(this);
this.append = append;
this.path = name;
open(name, append);
}
private native void open0(String name, boolean append)
throws FileNotFoundException;
private void open(String name, boolean append)
throws FileNotFoundException {
open0(name, append);
}
private native void write(int b, boolean append) throws IOException;
public void write(int b) throws IOException {
write(b, append);
}
private native void writeBytes(byte b[], int off, int len, boolean append)
throws IOException;
public void write(byte b[]) throws IOException {
writeBytes(b, 0, b.length, append);
}
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, append);
}
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
private native void close0() throws IOException;
}
FileReader
public class FileReader extends InputStreamReader {
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}
}
InputStreamReader
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
//调用的是StreamDecoder.read()方法
public int read() throws IOException {
return sd.read();
/*
StreamDecoder.class
public int read() throws IOException {
return this.read0();
}
private int read0() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.haveLeftoverChar) {
this.haveLeftoverChar = false;
return this.leftoverChar;
} else {
char[] var2 = new char[2];
int var3 = this.read(var2, 0, 2);
switch(var3) {
case -1:
return -1;
case 0:
default:
assert false : var3;
return -1;
case 2:
this.leftoverChar = var2[1];
this.haveLeftoverChar = true;
case 1:
return var2[0];
}
}
}
}
*/
}
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
public boolean ready() throws IOException {
return sd.ready();
}
public void close() throws IOException {
sd.close();
}
}
Reader
public abstract class Reader implements Readable, Closeable {
protected Object lock;
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
FileWriter
public class FileWriter extends OutputStreamWriter {
public FileWriter(String fileName) throws IOException {
super(new FileOutputStream(fileName));
}
public FileWriter(String fileName, boolean append) throws IOException {
super(new FileOutputStream(fileName, append));
}
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}
public FileWriter(File file, boolean append) throws IOException {
super(new FileOutputStream(file, append));
}
}
OutputStreamWriter
public class OutputStreamWriter extends Writer {
private final StreamEncoder se;
public OutputStreamWriter(OutputStream out) {
super(out);
try {
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
public void write(int c) throws IOException {
se.write(c);
/*StreamEncoder.class
public void write(int var1) throws IOException {
char[] var2 = new char[]{(char)var1};
this.write((char[])var2, 0, 1);
}
public void write(char[] var1, int var2, int var3) throws IOException {
Object var4 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
if (var2 >= 0 && var2 <= var1.length && var3 >= 0 && var2 + var3 <= var1.length && var2 + var3 >= 0) {
if (var3 != 0) {
this.implWrite(var1, var2, var3);
}
} else {
throw new IndexOutOfBoundsException();
}
}
}
*/
}
public void write(char cbuf[], int off, int len) throws IOException {
se.write(cbuf, off, len);
}
public void write(String str, int off, int len) throws IOException {
se.write(str, off, len);
}
public void flush() throws IOException {
se.flush();
/* StreamEncoder.class
public void flush() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
this.ensureOpen();
this.implFlush();
}
}
*/
}
public void close() throws IOException {
se.close();
/* StreamEncoder.class
public void close() throws IOException {
Object var1 = this.lock;
synchronized(this.lock) {
if (this.isOpen) {
this.implClose();
this.isOpen = false;
}
}
}
*/
}
}
Writer
public abstract class Writer implements Appendable, Closeable, Flushable {
private char[] writeBuffer;
private static final int WRITE_BUFFER_SIZE = 1024;
protected Object lock;
protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}
拓展
字符流和字节流的区别
字符流操作文件先经过缓冲区(内存)然后再通过缓冲区再操作文件
字节流操作文件不会经过缓冲区(内存直接操作文件本身)
缓冲区的作用
缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就显著提升了性能
对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作
字符流和字节流的选择
**选择字节流:**大多数时候 IO 操作都是直接操作磁盘文件,所以这些流在传输时都是以字节的方式进行的(图片等都是按字节存储的)
**选择字符流:**通过 IO 在内存中频繁处理字符串的情况使用字符流会好些,因为字符流具备缓冲区,提高了性能
序列化及实现
序列化就是一种用来处理对象流的机制,将对象的内容进行流化。可以对流化后的对象进行读写操作,可以将流化后的对象传输于网络之间。序列化是为了解决在对象流读写操作时所引发的问题
将需要被序列化的类实现Serialize接口,没有需要实现的方法,此接口只是为了标注对象可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,再使用ObjectOutputStream对象的write(Object obj)方法就可以将参数obj的对象写出
PrintStream/BufferedWriter/PrintWriter
PrintStream类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成PrintStream后进行输出。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;
BufferedWriter类将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须通过调用flush方法才能将其刷出去。并且BufferedWriter只能对字符流进行操作。
PrintWriter类的println方法自动添加换行,不会抛异常,若关心异常,需要调用checkError方法看是否有异常发生,PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush)
节点流/处理流定义及作用
节点流: 直接与数据源相连,用于输入或者输出(字节流)
**处理流:**在节点流的基础上对之进行加工,进行一些功能的扩展; 处理流的构造器必须要传入节点流的子类(字节缓冲流)
流的关闭及位置处理
流一旦打开就必须关闭,使用close方法;放入finally语句块中(finally 语句一定会执行);多个流互相调用只关闭最外层的流