文章目录
IO流
IO流概述:
-
将文件从C盘剪切到D盘这种操作,可以将这种数据传输操作,看作一种数据的流动,
按流动的方向分为:输入Input和输出Output,对于D盘就是输入,对于C盘就是输出 -
java中的IO操作主要是指的是 java.io包下的一些常用类的使用,通过这些常用类对数据的读取(输入Input)和 写出(输出Output)
-
输入就是文件中的数据输入到程序中,输出就是程序中的数据输出到文本中
IO流的分类:
- 按照流的方向来分,可以分为:输入流和输出流
- 按照流动的数据类型来分,可以分为:字节流和字符流
字节流:
- 输入流: InputStream
- 输出流: OutputStream
字符流:
- 输入流: Reader
- 输出流:Writer
OutputStream
此类定义:
-
public abstract class OutputStream extends Object implements Closeable, Flushable
-
此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将它们发送到某个接收器。
需要定义
OutputStream
的子类的应用程序必须始终至少提供一个写入一个输出字节的方法。
方法:
write(int b)此方法 只能写入 int 的低八位(最后的8个bit)
注意: 使用流的时候一定要 close!
FileOutputStream
-
public class FileOutputStream extends OutputStream
-
文件输出流是用于将数据写入
File
或FileDescriptor
的输出流。
构造方法:
boolean append 意思是 是否继续追加(在之前的文件后面接着写还是删除内容后再写)。
方法与Output Stream方法一样。
demo:
public class OutputStreamDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("e:/demo/a.txt", true);
byte[] bytes = {65,66,67,68,69};
String str = "hello,IO";
fos.write(bytes);
fos.write(str.getBytes(StandardCharsets.UTF_8) , 1,3);
fos.close();
}
}
结果:
InputStream
定义:
-
public abstract class InputStream extends Object implements Closeable
-
此抽象类是表示输入字节流的所有类的超类(顶级父类)
常用方法:如下
close
void close() ; ——关闭流
read
public abstract int read() throws IOException
描述:从输入流中读取下一个数据字节。 值字节返回int ,范围为0至255 。 如果由于到达流末尾而没有可用字节,则返回值-1 。
结果:数据的下一个字节,如果到达流的末尾, -1 。
public int read(byte[] b) throws IOException
描述:从输入流中读取一些字节数并将它们存储到缓冲区数组b 。 实际读取的字节数以整数形式返回。
如果b的长度为零,则不读取任何字节,并返回0 ; 否则,尝试读取至少一个字节。 如果由于流位于文件末尾而没有可用字节,则返回值-1 ; 否则,至少读取一个字节并存储到b 。
读取的第一个字节存储在元素b[0] ,下一个字节存入b[1] ,依此类推。 读取的字节数最多等于b的长度。 设k为实际读取的字节数; 这些字节将存储在元素b[0]到b[ k -1] ,使元素b[ k ]到b[b.length-1]不受影响。
结果:读入缓冲区的总字节数,如果由于已到达流末尾而没有更多数据, -1
public int read(byte[] b, int off, int len) throws IOException
b - 读取数据的缓冲区。
off - 数据写入的数组 b中的起始偏移量。
len - 要读取的最大字节数。
效果与 int read(byte[] b) 一样
子类FileInputStream
read读取:
public class InputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("e://demo//a.txt");
byte b = 0;
while(true) {
b = (byte) fis.read();
if (b == -1) break;
System.out.println((char) b);
}
fis.close();
}
}
结果:
A
B
C
D
E
e
l
l
read(byte[] b) 读取数据
public class InputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("e://demo//a.txt");
// 文件内容:abcdefghigklmnopqrstuvwxyz
byte[] b = new byte[10];
fis.read(b); // 每次读十个
System.out.println(new String(b)); //abcdefghig
fis.read(b); // 每次读十个
System.out.println(new String(b)); //klmnopqrst
fis.read(b); // 每次读十个
System.out.println(new String(b)); //uvwxyzqrst
fis.close();
}
}
读取出现问题!!! 原因是最后只有六个字母 只是覆盖了byte[]前六位 后面四位没有被覆盖,出现了现象!
解决办法:
public class InputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("e://demo//a.txt");
// 文件内容:abcdefghigklmnopqrstuvwxyz
byte[] b = new byte[10];
int len = fis.read(b);// 每次读十个
System.out.println(new String(b,0,len)); //abcdefghig
len = fis.read(b); // 每次读十个
System.out.println(new String(b,0,len)); //klmnopqrst
len = fis.read(b); // 每次读6个
System.out.println(new String(b,0,len)); //uvwxyz
len = fis.read(b); // len = -1
fis.close();
}
}
用字节流读取文字的时候会出现乱码问题
原因: 用字节流读取文字时,因为汉字的编码规则 不知道使用几个字节编成一个汉字,所有用byte[10] 读取的时候会出现这样的 只读取到 汉字的一半 然后会出现乱码 解决办法:使用Reader流读取!
Writer
该类是字符输入流的顶级父类,是个抽象类
定义:
-
public abstract class Writer extends Object implements Appendable, Closeable, Flushable
子类:
已知直接子类:
BufferedWriter , CharArrayWriter , FilterWriter , OutputStreamWriter , PipedWriter , PrintWriter , StringWriter
常用方法:
变量和类型 | 方法 | 描述 |
---|---|---|
Writer | append(char c) | 将指定的字符追加到此writer。 |
Writer | append(CharSequence csq) | 将指定的字符序列追加到此writer。 |
Writer | append(CharSequence csq, int start, int end) | 将指定字符序列的子序列追加到此writer。 |
abstract void | close() | 关闭流,先冲洗它。 |
abstract void | flush() | 刷新流。因为有缓存,所以要刷新。 |
void | write(char[] cbuf) | 写一个字符数组。 |
void | write(String str) | 写一个字符串 |
FileWriter子类
定义:
-
public class FileWriter extends OutputStreamWriter
该类继承了OutputStreamWriter
构造方法:
构造器 | 描述 |
---|---|
FileWriter(File file) | 给 File 写一个 FileWriter ,使用平台的 [default charset] (默认字符集) |
FileWriter(File file, boolean append) | 在给出要写入的 FileWriter 下构造 File ,并使用平台的 [default charset构造]一个布尔值,指示是否附加写入的数据。 |
FileWriter(File file, Charset charset, boolean append) | 构造FileWriter 给出File 写入,charset和一个布尔值,指示是否附加写入的数据。 |
demo:
public class Write {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("e://demo//a.txt");
char[] b = new char[10];
fw.write("锄禾日当午,汗滴禾下土!");
fw.append("谁知盘中餐,").append("粒粒皆辛苦!");
fw.close();
}
}
Reader
定义:
-
public abstract class Reader extends Object implements Readable, Closeable
-
用于读取字符流的抽象类,字符流的顶级父类
常用方法:
变量和类型 | 方法 | 描述 |
---|---|---|
abstract void | close() | 关闭流并释放与其关联的所有系统资源。 |
int | read() | 读一个字符。读取不到返回-1 |
int | read(char[] cbuf) | 将字符读入数组,返回读取长度 |
FileReader
定义:
-
public class FileReader extends InputStreamReader
-
使用默认缓冲区大小从字符文件中读取文本。继承了InputStreamReader
构造器:
demo:
public class Reader {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("e://demo//a.txt");
char[] chars = new char[10];
while(true){
int len = fr.read(chars);
if (len == -1)
break;
//System.out.println(new String(chars));这句输出有问题
System.out.println(new String(chars,0,len));
}
fr.close();
}
}
运行结果:
锄禾日当午,汗滴禾下
土!谁知盘中餐,粒粒
皆辛苦!
Flush刷新管道
一般使用字符流读取内容时,将一个个字符存储到缓存区 ,所以一般要刷新flush
将缓冲区的内容写入文件。
使用close方法也能刷新缓冲区。
字节流 "装饰"为 字符流
字节流转换成字符流 --> 使用了装饰者模式
使用 InputStreamReader构造方法进行转换
参数1 : 要转换的字节流
参数2 : 指定编码名称
demo:
public class Reader {
public static void main(String[] args) throws IOException {
// 定义个 字节流
FileInputStream fis = new FileInputStream("e://demo//a.txt");
// 将字节流转换成字符流
InputStreamReader fr = new InputStreamReader(fis);
char[] chars = new char[10];
while(true){
int len = fr.read(chars);
if (len == -1)
break;
System.out.println(new String(chars,0,len));
}
fr.close();
}
}
PrintStream
定义:
-
public class PrintStream extends FilterOutputStream implements Appendable, Closeable
-
PrintStream
向另一个输出流添加功能,即能够方便地打印各种数据值的表示。 -
与其他输出流不同,PrintStream永远不会抛出IOException异常;相反,异常情况仅设置可通过
checkError
方法测试的内部标志 -
还可以指定是否自动flush
方法:该类方法与Out的方法几乎一样
demo:
public static void main(String[] args) throws IOException {
// 字节打印流
PrintStream ps = new PrintStream("e://demo//a.txt");
ps.println("11111");
ps.println("22222");
ps.println("33333");
ps.println("44444");
ps.println("55555");
ps.flush();
ps.close();
// 字符打印流
PrintWriter pw = new PrintWriter("e://demo//a.txt");
pw.println("pw11111");
pw.println("pw22222");
pw.println("pw33333");
pw.println("pw44444");
pw.println("pw55555");
pw.flush();
pw.close();
}
BufferedReader
缓存读取流,将字符输入流 转换为带有缓存 可以一次读取一行的缓存字符读取流
新增方法:
public String readLine() throws IOException
描述: 读一行文字。 一行被认为是由换行符('\ n'),回车符('\ r'),回车符后紧跟换行符或到达文件结尾的任何一个终止(EOF)。
结果: 包含行内容的字符串,不包括任何行终止字符;如果在未读取任何字符的情况下到达流末尾,则返回null
demo:
public static void main(String[] args) throws IOException {
// 字符输出流
FileReader fr = new FileReader("e://demo//a.txt");
// 转换成bufferedReader
BufferedReader bfd = new BufferedReader(fr);
String str ;
while( (str = bfd.readLine()) != null){
System.out.println(str);
}
fr.close();
}
收集异常日志
可以利用IO流将错误异常信息写入文件,可以已日期创建文件,将每天的异常加入到文件中
demo:
public static void main(String[] args) throws IOException {
String str = null;
// 创建printWriter流
PrintWriter pw = new PrintWriter("e://demo//bug.txt");
try{
// 这句代码 会产生空指针异常
str.equals("hello");
} catch (Exception e){
//加入时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm ss");
String format = sdf.format(new Date());
pw.println(format);
// 将异常写入文件
e.printStackTrace(pw);
pw.flush();
}
}
运行结果:
properties
定义:
-
public class Properties extends Hashtable<Object,Object>
-
继承 Hashtable
-
Properties
类表示一组持久的属性。Properties
可以保存到流中或从流中加载。 属性列表中的每个键及其对应的值都是一个字符串。
存数据demo:
public static void main(String[] args) throws IOException {
Properties ppt = new Properties();
ppt.put("name","金苹果");
ppt.put("info","讲述了苹果种植的过程");
// 创建字符流
FileWriter fw = new FileWriter("e://demo//info.properties");
ppt.store(fw,"存储的图书");
fw.close();
}
结果:
取数据demo:
public static void main(String[] args) throws IOException {
/* Properties ppt = new Properties();
ppt.put("name","金苹果");
ppt.put("info","讲述了苹果种植的过程");
// 创建字符流
FileWriter fw = new FileWriter("e://demo//info.properties");
ppt.store(fw,"存储的图书");
fw.close();*/
Properties ppt = new Properties();
// 创建 字符输入流
FileReader fr = new FileReader("e://demo//info.properties");
ppt.load(fr);
String name = ppt.getProperty("name");
String info = ppt.getProperty("info");
System.out.println(name);
System.out.println(info);
}
结果:
金苹果
讲述了苹果种植的过程
序列化 与 反序列化
序列化:将程序中的对象 存储到 文件中的过程
反序列化: 将文件的内容 转化为 程序中的对象 的过程
序列化:
java官方考虑到有些类不想被序列化,所以就加了个标识 需要被序列化的类继承Serializable接口 (该接口没有任何方法)
对象的属性也必须全部继承serializable接口。
demo:
public static void main(String[] args) throws IOException {
//序列化:
Book book = new Book("java","从入门到入土");
// 字节输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e://demo//a.text"));
oos.writeObject(book);
oos.close();
// 反序列化
}
static class Book implements Serializable{
private String name;
private String info;
public Book() {
}
public Book(String name, String info) {
this.name = name;
this.info = info;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", info='" + info + '\'' +
'}';
}
}
结果:
反序列化:
demo:
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e://demo//a.text"));
Book book = (Book) ois.readObject();
System.out.println(book);
}
static class Book implements Serializable{
private String name;
private String info;
public Book() {
}
public Book(String name, String info) {
this.name = name;
this.info = info;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", info='" + info + '\'' +
'}';
}
}
运行结果:
Book{name='java', info='从入门到入土'}
try-with-resources
在jdk1.7之前,当我们对一些流进行关闭时进行的处理:
public static void main(String[] args) {
FileReader fr = null ;
try{
fr = new FileReader("e://demo//a.text");
// 读取一个字符操作
int ch = fr.read();
System.out.println((char) ch);
} catch (IOException e){
e.printStackTrace();
} finally {
// 关闭流 当关闭流放入try里面时 当读取字符出错时,fr.close() 就会执行不了
// 只能放这里
// 放到这里又要处理异常
try{
fr.close();
} catch (Exception e){
// 当 第10行代码 fr 没有被赋值成功 可能还会报 NullPointException
// 只能用 放大到 Exception 处理
e.printStackTrace();
}
}
}
在jdk1.7时,使用如下try() 括号里面实现资源声明时 必须要实现 因为close方法必须会被自动调用
Closeable 或 AutoCloseable 这两个接口
demo:
public static void main(String[] args) {
try(FileReader fr = new FileReader("e://demo//a.txt");){
// 读取一个字符操作
int ch = fr.read();
System.out.println((char) ch);
} catch (IOException e){
e.printStackTrace();
}
}
这里也有不好的地方,当我 fr 对象 还需要使用 ,不想再这就被关闭,怎么办?
这时 jdk9 版本进行了优化
FileReader fr = new FileReader("e://demo//a.txt");
PrintWriter fw = new PrintWriter("e://demo//a.txt");
try(fr,fw){
// 读取一个字符操作
int ch = fr.read();
System.out.println((char) ch);
} catch (IOException e){
e.printStackTrace();
}