在这里,我自己总结一下我学习Java的I/O的一些总结
首先,介绍一下I/O流的概念:
IO流用来处理设备之间的数据传输
1. Java对数据的操作是通过流的方式
2. Java用于操作流的类都在IO包中
3. 流按流向分为两种:输入流,输出流。
4. 流按操作类型分为两种:
4.1.字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
4.2.字符流 : 字符流只能操作纯字符数据,比较方便。
1. Java对数据的操作是通过流的方式
2. Java用于操作流的类都在IO包中
3. 流按流向分为两种:输入流,输出流。
4. 流按操作类型分为两种:
4.1.字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
4.2.字符流 : 字符流只能操作纯字符数据,比较方便。
I/O流分为字符流和字节流
字节流的输入和输出:InputStream , OutputStream
字符流的输入和输出:Reader ,Writer
(PS:字符流不能用来复制文件,因为字符流每次读入都是一个字符,经过转码可能会出现乱码,因为一个字符等于两个字节,字符码只用来读文件或者写文件)
伪代码(复制文件)
Class{
FileInputStream fis = new InputStream("xxx.txt"); //读xxx.txt文件
FileOutputStream fos = new OutputStream("yyy.txt"); //写文件到yyy.txt文件中
int a=0;
while( (a=fis.read()!=-1) ){ //由于当读文件读到-1的时候就读完,每次赋值给a进行判断
fos.write(a);
}
fis.close();
fos.close();
那么一个字节为什么a要用int类型,返回一个int类型而不是byte类型呢?
答:因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上
24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型
那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上
24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型
以上是基本代码,最基础,但是效率很差,需要一个一个地区遍历,一个一个地去传入文件,所以可以优化,设置一个数组,先读取足够多的一组数据,然后再一次写到文件中去,这样的效率会加快,而数组的大小是有要求的,必须是1024的倍数。
伪代码:
FileInputStream fis = new FileInputStream("致青春.mp3");
FileOutputStream fos = new FileOutputStream("copy.mp3");
int len;
byte[] arr = new byte[1024 * 8]; //自定义字节数组
while((len = fis.read(arr)) != -1) {
//fos.write(arr);
fos.write(arr, 0, len); //写出字节数组写出有效个字节个数
}
fis.close();
fos.close();
那么每一次都设置一个数组做起来就会很麻烦,所以Java有BufferedInputStream和BufferedOutputStream方法来封装InputStream和OutputStream这两个输入输出方法,使得文件先读进缓冲区,然后在缓冲区读取足够多字节后再进入内存,然后进入写的缓冲区,一次性写进文件中。而BufferedInputStream内置了一个缓冲区,会一次性从文件中读取8192个字节,即是8*1024个字节,程序再次读文件时就不用再次去找文件了,直接从缓冲区中读取。BufferedOutputStream也是同样的道理,程序向流写出字节时,不会直接写进文件,而是先写到缓冲区,当缓冲区写满再一次性写到文件中。
以下是伪代码:
class{
FileInputStream fis = new FileInputStream("陀飞轮.mp3"); //创建文件输入流对象,关联致青春.mp3
BufferedInputStream bis = new BufferedInputStream(fis); //创建缓冲区对fis装饰
FileOutputStream fos = new FileOutputStream("copy.mp3"); //创建输出流对象,关联copy.mp3
BufferedOutputStream bos = new BufferedOutputStream(fos); //创建缓冲区对fos装饰
int b;
while((b = bis.read()) != -1) {
bos.write(b);
}
bis.close(); //只关装饰后的对象即可
bos.close();
}
刷新缓冲区的方法:
close()会直接刷新缓冲区再关闭输入输出流
fluse()会直接刷新缓冲区,但没有关闭输入输出流,还能继续输入和输出。
流的标准处理异常:
try(
FileInputStream fis = new FileInputStream("aaa.txt");
FileOutputStream fos = new FileOutputStream("bbb.txt");
MyClose mc = new MyClose();
){
int b;
while((b = fis.read()) != -1) {
fos.write(b);
}
}
华丽丽的分割线
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
以下是字符流的知识点:
字符流的输入输出流是Reader和Writer,同样以文件为例子
字符流读文件:
FileReader fr = new FileReader("aaa.txt"); //创建输入流对象,关联aaa.txt
int ch;
while((ch = fr.read()) != -1) { //将读到的字符赋值给ch
System.out.println((char)ch); //将读到的字符强转后打印
}
fr.close();
字符流也可以拷贝文本文件, 但不推荐使用. 因为读取时会把字节转为字符, 写出时还要把字符转回字节.
* 程序需要读取一段文本, 或者需要写出一段文本的时候可以使用字符流
* 读取的时候是按照字符的大小读取的,不会出现半个中文
* 写出的时候可以直接将字符串写出,不用转换为字节数组
所以字符流也不能能拷贝非纯文本的文件。
IO流的readLine()和newLine()方法。
BufferedReader的readLine()方法可以读取一行字符(不包含换行符号)
BufferedWriter的newLine()可以输出一个跨平台的换行符号"\r\n"
BufferedWriter的newLine()可以输出一个跨平台的换行符号"\r\n"
newLine()是换行
readLine()是读取一行数据
newLine()是换行后,就可以使用readLine()来一行行读取数据
代码:
BufferedReader br = new BufferedReader(new FileReader("aaa.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("bbb.txt"));
String line;
while((line = br.readLine()) != null) {
bw.write(line);
//bw.write("\r\n"); //只支持windows系统
bw.newLine(); //跨平台的
}
br.close();
bw.close();
IO流(LineNumberReader)
* LineNumberReader是BufferedReader的子类, 具有相同的功能, 并且可以统计行号
* 调用getLineNumber()方法可以获取当前行号
* 调用setLineNumber()方法可以设置当前行号
*
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
* LineNumberReader是BufferedReader的子类, 具有相同的功能, 并且可以统计行号
* 调用getLineNumber()方法可以获取当前行号
* 调用setLineNumber()方法可以设置当前行号
*
LineNumberReader lnr = new LineNumberReader(new FileReader("aaa.txt"));
String line;
lnr.setLineNumber(100); //设置行号
while((line = lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber() + ":" + line);//获取行号
}
lnr.close();
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
以下是序列流的个人理解:
序列流可以把多个字节输入流整合成一个, 从序列流中读取数据时, 将从被整合的第一个流开始读, 读完一个之后继续读第二个, 以此类推.
*SequenceInputStream(InputStream, InputStream)
FileInputStream fis1 = new FileInputStream("a.txt"); //创建输入流对象,关联a.txt
FileInputStream fis2 = new FileInputStream("b.txt"); //创建输入流对象,关联b.txt
SequenceInputStream sis = new SequenceInputStream(fis1, fis2); //将两个流整合成一个流
FileOutputStream fos = new FileOutputStream("c.txt"); //创建输出流对象,关联c.txt
int b;
while((b = sis.read()) != -1) { //用整合后的读
fos.write(b); //写到指定文件上
}
sis.close();
fos.close();
内存输出流(ByteArrayOutputStream)
FileInputStream fis = new FileInputStream("a.txt");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b;
while((b = fis.read()) != -1) {
baos.write(b);
}
//byte[] newArr = baos.toByteArray(); //将内存缓冲区中所有的字节存储在newArr中
//System.out.println(new String(newArr));
System.out.println(baos);
fis.close();
打印流
1.该流可以很方便的将对象的toString()结果输出, 并且自动加上换行, 而且可以使用自动刷出的模式
2.System.out就是一个PrintStream, 其默认向控制台输出信息
PrintStream ps = System.out;
ps.println(97); //其实底层用的是Integer.toString(x),将x转换为数字字符串打印
ps.println("xxx");
ps.println(new Person("张三", 23));
Person p = null;
ps.println(p); //如果是null,就返回null,如果不是null,就调用对象的toString()
使用方法:
PrintWriter pw = new PrintWriter(new FileOutputStream("g.txt"), true);
pw.write(97);
pw.print("大家好");
pw.println("你好"); //自动刷出,只针对的是println方法
pw.close();
IO流(标准输入输出流概述和输出语句)
1.什么是标准输入输出流(掌握)
System.in是InputStream, 标准输入流, 默认可以从键盘输入读取字节数据
System.out是PrintStream, 标准输出流, 默认可以向Console中输出字符和字节数据
2.修改标准输入输出流(了解)
修改输入流: System.setIn(InputStream)
修改输出流: System.setOut(PrintStream)
1.什么是标准输入输出流(掌握)
System.in是InputStream, 标准输入流, 默认可以从键盘输入读取字节数据
System.out是PrintStream, 标准输出流, 默认可以向Console中输出字符和字节数据
2.修改标准输入输出流(了解)
修改输入流: System.setIn(InputStream)
修改输出流: System.setOut(PrintStream)
System.setIn(new FileInputStream("a.txt")); //修改标准输入流
System.setOut(new PrintStream("b.txt")); //修改标准输出流
InputStream in = System.in; //获取标准输入流
PrintStream ps = System.out; //获取标准输出流
int b;
while((b = in.read()) != -1) { //从a.txt上读取数据
ps.write(b); //将数据写到b.txt上
}
in.close();
ps.close();