一、IO流
IO流概述和分类
- IO流介绍
- IO:输入/输出(Input/Output)
- 流:是一种抽象概念,是对数据传输的总称.也就是说数据在设备间的传输称为流,流的本质是数据传输,数据的基本单位是字节,一个字符等于两个字节
- IO流就是用来处理设备间数据传输问题的.常见的应用: 文件复制; 文件上传; 文件下载
- IO流的分类
- 按照数据的流向
- 输入流:读数据,硬盘中数据输入内存中使用
- 输出流:写数据,内存中数据写入硬盘中保存
- 按照数据类型来分
- 字节流
- 字节输入流
- 字节输出流
- 字符流
- 字符输入流
- 字符输出流
- 字节流
- 按照数据的流向
- IO流的使用场景
- 如果操作的是纯文本文件,优先使用字符流
- 如果操作的是图片、视频、音频等二进制文件,优先使用字节流
- 如果不确定文件类型,优先使用字节流.字节流是万能的流
二、 字节流
2.1 字节流写数据
-
字节流抽象基类
- InputStream:这个抽象类是表示字节输入流的所有类的超类
- OutputStream:这个抽象类是表示字节输出流的所有类的超类
- 子类名特点:子类名称都是以其父类名作为子类名的后缀
-
字节输出流
- FileOutputStream(String name):创建文件输出流以指定的名称写入文件
-
使用字节输出流写数据的步骤
- 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
- 调用字节输出流对象的写数据方法
- 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
-
示例代码
public class FileOutputStreamDemo01 {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
/*
注意点:
1.如果文件不存在,会帮我们创建
2.如果文件存在,会把文件清空
*/
//FileOutputStream(String name):创建文件输出流以指定的名称写入文件
FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt");
//void write(int b):将指定的字节写入此文件输出流
fos.write(97);
// fos.write(57);
// fos.write(55);
//最后都要释放资源
//void close():关闭此文件输出流并释放与此流相关联的任何系统资源。
fos.close();
}
}
2.2 字节流写数据的三种方式
-
写数据的方法分类
方法名 说明 void write(int b) 将指定的字节写入此文件输出流 一次写一个字节数据 void write(byte[] b) 将 b.length字节从指定的字节数组写入此文件输出流 一次写一个字节数组数据 void write(byte[] b, int off, int len) 将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流 一次写一个字节数组的部分数据 -
示例代码
package com.svt.io.output;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class OutputDemo01 {
/**
* public void write(byte[] b): 将 blength字节从指定的字节数组写入此输出流。
* 一次写多个字节:
* 如果写的第一个字节是正数(0-127)那么显示的时候会查询ASCII表
* 如果写的第一个字节是负数,那第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认码表(GBK)
*
* public void write(byte[] b,int off,int len) : 从指定的字数组写入 len字节,从偏量 off开始输出到此输出流。
* public abstract void write(int b) : 将指定的字节输出流。
*
* 构造方法的作用:
* 1.创建一个FileOutputstream对象
* 2.会根据构造方法中传递的文件/文件路径,创建一个空的文件
* 3.会把FileOutputstream对象指向创建好的文件
*
* 1.创建FileOutputstream对象,构造方法中绑定要写入数据的目的地
* 2.调用FileOutputstream对象中的方法write,把数据写入到文件中
*
* @param args
*/
public static void main(String[] args) throws IOException {
//1.创建FileOutputstream对象,构造方法中绑定要写入数据的目的地
FileOutputStream fos = new FileOutputStream("F:\\DELL\\项目\\a.txt");
//2.调用FileOutputstream对象中的方法write,把数据写入到文件中
//在文件中显示100,写个字节
/* fos.write(49);
fos.write(48);
fos.write(48);*/
/**
* public void write(byte[] b): 将 blength字节从指定的字节数组写入此输出流。
* 一次写多个字节:
* 如果写的第一个字节是正数(0-127)那么显示的时候会查询ASCII表
* 如果写的第一个字节是负数,那第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认码表(GBK)
*/
byte[] bytes={65,66,67,68,69,70};//ABCDEF
//byte[] bytes={65,-66,-67,-68,69,-77};
//byte[] bytes={-127,-66,-67,-68,69,-77,2};
fos.write(bytes);
//fos.write(127);
//public void write(byte[] b,int off,int len) : 把字节数组的一部分写入到文件中
//int off:数组的开始索引
// int len:写几个字节
// 从指定的字数组写入 len字节,从偏量 off开始输出到此输出流。
fos.write(bytes,1,2);//BC
/*
写入字符串的方法:可以使用String类中的方法把字符串,转换为字节数组
byte[] getBytes() 把字符串转换为字节数组
*/
byte[] bytes1="你好".getBytes();
System.out.println(Arrays.toString(bytes1));//[-28, -67, -96, -27, -91, -67]
fos.write(bytes1);
//释放资源
fos.close();
}
}
2.3 字节流换行
- 字节流写数据如何实现换行
- windows:\r\n
- linux:\n
- mac:\r
- 字节流写数据如何实现追加写入
- public FileOutputStream(String name,boolean append)
- 创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头
- 示例代码
package com.svt.io.output;
import java.io.FileOutputStream;
import java.io.IOException;
public class OutputDemo02 {
/**
* 追加写/续写:使用两个参数的构造方法
* File0utputstream(String name, boolean append)
* 创建一个向具有指定 name 的文件中写入数据的输出文件流
* File0utputStream(File file, boolean append)
* 创建一个向指定 Fle 对象表示的文件中写入数据的文件输出流
* 参数:
* string name,File file:写入数据的目的地
* boolean append:追加写开关
* true:创建对象不会覆盖源文件,继续在文件的末尾追加写数据
* false:创建一个新文件覆盖源文件
*/
public static void main(String[] args) throws IOException {
//可以执行很多次,不会覆盖,会继续在文件的末尾追加写数据
FileOutputStream fos = new FileOutputStream("F:\\DELL\\项目\\dellTestProject\\ioProject\\c.txt",false);
//追加续写
// fos.write("你好".getBytes());
/**
* 换行
* - windows:\r\n
* - linux:\n
* - mac:\r
*/
for (int i = 0; i <= 10; i++) {
fos.write("你好".getBytes());
fos.write("\r\n".getBytes());
}
fos.close();
}
}
2.4 字节流读数据(一次读一个字节数据)
-
字节输入流
- FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名
-
字节输入流读取数据的步骤
- 创建字节输入流对象
- 调用字节输入流对象的读数据方法
- 释放资源
-
示例代码
package com.svt.io.output;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class OutputDemo03 {
/**
* java,io.Inputstream;字节输入流
* 此抽象类是表示字节输入流的所有类的超类。
*
* 定义了所有子类共性的方法:
* int read()从输入流中读取数据的下一个字节。
* int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 6 中。
* void cLose() 关闭此输入流并释放与该流关联的所有系统资源。
*
* java.io.FileInputstream extends Inputstream
* FileInputstream:文件字节输入流
* 作用:把硬盘文件中的数据,读取到内存中使用
*
* 构造方法:
* FileInputstream(string name)
* FileInputstream(File file)
* 参数:读取文件的数据源
* string name:文件的路径
* File file:文件
* 构造方法的作用:
* 1.会创建一个FileInputStream对象
* 2.会把FileInputstream对象指定构造方法中要读取的文件
*
*读取数据的原理(硬盘-->内存)
* java程序-->JVM-->0S-->0S读取数据的方法-->读取文件
*
* 字节输入流的使用步骤(重点):
* 1创建FileInputstream对象,构造方法中绑定要读取的数据源
* 2.使用FileInputstream对象中的方法read,读取文件
* 3.释放资源
*/
public static void main(String[] args) throws IOException {
//1.创建FileInputstream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("F:\\DELL\\项目\\dellTestProject\\ioProject\\b.txt");
//2.使用FileInputstream对象中的方法read,读取文件
//int read读取文件的一个字节并返回,读取到文件的末尾返回-1
/*int read = fis.read();
System.out.println(read);//97 a
read = fis.read();
System.out.println(read);//98
read = fis.read();
System.out.println(read);//-1 读取完毕*/
//再读取一次 还是-1 因为已经读取完毕
/**
* 发现以上读取文件是一个重复的过程,所以可以使用循环优化
* 不知道文件中有多少字节,使用while循环while循环
* 结束条件,读取到-1的时候结束
*
* 布尔表达式(read=fis.read())!=-1
* 1.fis.read() 读取一个字节
* 2.read=fis.read() 把读取到的字节赋值给变量
* 3.(read=fis.read())!=-1 判断变量read是否不等于-1
*/
int read=0;//记录读取到的字节
//结束条件,读取到-1的时候结束
while ((read=fis.read())!=-1){
System.out.println((char) read);
}
//释放资源
fis.close();
}
}
2.5 字节流读数据(一次读一个字节数组数据)
-
一次读一个字节数组的方法
- public int read(byte[] b):从输入流读取最多b.length个字节的数据
- 返回的是读入缓冲区的总字节数,也就是实际的读取字节个数
-
示例代码
package com.svt.io.output;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
/**
*字节输入流一次读取多个字节的方法:
* int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中
*
* 明确两件事情:
* 1.方法的参数byte[]的作用?
* 起到缓冲作用,存储每次读取到的多个字节
* 数组的长度定义为1024(1kb)或者1024的整数倍
* 2.方法的返回值int是什么?
* 每次读取的有效字节个数
*
* string类的构造方法
* string(byte[] bytes) :把字节数组转换为字符串
* String(byte[] bytes,int offset,int length)把字节数组的一部分转换为字符串
* offset:数组的开始索引 Length:转换的字节个数
*
*/
public class OutputDemo04 {
public static void main(String[] args) throws IOException {
//1.创建FileInputstream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("F:\\DELL\\项目\\dellTestProject\\ioProject\\b.txt");
//2.使用FileInputstream对象中的方法read,读取文件
//int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中
/*byte[] bytes = new byte[2];
int read = fis.read(bytes);
System.out.println(read);//2
//System.out.println(Arrays.toString(bytes));
System.out.println(new String(bytes));//AB
read=fis.read(bytes);
System.out.println(read);//2
System.out.println(new String(bytes));//CD
read=fis.read(bytes);
System.out.println(read);//1
System.out.println(new String(bytes));//ED
read=fis.read(bytes);
System.out.println(read);//-1
System.out.println(new String(bytes));//ED*/
/**
* 发现以上读取时一个重复的过程,可以使用循环优化
* 不知道文件中有多少字节,所以使用ihile循环
* while循环结束的条件读取到-1结束
*/
byte[] bytes = new byte[1024];//存储读取到的多个字节
int len=0;//记录每次读取的有效字节个数
//while循环结束的条件读取到-1结束
while ((len=fis.read(bytes))!=-1){
//String(bytel] bytes,int offset,int length)把字节数组的一部分转换为字符串
System.out.println(new String(bytes,0,len));
}
//释放资源
fis.close();
}
}
2.6 字节流复制文件
- 需求明确:
数据源: c:\1.jpg
数据的目的地: d:\1.jpg - 文件复制的步骤:
1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
3.使用字节输入流对象中的方法read读取文件
4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
5.释放资源 - 示例代码
package com.svt.io.output;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class OutputDemo05 {
/**
* 明确:
* 数据源: c:\\1.jpg
* 数据的目的地: d:\\1.jpg
*
* 文件复制的步骤:
* 1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
* 2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
* 3.使用字节输入流对象中的方法read读取文件
* 4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
* 5.释放资源
* @param args
*/
public static void main(String[] args) throws IOException {
long l = System.currentTimeMillis();
//1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("F:\\DELL\\dellStudy\\06-IO流\\02-学习资料\\学习笔记\\day20_IO流02\\资料\\转换流的图解.png");
//2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
FileOutputStream fos = new FileOutputStream("F:\\DELL\\DELLlianxi\\作业\\06IO流\\转换流的图解.png");
//一次读取一个字节写入一个字节的方式
//3.使用字节输入流对象中的方法read读取文件
/*int len=0;
while ((len=fis.read())!=-1){
//4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
fos.write(len);
}*/
//优化
//使用数组缓冲读取多个字节,写入多个字节
byte[] bytes = new byte[1024];
int len=0;
while ((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
//释放资源(先关写的,再关读的,如果写完了,那肯定也读取完毕了)
fos.close();
fis.close();
long e = System.currentTimeMillis();
System.out.println("耗时"+(e-l)+"毫秒");
}
}
2.7 字节流复制文件【应用】
-
案例需求
把“E:\wedu\mn.jpg”复制到模块目录下的“mn.jpg” (文件可以是任意文件去)
-
实现步骤
- 根据数据源创建字节输入流对象
- 根据目的地创建字节输出流对象
- 读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
- 释放资源
-
代码实现
public class CopyJpgDemo {
public static void main(String[] args) throws IOException {
//根据数据源创建字节输入流对象
FileInputStream fis = new FileInputStream("E:\\wedu\\mn.jpg");
//根据目的地创建字节输出流对象
FileOutputStream fos = new FileOutputStream("myByteStream\\mn.jpg");
//读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
byte[] bys = new byte[1024];
int len;
while ((len=fis.read(bys))!=-1) {
fos.write(bys,0,len);
}
//释放资源
fos.close();
fis.close();
}
}
三、字符流
3.1 为什么会出现字符流
- 字符流的介绍
由于字节流操作中文不是特别的方便,所以Java就提供字符流
字符流 = 字节流 + 编码表 - 中文的字节存储方式
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?
汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
3.2 编码表
- 什么是字符集
是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等 - 常见的字符集
-
ASCII字符集:
lASCII:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等 -
GBXXX字符集:
GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等 -
Unicode字符集:
UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用 中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码编码规则:
128个US-ASCII字符,只需一个字节编码
拉丁文等字符,需要二个字节编码
大部分常用字(含中文),使用三个字节编码
其他极少使用的Unicode辅助字符,使用四字节编码
-
3.3 字符串中的编码解码问题
-
相关方法
方法名 说明 byte[] getBytes() 使用平台的默认字符集将该 String编码为一系列字节 byte[] getBytes(String charsetName) 使用指定的字符集将该 String编码为一系列字节 String(byte[] bytes) 使用平台的默认字符集解码指定的字节数组来创建字符串 String(byte[] bytes, String charsetName) 通过指定的字符集解码指定的字节数组来创建字符串 -
代码演示
public class StringDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
//定义一个字符串
String s = "中国";
//byte[] bys = s.getBytes(); //[-28, -72, -83, -27, -101, -67]
//byte[] bys = s.getBytes("UTF-8"); //[-28, -72, -83, -27, -101, -67]
byte[] bys = s.getBytes("GBK"); //[-42, -48, -71, -6]
System.out.println(Arrays.toString(bys));
//String ss = new String(bys);
//String ss = new String(bys,"UTF-8");
String ss = new String(bys,"GBK");
System.out.println(ss);
}
}
3.4 字符流写数据
-
介绍
Writer: 用于写入字符流的抽象父类
FileWriter: 用于写入字符流的常用子类
-
构造方法
方法名 说明 FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter 对象 FileWriter(File file, boolean append) 根据给定的 File 对象构造一个 FileWriter 对象 FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象 FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象 -
成员方法
方法名 说明 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) 写一个字符串的一部分 -
刷新和关闭的方法
方法名 说明 flush() 刷新流,之后还可以继续写数据 close() 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 -
代码演示
package com.svt.io.writer;
import java.io.FileWriter;
import java.io.IOException;
public class WriterDemo01 {
/**
* java.io.writer:字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类
* 共性的成员方法:
* void write(int c) 写入单个字符。
* void write(char[] cbuf)写入字符数组。
* abstract void write(char[] cbuf, int off,int len)写入字数组的某-部,off数组的开始索引, len写的字符个数。
* void write(string str)写入字符串。
* void write(String str,int off,int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数.
* void flush()刷新该流的缓冲。
* void close() 关闭此流,但要先刷新它。
*
* java.io.Filelriter extends Outputstreamwriter extends Writer
* Filewriter:文件字符输出流
* 作用:把内存中字符数据写入到文件中
*
* 构造方法:
* Filewriter(File file)根据给定的 File 对象构造一个 Filelriter 对象。
* Filekriter(string fileName) 根据给定的文名构造一个 Filelriter 对象。
* 参数:写入数据的目的地
* string fileName:文件的路径
* File file:是一个文件
*构造方法的作用
* 1.会创建一个Filewriter对象
* 2.会根据构造方法中传递的文件/文件的路径,创建文件
* 3.会把FiLewriter对象指向创建好的文件
*
* 字符输出流的使用步骤(重点):
* 1创建Filewriter对象,构造方法中绑定要写入数据的目的地
* 2.使用Filewriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程
* 3.使用Filewriter中的方法fLush,把内存缓冲区中的数据刷新到文件中
* 4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
*
* @param args
*/
/**
* fLush方法和cLose方法的区别
* fLush : 刷新缓冲区,流对象可以继续使用。
* close: 先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//1创建Filewriter对象,构造方法中绑定要写入数据的目的地
FileWriter fw = new FileWriter("ioProject\\b.txt");
//2.使用Fileriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
fw.write(98);
//3.使用Filewriter中的方法fLush,把内存缓冲区中的数据刷新到文件中
//fw.flush();
//4.释放资源(会先把内存缓冲区中的数据刷新到文件中)
fw.close();//关闭文件前也会刷新数据
}
}
- 字符输出流写数据的其他方法
package com.svt.io.writer;
import java.io.FileWriter;
import java.io.IOException;
public class WriterDemo02 {
/**
* 字符输出流写数据的其他方法
* void write(char[] cbuf)写入字符数组。
* abstract void write(char[] cbuf,int off,int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
* void write(string str)写入字符串。
* void write(String str,int offint len) 写入字将串的某一部分,off字符串的开始索引,len写的字符个数。
*/
public static void main(String[] args) throws IOException {
//创建对象
FileWriter fw = new FileWriter("ioProject\\c.txt");
//void write(char[] cbuf)写入字符数组
char[] cs={'w','o','n','w','o','o'};
fw.write(cs);
//abstract void write(char[] cbuf,int off,int len)
fw.write(cs,0,2);
//void write(string str)写入字符串
fw.write("全圆佑");
//void write(String str,int offint len)
fw.write("是大傻子",1,3);
fw.close();
}
}
3.5 字符流读数据
-
介绍
Reader: 用于读取字符流的抽象父类
FileReader: 用于读取字符流的常用子类
-
构造方法
方法名 说明 FileReader(File file) 在给定从中读取数据的 File 的情况下创建一个新 FileReader FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader
-
成员方法
方法名 说明 int read() 一次读一个字符数据 int read(char[] cbuf) 一次读一个字符数组数据 -
代码演示
package com.svt.io.reader;
import java.io.FileReader;
import java.io.IOException;
public class ReaderDemo01 {
/**
*java.io.Reader:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类
* 共性的成员方法:
* int read() 读取单个字符并返回。
* int read(char[] cbuf)一次读取多个字符,将字符读入数组。
* void close() 关闭该流并释放与之关联的所有资源。
*
* java.io.FileReader extends InputstreamReader extends Reader
* FileReader:文件字符输入流作用:把硬盘文件中的数据以字符的方式读取到内存中
* 构造方法:
* FileReader(string fileName)
* FileReader(File file)
* 参数:读取文件的数据源
* string fileName:文件的路径
* File file:一个文件
*
* FileReader构造方法的作用:
* 1.创建一个FileReader对象
* 2.会把FileReader对象指向要读取的文件
*
* 字符输入流的使用步骤
* 1.创建FileReader对象,构造方法中绑定要读取的数据源
* 2.使用FileReader对象中的方法read读取文件
* 3.释放资源
* @param args
*/
public static void main(String[] args) throws IOException {
//1.创建FileReader对象,构造方法中绑定要读取的数据源
FileReader fr = new FileReader("F:\\DELL\\项目\\dellTestProject\\ioProject\\c.txt");
//2.使用FileReader对象中的方法read读取文件
//int read() 读取单个字符并返回
/*int len;
while ((len=fr.read())!=-1){
System.out.print((char) len);
}*/
//int read(char[] cbuf)一次读取多个字符,将字符读入数组。
char[] chars = new char[1024];//存储读取到的多个字符
int len;//记录的是每次读取的有效字符个数
while ((len=fr.read(chars))!=-1){
/**
* string类的构造方法
* string(char[] value) 把字符数组转换为字符串
* String(char[] valueint offsetint count) 把字数组的一部分转换为字串
* offset组的开始索引 count转换的个数
*/
System.out.print(new String(chars,0,len));
}
//释放资源
fr.close();
}
}
3.6 续写和换行
- 续写,追加写:使用两个参数的构造方法
FileWriter(string fileName, boolean append)
Filewriter(File file, boolean append) - 参数:
string fileName,File file:写入数据的目的地
boolean append;续写开关
true:不会创建新的文件覆盖源文件,可以续写
false:创建新的文件覆盖源文件换行:换行符号 - 示例代码
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("ioProject\\c.txt",true);
for (int i = 0; i < 10; i++) {
fw.write("全圆佑大傻子"+i+"\r\n");
}
fw.close();
}
四、异常处理
4.1 JDK7之前
-
异常处理格式
- try-catch-finally
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}finally{
一定会指定的代码
资源释放;
}
- finally特点
- 被finally控制的语句一定会执行,除非JVM退出
- 示例代码
package com.svt.io.writer;
import java.io.FileWriter;
import java.io.IOException;
public class WriterDemo04TryCatch {
/**
* 在jdk1.7之前使用try catch finally 处理流中的异常格式:
* try{
* 可能会产出异常的代码
* }catch(异常类变量 变量名){
* 异常的处理逻辑
* }finally{
* 一定会指定的代码
* 资源释放
* }
*
* @param args
*/
public static void main(String[] args) {
FileWriter fw=null;//提高变量fw的作用域 让finally可以使用
//变量在定义的时候,可能没有值,但是使用的时候必须有值
try {//可能会产出异常的代码
fw = new FileWriter("ioProject\\c.txt",true);
for (int i = 0; i < 10; i++) {
fw.write("全圆佑大傻子"+i+"\r\n");
}
} catch (IOException e) {//异常的处理逻辑
e.printStackTrace();
} finally {//一定会指定的代码
//如果创建对象失败,fw的默认值是null,不能调用方法,会抛出空指针异常,需要增加一个判断,不是null在把资源释放
if (fw!=null){
try {//fw.close声明抛出了IOException异常对象,所以我们就处理这个异常对象,throws/try catch
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4.2 JDK7新特性
- JDK7的新特性在try的后边可以增加一个()在括号中可以定义流对象
那么这个流对象的作用域就在try中有效
try中的代码执行完毕,会自动把流对象释放,不用写finaLly格式: - 异常处理格式
try(定义流对象;定义流对象....){
可能会产出异常的代码
}catch(异常类变量 变量名){
异常的处理逻辑
}
- 示例代码
package com.svt.io.writer;
import java.io.FileWriter;
import java.io.IOException;
public class WriterDemo05JDK7 {
/**
* JDK7的新特性在try的后边可以增加一个()在括号中可以定义流对象
* 那么这个流对象的作用域就在try中有效
* try中的代码执行完毕,会自动把流对象释放,不用写finaLly格式:
* try(定义流对象;定义流对象....){
* 可能会产出异常的代码
* }catch(异常类变量 变量名){
* 异常的处理逻辑
* }
*/
public static void main(String[] args) {
try (FileWriter fw = new FileWriter("ioProject\\c.txt",true);){
for (int i = 0; i < 10; i++) {
fw.write("全圆佑大傻子"+i+"\r\n");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.3 JDK9新特性
- JDK9新特性try的前边可以定义流对象
在try后边的()中可以直接引入流对象的名称(变量名)
在try代码执行完毕之后,流对象也可以释放掉,不用写finally - 格式:
A a = new A()B b = new B();
try(a;b){
可能会产出异常的代码
}catch(异常类变量 变量名){
异常的处理逻辑
}
- 示例代码
package com.svt.io.writer;
import java.io.*;
public class WriterDemo06JDK9 {
/**
* JDK9新特性try的前边可以定义流对象
* 在try后边的()中可以直接引入流对象的名称(变量名)
* 在try代码执行完毕之后,流对象也可以释放掉,不用写finally
* 格式:
* A a = new A()B b = new B();
* try(a;b){
* 可能会产出异常的代码
* }catch(异常类变量 变量名){
* 异常的处理逻辑
* }
*
*
* 写的是对的 但我是JDK8 所以用不了JDK9的新特性
*/
public static void main(String[] args) throws FileNotFoundException {
//1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("F:\\DELL\\dellStudy\\06-IO流\\02-学习资料\\学习笔记\\day20_IO流02\\资料\\转换流的图解.png");
//2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
FileOutputStream fos = new FileOutputStream("F:\\DELL\\DELLlianxi\\作业\\06IO流\\转换流的图解.png");
//一次读取一个字节写入一个字节的方式
//3.使用字节输入流对象中的方法read读取文件
/*try (fis;fos){
int len=0;
while ((len=fis.read())!=-1){
//4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
fos.write(len);
}
} catch(IOException e){
System.out.println(e);
}*/
}
}
版本是1.9的可以试试这个新特性
五、缓冲流
5.1 字节缓冲流
-
字节缓冲流介绍
- 在基本流对象基础上创建而来 是对基本流对象的增强
- lBufferOutputStream:该类实现缓冲输出流.通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
- lBufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组.当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
-
构造方法:
方法名 说明 BufferedOutputStream(OutputStream out) 创建字节缓冲输出流对象 BufferedInputStream(InputStream in) 创建字节缓冲输入流对象 -
示例代码
public class BufferStreamDemo {
public static void main(String[] args) throws IOException {
//字节缓冲输出流:BufferedOutputStream(OutputStream out)
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\bos.txt"));
//写数据
bos.write("hello\r\n".getBytes());
bos.write("world\r\n".getBytes());
//释放资源
bos.close();
//字节缓冲输入流:BufferedInputStream(InputStream in)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("myByteStream\\bos.txt"));
//一次读取一个字节数据
// int by;
// while ((by=bis.read())!=-1) {
// System.out.print((char)by);
// }
//一次读取一个字节数组数据
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
//释放资源
bis.close();
}
}
5.2 字节缓冲流复制视频
-
案例需求
把“E:\svt\字节流复制图片.avi”复制到模块目录下的“字节流复制图片.avi”
-
实现步骤
- 根据数据源创建字节输入流对象
- 根据目的地创建字节输出流对象
- 读写数据,复制视频
- 释放资源
-
代码实现
public class CopyAviDemo {
public static void main(String[] args) throws IOException {
//复制视频
// method1();
method2();
}
//字节缓冲流一次读写一个字节数组
public static void method2() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\svt\\字节流复制图片.avi"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\字节流复制图片.avi"));
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1) {
bos.write(bys,0,len);
}
bos.close();
bis.close();
}
//字节缓冲流一次读写一个字节
public static void method1() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\svt\\字节流复制图片.avi"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\字节流复制图片.avi"));
int by;
while ((by=bis.read())!=-1) {
bos.write(by);
}
bos.close();
bis.close();
}
}
5.3 字符缓冲流
-
字符缓冲流介绍
-
BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途
-
BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途
-
-
构造方法
方法名 说明 BufferedWriter(Writer out) 创建字符缓冲输出流对象 BufferedReader(Reader in) 创建字符缓冲输入流对象 -
代码演示
public class BufferedStreamDemo01 {
public static void main(String[] args) throws IOException {
//BufferedWriter(Writer out)
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\bw.txt"));
bw.write("hello\r\n");
bw.write("world\r\n");
bw.close();
//BufferedReader(Reader in)
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\bw.txt"));
//一次读取一个字符数据
// int ch;
// while ((ch=br.read())!=-1) {
// System.out.print((char)ch);
// }
//一次读取一个字符数组数据
char[] chs = new char[1024];
int len;
while ((len=br.read(chs))!=-1) {
System.out.print(new String(chs,0,len));
}
br.close();
}
}
5.4 字符缓冲流特有功能
-
方法介绍
BufferedWriter:
方法名 说明 void newLine() 写一行行分隔符,行分隔符字符串由系统属性定义 BufferedReader:
方法名 说明 String readLine() 读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null -
代码演示
public class BufferedStreamDemo02 {
public static void main(String[] args) throws IOException {
//创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\bw.txt"));
//写数据
for (int i = 0; i < 10; i++) {
bw.write("hello" + i);
//bw.write("\r\n");
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
//创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\bw.txt"));
String line;
while ((line=br.readLine())!=null) {
System.out.println(line);
}
br.close();
}
}
5.5 字符缓冲流对文本排序
- 案例需求
对文本的内容进行排序按照(1,2,3…)顺序排序
3.侍中、侍郎郭攸之、费讳、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、讳、允等之慢,以彰其咎;陛下亦宜自谋,以咨善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之日能,是以众议举宠为督。愚以为营中之事,悉以咨之必能使行阵和睦,优劣得所。
2.宫中府中,俱为一体,陟罚减否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
1.先帝创业未半而中道崩胆,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠速之路也。
9.今当远离,临表涕零,不知所言。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾爱,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临期寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛今南方已定,兵甲已足,当奖率三军,北定中原,庶竭弩钝,携除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠些下之职分也。至于斟酌损益,进尽忠言,则攸之、讳、允之任也。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
- 实现步骤
1.创建一个HashMap集合对象,key:存储每行文本的序号(1,2,3,…);value:存储每行的文本
2.创建字符缓冲输入流对象,构造方法中绑定字符输入流
3.创建字符缓冲输出流对象,构造方法中绑定字符输出流
4.使用字符缓冲输入流中的方法readline,逐行读取文本
5.对读取到的文本进行切割,获取行中的序号和文本内容
6.把切好的序号和文本的内容存储到HashMap集合中(key序号是有序的,会自动排序1,2,3,4…
7.遍历HashMap集合,获取每一个键值对
8.把每一个键值对,拼接为一个文本行
9.把拼接好的文本,使用字符缓冲输出流中的方法wirite,写入到文件中
10.释放资源 - 示例代码
package com.svt.buffered;
import java.io.*;
import java.util.HashMap;
/**
* 练习:
* 对文本的内容进行排序按照(1,2,3....)顺序排序
* 分析:
* 1.创建一个HashMap集合对象,key:存储每行文本的序号(1,2,3,..);value:存储每行的文本
* 2.创建字符缓冲输入流对象,构造方法中绑定字符输入流
* 3.创建字符缓冲输出流对象,构造方法中绑定字符输出流
* 4.使用字符缓冲输入流中的方法readline,逐行读取文本
* 5.对读取到的文本进行切割,获取行中的序号和文本内容
* 6.把切好的序号和文本的内容存储到HashMap集合中(key序号是有序的,会自动排序1,2,3,4..
* 7.遍历HashMap集合,获取每一个键值对
* 8.把每一个键值对,拼接为一个文本行
* 9.把拼接好的文本,使用字符缓冲输出流中的方法wirite,写入到文件中
* 10.释放资源
*/
public class BufferedDemo01 {
public static void main(String[] args) throws IOException {
//1.创建一个HashMap集合对象,key:存储每行文本的序号(1,2,3,..);value:存储每行的文本
HashMap<String, String> hm = new HashMap<>();
//2.创建字符缓冲输入流对象,构造方法中绑定字符输入流
BufferedReader br = new BufferedReader(new FileReader("ioProject\\zgl.txt"));
//3.创建字符缓冲输出流对象,构造方法中绑定字符输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("ioProject\\out.txt"));
//4.使用字符缓冲输入流中的方法readline,逐行读取文本
String line;
while ((line=br.readLine())!=null){
//5.对读取到的文本进行切割,获取行中的序号和文本内容
String[] split = line.split("\\.");
//6.把切好的序号和文本的内容存储到HashMap集合中(key序号是有序的,会自动排序1,2,3,4..
hm.put(split[0],split[1]);
}
//7.遍历HashMap集合,获取每一个键值对
for (String key : hm.keySet()) {
String value=hm.get(key);
//8.把每一个键值对,拼接为一个文本行
line=key+"."+value;
//9.把拼接好的文本,使用字符缓冲输出流中的方法wirite,写入到文件中
bw.write(line);
//写个换行
bw.newLine();
}
//10.释放资源
bw.close();
br.close();
}
}