目录
二、IO流的java.io.FileOutputStream类(输出字节流)
三、io流的java.io.FileInputStream类(输入字节流)
五、io流的java.io.FileReader类(输入字符流)
一、IO流的概述:
可以将数据的传输看成一种流动,按照流动的方向可以分为输入Input和输出Output
Java的IO操作,一般指的是Java.IO包下的一些常用类的使用,通过这些常用类对数据进行读取(Input)和输出(Output)
按照流动方向可以分为:输入流和输出流。
按照流动的数据类型可以分为:字节流和字符流
字节流:
输出——OutputStream (顶级父类)
输入——InputStream (顶级父类)
字符流:
输出——Writer (顶级父类)
输入——Reader (顶级父类)
二、IO流的java.io.FileOutputStream类
(输出字节流)
* 每创建一个FileOutputStream的对象,就相当于开了一个流管道,就可以通过此对象向指定文件输出内容。
方法的实现——write(输入流)
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("d://b.txt");//创建一个对象
fos.write(65); //传入一个字节 65
byte [] bytes = {65,66,67,68}; //创建一个数组
fos.write(bytes); //传入数组bytes
byte [] bytes1 = "哈哈哈哈".getBytes(StandardCharsets.UTF_8); //传入字符数组
fos.write(bytes1);
fos.close(); //用完要关闭流!!很重要!!
System.out.println("创建完成");
}
执行结果
值得注意的是:每创建一个对象都会清空原本的文件然后重写,eg:
加上这段代码后:
FileOutputStream fos2 = new FileOutputStream("d://b.txt");
byte [] bytes2 = "继续写的".getBytes(StandardCharsets.UTF_8);
fos2.write(bytes2);
fos2.write(66);
fos2.close();
运行结果:
除非:在new对象时在路径后面加上,true
FileOutputStream fos2 = new FileOutputStream("d://b.txt",true);
byte [] bytes2 = "继续写的".getBytes(StandardCharsets.UTF_8);
fos2.write(bytes2);
fos2.write(66);
fos2.close();
运行结果:
写出数组中的一部分:
FileOutputStream fos = new FileOutputStream("D://c.txt");
byte [] bytes = {65,66,67,68,10};
fos.write(bytes,1,2); //传入数组bytes,从下标1开始,输入两个
fos.close();
运行结果:
三、io流的java.io.FileInputStream类(输入字节流)
InputStream是将文件内容读到程序中
例如:我们现在创建一个文件,路径为:d://c.txt 。内容如下!
现在我们实现一下将内容读到程序中的方法,来将此文件中的内容,读到程序中
此为以字节形式输出
FileInputStream fos = new FileInputStream("d://c.txt");//new一个输入流对象
/**
* 读取,以字节形式输出
*/
byte b = (byte) fos.read(); //因为是字节型,所以要强转
System.out.println((char)b); //再将字节强转成字符进行输出
fos.close();
注意:read读取,返回是int值,是从第几个字节读到第几个字节
运行结果:
此段代码为:每次读一个字节,循环输出!
fos.close();*/
/**
* 循环读取
*/
while (true){
byte b = (byte) fos.read(); //因为是字节型,所以要强转
if(b!=-1) { //因为读取不到的话会返回-1
System.out.print((char) b); //再将字节强转成字符进行输出
}else{
break;
}
}
fos.close();
结果:
但其实,我们通常用的输入都是用数组:
/**
* 读取,以数组形式输出
*/
byte[] bytes = new byte[10];
int len = fos.read(bytes);
System.out.println(new String(bytes,0,len));
len = fos.read(bytes);
System.out.println(new String(bytes,0,len));
len = fos.read(bytes);
System.out.println(new String(bytes,0,len));
fos.close();
运行结果:
这里有个知识点:我们如果不用len来限定输出的长度,那么输出的结果会是这样:
这是因为,我们创建的数组长度为10,第三次读取的时候,长度不够,所以只替换数组中的前6个!后面四个和上一次读取输出的数组的后四个一样!!
四、io流的java.io.Writer类(输出字符流)
注意:字符流在输出时要刷新管道,而 字节流不需要。刷新管道即用对象调用flush方法。也可以不用专门调用,因为close方法会自动刷新管道。再次强调是因为,如果没有close,也没有flush。字节流是可以输出的,但是字符流不可以。
1、为什么要用字符流?
因为字节流在输出字符时,不知道字符占几个字节,假如一个字占两个字节,但是,你只输出了一个字节,那么就是半个字,计算机会将其显示出来,但由于不认识,所以显示出来就是一个问号或其他乱码。为了解决这个问题,我们就用字符流。
2、字符流
字符流以字为单位输出,如果是半个字就不会输出。所以不至于输出问号或乱码。但字符流的方法与字节流大同小异!我们来实现一下!
FileWriter w = new FileWriter("d://a.txt");
w.write("进大厂,买摩托");
FileWriter w2 = (FileWriter) w.append("哈哈"); //追加返回的是此对象,
System.out.println(w2 == w); //结果为true即这俩为一个对象
// 需要强转,因为是多态
/**
* 可以连续追加
*/
w.append("第一次追加").append("第二次追加").append("第三次追加");
w.close(); //关闭流
下面为文件结果
值得注意的是:append方法为依次输入时的追加内容。而在new对象时,路径后面如果加true,是指在上一次的文件中直接继续添加,而不用清空原文件!
五、io流的java.io.FileReader类(输入字符流)
和字节输入流类似,我们来实现一下常用方法!(用刚刚用字符输出流写的文件)
先用简单的read方法来读字符
FileReader r = new FileReader("d://a.txt");
//读一个字符
int c = r.read(); //read返回值是int型
System.out.println((char)c); //输出要强转
//用循环来读一串字符
while(true){
int c1 = r.read();
if(c1 == -1){
break;
}
System.out.print((char) c1);
}
r.close();
运行结果:
用数组来输入字符流:
注意!!!!!:此处创建数组,长度为100,但是我们本来的字符长度没有100,所以后面的长度全部用空格来填满!这样很占内存!!
char [] c = new char[100];
r.read(c);
System.out.println(c);
r.close();
运行结果:
解决方案~~用length来限定长度!
char [] c = new char[100];
int len = r.read(c); //read返回的int就是长度,将长度赋给len
String text = new String(c,0,len); //输出字符串,从0开始,输出len个字符
System.out.println(text);
System.out.println(text.length());
r.close();
运行结果!
六、转换流
转换流是一种将字节流装饰为字符流的流
1、将字节输出流转换为字符输出流:
OutputStreamWriter 类
2、将字节输入流转换为字符输入流
InputStreamReader
演示实现一下!
我们先用输出流来写一个txt文件
FileOutputStream fis = new FileOutputStream("d://a.txt"); //创建一个输出字节流对象
//转换流
OutputStreamWriter fiss = new OutputStreamWriter(fis); //用转换流将字节流转换为字符流
fiss.write("床前明月光");
fiss.close();
结果,在d盘中:
再用输入流,将刚刚写的txt输入到程序中:
FileInputStream fis = new FileInputStream("d://a.txt"); //创建一个输入字节流对象
/* *
* 转换流*/
InputStreamReader fiss = new InputStreamReader(fis); //用转换流将字节流转换为字符流
while (true){
int c = fiss.read();
if(c==-1){
break;
}
System.out.println((char)c);
}
fiss.close();
结果:
七、打印流
将字符打印出去,System.out其实就是在用字符的打印(输出)流。
很简单,我们用代码演示
PrintStream ps = new PrintStream("d://c.txt");
ps.println("锄禾日当午");
ps.close();
PrintWriter ps1 = new PrintWriter("d://c.txt");
ps1.append("汗滴禾下土");
ps1.close();
这里面的PrintStream 和 PrintWriter 的实现和方法都没啥区别。
运行结果,这里展示一下第二个的,第一个和这个一样
打印流也可以直接将字节流转化为字符流
FileOutputStream fos = new FileOutputStream("d://e.txt"); //字节流
PrintWriter foss = new PrintWriter(fos); //用PrintWriter来转换成字符流
foss.println("进大厂1");
foss.println("进大厂2");
foss.println("进大厂3");
foss.close();
结果:
八、缓存流
之前的流都是一次读一个字节或者一个字符。
而缓存流是:
将字符输入流转换成带有缓存的,可以一次输出一行字符的缓存字符读取流。
FileReader fos1 = new FileReader("d://e.txt"); //先用FileReader读取文件
BufferedReader fos2 = new BufferedReader(fos1); //创建缓存流对象
String text = fos2.readLine(); //用对象调用读取一行的方法
System.out.println(text);
结果: