目录
IO流概述:
lI表示intput,把硬盘文件中的数据读入到内存的过程,称之输入,负责读。
lO表示output,把内存中的数据写出到硬盘文件的过程,称之输出,负责写。
IO流的分类:
流的四大分类:
字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流称为字节输入流。
字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流称为字节输出流。
字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流称为字符输入流。
字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流称为字符输出流。
IO流体系:
字节流InputStream 、OutputStream和字符流Reader、Writer均是抽象类,不能创建实例对象,要通过多态创建起子类对象。
四个基础流
下面学习FileInputStream、FileOutputStream、Filereader、FileWriter四个基础流的使用,其余高级流均是基于基础流,用法差不多。
FileInputStream:文件字节输入流
作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中去。
(可以操作所有类型的文件)
构造器:
public FileInputStream(File file):创建字节输入流管道与源文件对象接通
public FileInputStream(String pathname):创建字节输入流管道与源文件路径接通
方法:
public int read():每次读取一个字节返回,如果字节已经没有可读的返回-1
public int read(byte[] buffer):每次读取一个字节数组返回,如果字节已经没有可读的返回
下面以代码形式展示使用以及读取方法:
步骤:
1、创建一个文件字节输入流管道与源文件接通 2、读取字节(3种方式) 3、关闭流资源
读取方式1:每次读取一个字节(读取中文会乱码)
public static void main(String[] args) {
//1、创建一个文件字节输入流管道与源文件接通
InputStream is = null;
try {
is = new FileInputStream("day11/src/data.txt");
//2、使用循环读取字节返回
int num;
while((num = is.read()) != -1){
System.out.print((char)num);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
//3、关闭流
if(is != null){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
读取方式2:每次读取一个字节数组(性能比方式1高一些,但读取中文也可能乱码)
//定义一个字节数组,用于读取字节数组
byte[] bytes = new byte[3];//此位置的3可随意填写每次想读取的字节数(此方式读中文可能出现乱码)
int len;//记录每次读取的字节数
while((len = is.read(bytes)) != -1){
//读取多少倒出多少
System.out.print(new String(bytes, 0, len));
}
读取方式3:一次性读取全部字节,避免乱码(但如果文件过大,定义的字节数组可能引起内存溢出)
//定义一个字节数组与文件大小一样大
//方式1:自己写
byte[] bytes = new byte[(int)f.length()];
is.read(bytes);
System.out.println(new String(bytes));
//方式2:jdk9开始提供
byte[] bytes = is.readAllBytes();
System.out.println(new String(bytes));
FileOutputStream:文件字节输出流
文件字节输出流:FileOutputStream
作用:以内存为基准,把内存中的数据以字节的形式写出到磁盘文件中去的流。
(可以操作所有类型的文件)构造器:
public FileOutputStream(File file):创建字节输出流管道与源文件对象接通
public FileOutputStream(File file,boolean append):创建字节输出流管道与源文件对象接通,可追加数据
public FileOutputStream(String filepath):创建字节输出流管道与源文件路径接通
public FileOutputStream(String filepath,boolean append):创建字节输出流管道与源文件路径接通,可追加数据
方法:
public void write(int a):写一个字节出去
public void write(byte[] buffer):写一个字节数组出去
public void write(byte[] buffer , int pos , int len):写一个字节数组的一部分出去。
流的关闭与刷新:
flush():刷新流,还可以继续写数据
close():关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
1、public void write(int a):写一个字节出去
os.write('1');
os.write('a');
os.write(97);
// os.write('你');(写中文字符会乱码)
2、public void write(byte[] buffer):写一个字节数组出去
byte[] bytes1 = {'a', 'b', 98, 99};
os.write(bytes1);
byte[] bytes2 = "你我他她".getBytes();(可以用此方式写中文(字符转成字节(编码)))
os.write(bytes2);
3、public void write(byte[] buffer , int pos , int len):写一个字节数组的一部分出去。
byte[] bytes3 = {'a', 'b', 98, 99};
os.write(bytes3, 0, 3);
下面以代码形式展示使用以及写入方法:
public static void main(String[] args) throws Exception {
//创建一个文件字节输出流管道与目标文件接通
// OutputStream os = new FileOutputStream("day11/src/outdata1.txt");//先清空原有数据,再写入数据
OutputStream os = new FileOutputStream("day11/src/outdata1.txt", true);//追加数据
//写数据出去
// public void write(int a):写一个字节出去
os.write('1');
os.write('a');
os.write(97);
// os.write('你');
os.write("\r\n".getBytes());//换行
// public void write(byte[] buffer):写一个字节数组出去
byte[] bytes1 = {'a', 'b', 98, 99};
os.write(bytes1);
os.write("\r\n".getBytes());//换行
byte[] bytes2 = "你我他她".getBytes();
os.write(bytes2);
os.write("\r\n".getBytes());//换行
//public void write(byte[] buffer , int pos , int len):写一个字节数组的一部分出去。
byte[] bytes3 = {'a', 'b', 98, 99};
os.write(bytes3, 0, 3);
os.write("\r\n".getBytes());//换行
// os.flush();//刷新流,还可以继续写数据
os.close();//关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据
}
两个基础的字节流虽然可以操作各种类型的文件(如视频、音频、图片、文本文件等),但是操作纯文本文件可能会有乱码问题。推荐使用字符流操作纯文本文件,字符流只能操作纯文本文件,下面学习两个基础字符流。
FileReader:文件字符输入流
文件字符输入流:FileReader
作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。构造器:
public FileReader(File file):创建字符输入流管道与源文件对象接通
public FileReader(String pathname):创建字符输入流管道与源文件路径接通方法:
public int read():每次读取一个字符返回,如果字符已经没有可读的返回-1
public int read(char[] buffer):每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回-1
下面以代码形式展示使用以及读取方法:
1、 public int read():每次读取一个字符(读取中文不会乱码,但效率有些慢)
public static void main(String[] args) throws Exception {
//创建一个字符输入流管道与源文件接通
Reader r = new FileReader("day11/src/data3.txt");
//读取一个字符
//使用循环
int code;
while((code = r.read()) != -1){
System.out.print((char)code);
}
r.close();
}
2、每次读取一个字符数组(这是仅使用基础流读取纯文本文件最好的方法,如果想要效率更好可以使用高级流包裹基础流)
public static void main(String[] args) throws Exception {
//创建一个字符输入流管道与源文件接通
Reader r = new FileReader("day11/src/data3.txt");
//读取一个字符数组
char[] chars = new char[1024];
//使用循环
int len;
while((len = r.read(chars)) != -1){
System.out.print(new String(chars, 0, len));
}
r.close();
}
FileWriter:文件字符输出流
文件字符输出流:FileWriter
作用:以内存为基准,把内存中的数据以字符的形式写出到磁盘文件中去的流。构造器:
public FileWriter(File file):创建字符输出流管道与源文件对象接通
public FileWriter(File file,boolean append):创建字符输出流管道与源文件对象接通,可追加数据
public FileWriter(String filepath):创建字符输出流管道与源文件路径接通
public FileWriter(String filepath,boolean append):创建字符输出流管道与源文件路径接通,可追加数据方法:
void write(int c):写一个字符
void write(char[] cbuf):写入一个字符数组
void write(char[] cbuf, int off, int len):写入字符数组的一部分
void write(String str):写一个字符串
void write(String str, int off, int len):写一个字符串的一部分
下面以代码形式展示使用以及读取方法:
1、void write(int c):写一个字符
w.write('1');
w.write(98);
w.write('a');
w.write('郝');//字符流可以写中文字符
2、void write(String str):写一个字符串 (这是一个很好的写文本的方式)
w.write("你我他abc");
3、void write(char[] cbuf):写入一个字符数组(没必要,直接写一个字符串就挺好)
char[] chars = "我是好人".toCharArray();
w.write(chars);
4、void write(String str, int off, int len):写一个字符串的一部分
w.write("一二三四五", 0 ,4);
5、void write(char[] cbuf, int off, int len):写入字符数组的一部分
w.write(chars, 0, 3);
public static void main(String[] args) throws IOException {
// Writer w = new FileWriter("day11/src/outdata2txt");先清空原有数据,再写入数据
Writer w = new FileWriter("day11/src/outdata2txt", true);
// void write(int c):写一个字符
w.write('1');
w.write(98);
w.write('a');
w.write('郝');//字符流可以写中文字符
w.write("\r\n");//换行
// void write(String str):写一个字符串
w.write("你我他abc");
w.write("\r\n");//换行
// void write(char[] cbuf):写入一个字符数组
char[] chars = "我是好人".toCharArray();
w.write(chars);
w.write("\r\n");//换行
//void write(String str, int off, int len):写一个字符串的一部分
w.write("一二三四五", 0 ,4);
w.write("\r\n");//换行
// void write(char[] cbuf, int off, int len):写入字符数组的一部分
w.write(chars, 0, 3);
w.write("\r\n");//换行
w.close();
}
字节流、字符流的使用场景总结
字节流适合做一切文件数据的拷贝(音视频,文本) 字节流不适合读取中文内容输出
字符流适合做文本文件的操作(读,写)
补充字符集知识
常见字符集底层字符的编码是什么样的?
英文和数字等在任何国家的字符集中都占1个字节
GBK字符中一个中文字符占2个字节
UTF-8编码中一个中文1般占3个字节
编码前的字符集和解码时的字符集有什么要求?
必须一致,否则会出现字符乱码
英文和数字不会乱码
编码:
byte[] getBytes():使用平台的默认字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
byte[] getBytes(String charsetName):使用指定的字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
解码:
String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的 String
String(byte[] bytes, String charsetName):通过指定的字符集解码指定的字节数组来构造新的 String
代码展示:
1、编码,把文字转换成字节(使用指定的编码)
String str = "abc我你他她";
byte[] bytes = str.getBytes();//以当前代码默认字符集进行编码
byte[] bytes = str.getBytes("GBK");//以指定字符集进行编码
2、解码:把字节转换成对应的中文形式(编码前和编码后的字符集必须一致,否则乱码)
String s = new String(bytes);//以当前代码默认字符集进行解码
String s = new String(bytes ,"GBK");//以指定字符集进行解码