IO流基础概念
字节流:
字节输出流FileOutputStream(将程序中的数据输出到本地文件)
作用:程序数据------>文件
该流可以将程序中的内容输出到本地文件中存储,具体有三个步骤
1、创建字节输出流对象
2、写入数据
3、释放资源
一次写入一个数据
创建字节输出流并写入a字母实现代码如下:
package com.itazhang.Demo1;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo1 {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
FileOutputStream f = new FileOutputStream("D:\\11Codingtext\\MyIO\\a.txt");
//写入数据
f.write(97);
//释放资源
f.close();
}
}
该创建方法:1、如果该父路径下没有该文件,会自动创建文件进行操作。2、如果用于进行写入数据的文件里最开始有其他数据,则会将之前的文件里的数据先清除再进行写入数据操作,相当于用将要写入该文件的数据将该文件原有的数据给覆盖了(可以理解为游戏存档,将之前的存档覆盖)在最开始的数据被覆盖之后,也就是最开始的文件数据被清空,且在第一次write方法写入数据,后面的连续写入数据操作是不会覆盖的,相当于每次创建字节输出流文件里面的数据才会被清除并进行后面的写入数据操作,并不是每次写入都会覆盖之前的数据,也能在创建该字节输出流文件时,在文件地址后面传入第二个参数true,就可以将默认的续写功能打开,这个时候就不会自动清空之前的数据(默认是false也就是关闭续写功能的)
如下:
FileOutputStream f = new FileOutputStream("D:\\11Codingtext\\MyIO\\a.txt",true);
3、在写入数据时,write()方法是写入的数据类型是整数,但是真正写入的数据是该整数在ascll编码里对应的字符4、每次使用完之后都得释放资源
一次写入多个数据
package com.itazhang.Demo1;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class ByteStreamDemo1 {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
FileOutputStream f = new FileOutputStream("D:\\11Codingtext\\MyIO\\a.txt");
//创建字节数组,一次性写入多个值
String str ="abdferrr";
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
//写入数据
f.write(bytes);
//释放资源
f.close();
}
}
一次写入提供字节数组的前几个数据。
格式为(写入的字节数组,写入数据在数组的起始索引,从起始索引开始写入的长度),如下
f.write(bytes,0,3);
字节输入流FileInputStream(将本地文件中的数据输入到程序中)
作用:文件数据--------->程序
步骤如下:
1、创建字节输入流对象
2、从本地文件数据
3、释放资源
该方法时将本地文件中的数据读取之后输入到程序中,但是在创建字节流输入对象的时候,如果需要读取的文件不存在的话,会直接报错,且在从本地文件进行读取操作的时候read方法是一次只能读取一个数据,且返回的是int类型的数值(该数字对应的是被读取的字符对应ascll码),如果想要看到原本的字符,则需要将该数字强转为读取字符的类型,在多次调用read方法读完文件数据后,如果再使用read方法对该文件进行读取,则只会返回-1,每次使用完之后也会释放资源
下面为一次read方法的使用,也就是读取本地文件的第一个数据的代码,如下:
package com.itazhang.Demo1;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStreamDemo2 {
public static void main(String[] args) throws IOException {
FileInputStream f =new FileInputStream("D:\\11Codingtext\\MyIO\\a.txt");
//此时的read方法相当于只读了一次就是将文档中的字符串中的第一个字母进行read操作
int read1 = f.read();
System.out.println(read1);
//如果想读取到读取出来的ascll码对应的字符,此时直接用char类型强转类型即可
System.out.println((char) read1);
f.close();
}
}
下面为对read方法的循环使用,从而读取到本地文件的所有数据,利用read方法在读取完文件的数据之后会返回-1这个特点,我们能将其做为while循环的结束条件,代码如下:
package com.itazhang.Demo1;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStreamDemo2 {
public static void main(String[] args) throws IOException {
FileInputStream f =new FileInputStream("D:\\11Codingtext\\MyIO\\a.txt");
while(true){
int read1 = f.read();
if(read1 == -1){
break;
}
System.out.println((char)read1);
}
f.close();
}
}
System.out.println((char)read1);
但是注意上方不能写成下列形式,因为如果写成下列形式,相当于在打印方法里又调用了一次read方法,可以理解为指针在使用打印方法的时候因为调用了read方法所以指针又向后移动了一位,这时候就会出现打印一个字母读取两次的情况,就会跳过打印一些数据。
System.out.println((char)f.read());
拷贝文件数据的练习(一次读取一个byte的数据)
需求:将一个文件a的数据拷贝到另一个文件b里
分析:需要将一个文件的数据拷贝到另一个文件,那么首先需要通过创建FileInputStream的对象,调用FileInputSteam里的read方法从文件中将源文件a的数据取出并存储到程序的一个容器里(也能边读边写),再创建一个FileOutputStream对象,使用FileOutputStream里的write方法将该容器里的数据写入到b文件里,这样就实现了将文件a的数据拷贝到b文件里,具体实现代码如下:
package com.itazhang.Demo1;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class CopyExercise1 {
public static void main(String[] args) throws IOException {
//从原文件中读取数据并放入一个集合中
FileInputStream fin = new FileInputStream("D:\\11Codingtext\\MyIO\\a.txt");
ArrayList<Integer> list =new ArrayList<>();
while(true){
int i =fin.read();
if(i==-1){
break;
}
int temp = i;
list.add(temp);
}
//将这个集合里的数据写入到目的文件中
FileOutputStream fout = new FileOutputStream("D:\\11Codingtext\\MyIO\\b.txt");
for (Integer tempvalue : list) {
fout.write(tempvalue);
}
fin.close();
fout.close();
}
}
对上诉代码精简,边读取边写入,代码如下:
package com.itazhang.Demo1;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class CopyExercise1 {
public static void main(String[] args) throws IOException {
//从原文件中读取数据并放入一个集合中
FileInputStream fin = new FileInputStream("D:\\11Codingtext\\MyIO\\a.txt");
FileOutputStream fout = new FileOutputStream("D:\\11Codingtext\\MyIO\\b.txt");
while(true){
int i =fin.read();
if(i==-1){
break;
}
int temp = i;
fout.write(temp);
}
fout.close();
fin.close();
}
}
一次读取多个字节
使用read(byte数组)的方式能一次读取数组长度个数据,这样的话在读取的时候,读取出来的数据是直接存储在这个byte数组中的,而此时read(byte数组)这个方法的返回值是这个数组的长度也是一次能读取的数据个数
在读取的时候因为他是按照数组的固定长度读取的,那么如果在读取最后一次的时候,这个数组并没有满会怎么样呢,测试代码如下:原文件中数据为:abcdefghi
package com.itazhang.Demo1;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo3 {
public static void main(String[] args) throws IOException {
FileInputStream f = new FileInputStream("D:\\11Codingtext\\MyIO\\a.txt");
FileOutputStream fo = new FileOutputStream("D:\\11Codingtext\\MyIO\\b.txt");
byte[] brr = new byte[2];
//第一次,打印ab,值为2
System.out.println("-------1---------");
int temp1 = f.read(brr);
System.out.println(temp1);
System.out.println(new String(brr));
//第二次,打印cd,值为2
System.out.println("-------2---------");
int temp2 = f.read(brr);
System.out.println(temp2);
System.out.println(new String(brr));
//第三次,打印ef,值为2
System.out.println("-------3---------");
int temp3 = f.read(brr);
System.out.println(temp3);
System.out.println(new String(brr));
//第四次,打印gh,值为2
System.out.println("-------4---------");
int temp4 = f.read(brr);
System.out.println(temp4);
System.out.println(new String(brr));
//第五次,第五次打印结果为ih,值为1
System.out.println("-------5---------");
int temp5 = f.read(brr);
System.out.println(temp5);
System.out.println(new String(brr));
//第六次,打印出的数据还是ih,值为-1
System.out.println("-------6---------");
int temp6 = f.read(brr);
System.out.println(temp6);
System.out.println(new String(brr));
}
}
运行结果如下:
会发现,前4次打印数据是符合我们的预想的,在第五次原文件的数据应该被读取完了,所以返回的数字是1,但是为啥他数组里的数据是ih呢,因为这个数组的长度为2,所以一次只能接受2个数据,而在read的时候因为前4次的数据是够的,所以会将读取到的两个数据放入数组中,每次放入数组的数据会覆盖前一次放入的两个数组内的值,但是到了第5次,只读取到了一个数据,所以只会将i这一个数据放入数组覆盖掉之前的一个值,即i覆盖掉之前gh位置的g,所以现在数组里显示的是ih,在第六次read的时候,因为这个文件里的数据已经被读取完了,所以会返回-1,而数组里的数据由于没有被改变所以值还是为之前的ih。所以这就是上诉情况出现的原因。
那么因为在拷贝的时候我在每一次读取数据之后是会将数据通过FileOutStream的write方法写入到对应的文件中的,像上诉情况我最后是不能写入ih到目的文件的,所以就需要使用创建String的一种方式,new String(bytes,0,temp5),也是这种方式,他会自动的将bytes数组也就是我每一次read出来的数据从0索引开始创建temp5也就是读取到的长度的字符串,例如在第五次,temp5也就是这次读取到数据的个数为1,这次数组里的数据为ih,那么这次就会创建i这个字符串,而不是ih,这样就能避免上诉方法。
于是代码就能优化成下列方式
package com.itazhang.Demo1;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo3 {
public static void main(String[] args) throws IOException {
FileInputStream f = new FileInputStream("D:\\11Codingtext\\MyIO\\a.txt");
FileOutputStream fo = new FileOutputStream("D:\\11Codingtext\\MyIO\\b.txt");
byte[] brr = new byte[2];
//第一次,打印ab,值为2
System.out.println("-------1---------");
int temp1 = f.read(brr);
System.out.println(temp1);
System.out.println(new String(brr,0,temp1));
//第二次,打印cd,值为2
System.out.println("-------2---------");
int temp2 = f.read(brr);
System.out.println(temp2);
System.out.println(new String(brr,0,temp2));
//第三次,打印ef,值为2
System.out.println("-------3---------");
int temp3 = f.read(brr);
System.out.println(temp3);
System.out.println(new String(brr,0,temp3));
//第四次,打印gh,值为2
System.out.println("-------4---------");
int temp4 = f.read(brr);
System.out.println(temp4);
System.out.println(new String(brr,0,temp4));
//第五次,第五次打印结果为ih,值为1
System.out.println("-------5---------");
int temp5 = f.read(brr);
System.out.println(temp5);
System.out.println(new String(brr,0,temp5));
}
}
拷贝文件数据的练习优化(一次读取多个个byte的数据,用byte数组实现)
而之前将a文件拷贝到b文件夹的练习就可以被优化,这时我们可以用一个长度为5的数组来存储每次读取的a文件数据,且将这个数组的数据写入到b文件中,具体代码如下:
package com.itazhang.Demo1;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BytesStreamDemo4 {
public static void main(String[] args) throws IOException {
FileInputStream fin = new FileInputStream("D:\\11Codingtext\\MyIO\\a.txt");
FileOutputStream fout = new FileOutputStream("D:\\11Codingtext\\MyIO\\b.txt");
byte[] brr = new byte[4];
int temp ;
while(true){
temp = fin.read(brr);
if(temp == -1){
break;
}
fout.write(brr,0,temp);
}
fout.close();
fin.close();
}
}
而在之前一个个读取的代码中加入运行时间判断,发现在文件中长数据的读取和写入时,后面优化后的代码也就是用字节数组的方法时间会少很多,效率会提高很多
long start = System.currentTimeMillis(); long end = System.currentTimeMillis(); System.out.println(end - start);