1、为什么要学IO流?
因为内存中不能永久存储数据,程序停止,数据就会丢失。因此需要将数据保存在硬盘中的文件内。而File只能对文件本身进行操作,不能操作文件内容,所以需要IO流读写文件中的数据。
2、IO流的作用?
读写数据,可以是本地文件,也可以是网络上的
3、IO流读写的参照物?
程序或者说是内存(因为程序运行在内存中)。程序向文件写数据,从文件中读数据。
4、IO流的分类?
按流的方向分:输出流、输入流。
按操作文件类型分:字节流、字符流。
(字节流可以操作所有类型的文件:文本、视频、音频…… 字符流只能操作纯文本文件)
(纯文本文件:windows自带的记事本能打开并能读懂的文件。例如:txt文件、md文件、xml文件)
5、FileOnputStream
5.1 初识FileOnputStream
作用:操作本地文件的字节输出流,可以把程序中的数据写到文件中。
步骤:
1、创建字节输出流对象
2、写出数据
3、关闭流
public static void main(String[] args) throws IOException {
/**
* 1、创建字节输出流对象
* 细节1:参数是File对象或字符串表示的路径
* 细节2:如果文件不存在,会创建一个新文件,但要保证父级目录存在
* 细节3:如果文件存在,会清空文件
* 2、写出数据
* 细节1:write方法的参数是整数,但写到文件中的是整数所对应的ASCII上表示的字符
* 3、关闭流
* 细节1:每次使用完流,必须释放资源
*/
FileOutputStream fos = new FileOutputStream("./a.txt");
fos.write(97);
fos.close();
}
5.2 FileOnputStream写数据的三种方式
/**
* 一次写出一个字节
*/
FileOutputStream fos = new FileOutputStream("./a.txt");
fos.write(97);
fos.write(98);
fos.close();
/**
* 一次写出一个字节数组的数据
*/
FileOutputStream fos = new FileOutputStream("./a.txt");
byte[] bytes = new byte[]{97,98,99,100,101};
fos.write(bytes);
fos.close();
/**
* 一次写出一个字节数组的部分数据
*/
FileOutputStream fos = new FileOutputStream("./a.txt");
byte[] bytes = new byte[]{97,98,99,100,101};
//从0开始写出,写1个字节到文件
fos.write(bytes,0,1);
fos.close();
5.3 FileOnputStream换行写和续写
换行写:再写出一个换行符即可
(注:再windows系统中,java对回车进行了优化。当我们只写\r或者\n时,java会在底层进行补全,因此也会实现换行。)
不同的系统中换行符是不一样的:
windows: \r\n
Linux : \n
Mac: \r
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("./a.txt");
String str1 = "huanhang";
byte[] bytes1 = str1.getBytes();
fos.write(bytes1);
//换行
String huanhang = "\r\n";
byte[] bytes = huanhang.getBytes();
fos.write(bytes);
String str2 = "sucess";
byte[] bytes2 = str2.getBytes();
fos.write(bytes2);
fos.close();
}
续写:打开续写开关即可
开关位置:创建FileOutputStream对象时的第二个参数,默认为false,改为true即可。
此时,创建对象时不会清空文件内容。
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("./a.txt",true);
String str1 = "huanhang";
byte[] bytes1 = str1.getBytes();
fos.write(bytes1);
fos.close();
}
6、FileInputStream
6.1 初识FileInputStream
作用:操作本地文件的字节输入流,可以把文件中的数据读取到程序中。
步骤:
1、创建字节输入流对象
2、读取数据
3、关闭流
public static void main(String[] args) throws IOException {
/**
* 1、创建字节输出流对象
* 细节1:若文件不存在,直接报错
* 2、写出数据
* 细节1:读到末尾了,会返回-1.若文件内容末尾是-1,他会分开读“-”和“1”
* 细节2:一次读一个字节,读到的是数据在ascii码上的数字
* 3、关闭流
* 细节1:使用完流,一定要关闭流
*/
FileInputStream fis = new FileInputStream("./a.txt");
//读第一个字节
char read1 = (char)fis.read();
System.out.println(read1);
//都第二个字节
char read2 = (char)fis.read();
System.out.println(read2);
//读第三个字节
char read3 = (char)fis.read();
System.out.println(read3);
//文件内容读完后,再读取,会返回-1
int read6 = fis.read();
System.out.println(read6);
fis.close();
}
6.2 FileInputStream循环读取
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("./a.txt");
int b;
while((b=fis.read())!=-1){
System.out.println((char) b);
}
fis.close();
}
若我们不借助第三方变量b,读取的时候会出问题
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("./a.txt");
/**
* read方法:读取数据,读取一个数据就移动一次指针
*/
while(fis.read()!=-1){
System.out.println((char) fis.read());
}
fis.close();
}
文件中的内容是:
读取到的内容是:
原因:read方法:读取数据,读取一个数据就移动一次指针。
6.3 FileInputStream读数据的两种方式
注:
1、一次读取一个字节数组数据,每次读取会尽可能把数组装满。
2、一般会创建的数组长度是1024的整数倍。
第三次读取的时候,会发现多输出了一个d,改进:
public static void main(String[] args) throws IOException {
/**
* 一次读取多个数据
*/
FileInputStream fis = new FileInputStream("E:\\a.txt");
int len;
byte[] bytes = new byte[2];
//len表示读取到数组的长度
len = fis.read(bytes);
System.out.println(len);
System.out.println(new String(bytes,0,len));
len = fis.read(bytes);
System.out.println(len);
System.out.println(new String(bytes,0,len));
len = fis.read(bytes);
System.out.println(len);
System.out.println(new String(bytes,0,len));
fis.close();
}
7、拷贝文件
思路:边读边写
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("E:\\zzy.jpeg");
FileOutputStream fos = new FileOutputStream("./copyzzy.jpeg");
//边读边写
int b;
while((b=fis.read())!=-1){
fos.write(b);
}
//关闭资源。先开的后关
fos.close();
fis.close();
}
思考:若拷贝的文件过大,会不会速度很慢?
会。因为上面的read是一次读取一个字节,我们将其改进成一次读取多个字节。
改进代码:
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("E:\\zzy.jpeg");
FileOutputStream fos = new FileOutputStream("./copyzzy.jpeg");
//边读边写
int len;
byte[] bytes = new byte[1024];
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
//关闭资源。先开的后关
fos.close();
fis.close();
}
将抛出异常改为捕获异常
注:被finally包起来的代码一定会被执行,除非jvm退出。
public static void main(String[] args){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("E:\\zzy.jpeg");
fos = new FileOutputStream("./copyzzy.jpeg");
//边读边写
int len;
byte[] bytes = new byte[1024];
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
}catch (IOException e){
e.printStackTrace();
}finally {
//关闭资源。先开的后关
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
8、try{}catch(){}异常处理(了解即可)
/**
* JDK7中的方案
* 注:只有实现了AutoCloseable接口,才能在try后面的括号内创建对象
*
*/
public static void main(String[] args) {
try(FileInputStream fis = new FileInputStream("E:\\zzy.jpeg");
FileOutputStream fos = new FileOutputStream("./copyzzy.jpeg");){
//边读边写
int len;
byte[] bytes = new byte[1024];
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
}catch(IOException e){
e.printStackTrace();
}
}
/**
* JDK9中IO异常处理
*
*/
public static void main(String[] args) throws FileNotFoundException {
FileInputStream fis = new FileInputStream("E:\\zzy.jpeg");
FileOutputStream fos = new FileOutputStream("./copyzzy.jpeg");
try(fis;fos){
//边读边写
int len;
byte[] bytes = new byte[1024];
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
}catch (IOException e){
e.printStackTrace();
}
}