JavaIO流二
JavaIO流二
IO流的概述和分类
- IO流的概述:
- IO:输入/输出(Input/Output)
- 流:是一种抽象概念:是对数据传输的总称也就是说数据在设备间的传输称为流,流的本质就是数据传输
- IO流就是用来处理设备间数据传输问题的
- 常见应用场景:文件复制,文件上传,文件下载
- IO流分类:
- 按照数据的流向
- 输入流:读数据
- 输出流:写数据
- 按照数据类型来分
- 字节流
- 字节输入流、字节输出流
- 字符流
- 字符输出流、字符输入流
- 字节流
- 按照数据的流向
- 一般我们把IO流按照数据类型来分的,而对于能读懂里面内容的可以采用字符流,否则就采用字节流。如果不知使用哪种流,就使用字节流
一、字节流
1.1、字节流写数据
字符流抽象基类
- InputStream:这个抽象类就是表示字节输入流的所有类的超类
- OutputStream:这个抽象类就是表示字节输出流的所有类的超类
- 子类名特点:子类名称都是父类名作为子类名的后缀
FileOutputStream:文件输出流用于将数据写入File
- FileOutputStream(String name):创建文件输出流以指定的名称写入文件
使用字节输出流写数据的步骤:
- 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
- 调用字节输出流对象的写数据方法
- 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
//创建字节输出流对象
FileOutputStream file = new FileOutputStream("java基础语法\\javase.txt");
/*
* FileOutputStream三个功能:
* 1、调用了系统功能创建文件
* 2、创建字节输出流对象
*3、让字节输出流对象指向创建好的文件
* */
//write(int b):将指定的字节写入此文件输出流。
file.write(99);
// file.write(57);
// file.write(57);
//所有IO流都需要释放资源
//close():关闭此文件输出流并释放与此流相关联的任何系统资源。
file.close();
}
1.2、字节流写数据的三种方式
void write(int b) 将指定的字节写入此文件输出流。
void write(byte[] b) 将b.length个字节从指定的字节数组写入此文件输出流。
void write(byte[] b, int off, int len) 将len字节从位于偏移量 off的指定字节数组写入此文件输出流。
public class FileOutputStreamdemo02 {
public static void main(String[] args) throws IOException {
//FileOutputStream(String name):创建文件输出流以指定的名称写入文件。
FileOutputStream fos = new FileOutputStream("java基础语法\\fos.txt");
//下面是上面创建fos.txt文件完整写法
// FileOutputStream fos = new FileOutputStream(new File("java基础语法\\fos.txt"));
//FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件。
// File file = new File("java基础语法\\fos.txt");
// FileOutputStream fos2 = new FileOutputStream(file);
// FileOutputStream fos2 = new FileOutputStream(new File("java基础语法\\fos.txt"));
// fos.write(97);
// fos.write(98);
// fos.write(99);
// fos.write(100);
// fos.write(101);
// byte[] b = {97,98,99,100,101};
//byte[] getBytes() :返回字符串对应的字节数组
byte[] b = "abcde".getBytes();
// fos.write(b);
fos.write(b,0,b.length);
}
}
1.3、字节流写数据的两个问题
- 1、如何实现换行呢?
- 写完数据后,加换行符
- Windows:\r\n
- linux:\n
- mac:\r
- 写完数据后,加换行符
- 2、如何实现追加写入呢?
- public FileOutputStream(String name,boolean append)
- 创建文件输出流以指定的名称写入文件。如果第二个参数为true,则字节将写入文件的末尾而不是开头
public static void main(String[] args) throws IOException {
//创建字节输出流对象
// FileOutputStream fos = new FileOutputStream("Java基础语法\\demo01.txt");
//实现追加写入的方法
FileOutputStream fos = new FileOutputStream("Java基础语法\\demo01.txt",true);
//写入数据
for (int i = 0; i < 10; i++) {
fos.write("hello".getBytes());
//实现换行的方法
fos.write("\n".getBytes());
}
//释放资源
fos.close();
}
1.4、字节流写数据加异常处理
finally:在异常处理时提供finally块来执行所有的清除操作。比如说IO流中的释放资源
特点:被finally控制的语句一定会执行,除非JVM退出FileOutputStreamdemo03
public static void main(String[] args){
// try {
// FileOutputStream fos = new FileOutputStream("Java基础语法\\demo02.txt");
// fos.write("hello".getBytes());
// fos.close();
// }catch (IOException e){
// e.printStackTrace();
// }
//加入finally来实现释放资源
FileOutputStream fos = null;
try {
fos = new FileOutputStream("Java基础语法\\demo02.txt");
fos.write("hello".getBytes());
}catch (IOException e){
e.printStackTrace();
}finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1.5、字节流读数据(一次读一个字节数据)01
FileInputStream:从文件系统中的文件获取输入字节
FileInputStream(String name):通过打开与实际文件的连接来创建一个 `FileInputStream ,该文件由文件系统中的路径名name命名。
public class FileInputStreamdemo01 {
public static void main(String[] args) throws IOException {
//创建字节流输入流对象
FileInputStream fis = new FileInputStream("java基础语法\\demo02.txt");
//调用字节流读数据的方法
//int read():从该输入流读取一个字节的数据
// //第一次读取数据
// int by = fis.read();
// System.out.println(by);
// System.out.println((char)by);
// //第二次读取数据
// int by1 = fis.read();
// System.out.println(by1);
// System.out.println((char)by1);
//上面的操作太过繁琐了
//下面用循环做
// int by = fis.read();
// while(by != -1){
// System.out.print((char)by);
// by=fis.read();
// }
//优化
int by;
while((by=fis.read())!=-1){
System.out.print((char)by);
}
//释放资源
fis.close();
}
}
//-----------------------------------------------------------------------------------------------------
//案例:复制文本文件
public class Demo01 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
FileInputStream fis = new FileInputStream("D:\\test\\javase.txt");
//创建字节输出流对象
FileOutputStream fos = new FileOutputStream("Java基础语法\\javase.txt");
//读写数据
int by;
while((by=fis.read())!=-1){
fos.write(by);
}
//释放资源
fis.close();
fos.close();
}
}
1.6、字节流读数据(一次读一个字节数据数组)02
public class FileInputStreamdemo02 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
FileInputStream fis = new FileInputStream("Java基础语法\\demo02.txt");
//调用字节输入流对象的读数据方法
//int read(byte[] b):从该输入流读取最多 b.length个字节的数据为字节数组
/*
byte[] bys = new byte[5];
//第一次读数据
int len = fis.read(bys);
System.out.println(len);
//String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的 String
// System.out.println(new String(bys));
System.out.println(new String(bys,0,len));
//第二次读数据
len = fis.read(bys);
System.out.println(len);
// System.out.println(new String(bys));
System.out.println(new String(bys,0,len));
//第三次读数据
len = fis.read(bys);
System.out.println(len);
//String(byte[] bytes, int offset, int length):通过使用平台的默认字符集解码指定的字节子阵列来构造新的String
System.out.println(new String(bys,0,len));
*/
/*分析:
* 第一次:hello
* 第二次:\r\nwor
* 第三次:ldwor
* */
byte[] bys = new byte[1024];//1024及其整数倍
int len;
while((len=fis.read(bys))!=-1){
System.out.println(new String(bys,0,len));
}
//释放资源
fis.close();
}
}
//---------------------------------------------------------------------------------------------------------------
//案例:复制图片
public class Demo02 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\test\\AL.png");
FileOutputStream fos = new FileOutputStream("Java基础语法\\AL.png");
byte[] by = new byte[1024];
int len;
while((len=fis.read(by))!=-1){//read位置注意写要读取的对象
fos.write(by,0,len);
}
fis.close();
fos.close();
}
}
1.7、字节缓冲流
- BufferedOutputStream:该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流入字节,而不必为写入的每个字节导致底层系统的调用
- BufferedInputStream:创建BufferedInputStream将创建一个内容缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
构造方法:
- 字节缓冲输出流:
BufferedOutputStream(OutputStream out)
- 字节缓冲输入流:
BufferedInputStream(InputStream in)
为何构造方法所需的是字节流,而不是具体的文件或者路径?
- 这是因为字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作
public class BufferedStreamdemo {
public static void main(String[] args) throws IOException {
// FileOutputStream fos = new FileOutputStream("Java基础语法\\fos.txt");
//创建字节缓冲输出流
// BufferedOutputStream bos = new BufferedOutputStream(fos);
//合并上面两步
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Java基础语法\\fos.txt"));
//写数据
bos.write("hello\r\n".getBytes());
bos.write("world\r\n".getBytes());
//释放资源
bos.close();
//创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("Java基础语法\\\\fos.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();
}
}
//-------------------------------------------------------------------------------------------------------------
//案例:复制视频
public class Demo03 {
public static void main(String[] args) throws IOException{
//记录开始时间
long startTime = System.currentTimeMillis();
//复制视频
// method1();//用时77834毫秒
// method2();//用时99毫秒
// method3();//用时321毫秒
method4();//用时44毫秒
//记录结束时间
long endTime = System.currentTimeMillis();
System.out.println("共耗时"+(endTime-startTime)+"毫秒");
}
//字节缓冲流一次读写一个字节数组
public static void method4() throws IOException{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\test\\deng.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Java基础语法\\deng.mp4"));
byte[] bys = new byte[1024];
int len;
while((len=bis.read(bys))!=-1){
bos.write(bys,0,len);
}
bis.close();
bos.close();
}
//字节缓冲流一次读写一个字节
/*
public static void method3() throws IOException{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\test\\deng.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Java基础语法\\deng.mp4"));
int by;
while((by=bis.read())!=-1){
bos.write(by);
}
bis.close();
bos.close();
}*/
//基本字节流一次读写一个字节数组
/*
public static void method2() throws IOException{
FileInputStream fis = new FileInputStream("D:\\test\\deng.mp4");
FileOutputStream fos = new FileOutputStream("Java基础语法\\deng.mp4");
byte[] bys = new byte[1024];
int len;
while((len=fis.read(bys))!=-1){
fos.write(bys,0,len);
}
fis.close();
fos.close();
}*/
//基本字节流一次读写一个字节
//这种方式运行起来是非常慢的
/*
public static void method1() throws IOException {
FileInputStream fis = new FileInputStream("D:\\test\\deng.mp4");
FileOutputStream fos = new FileOutputStream("Java基础语法\\deng.mp4");
int by;
while((by=fis.read())!=-1){
fos.write(by);
}
fis.close();
fos.close();
}*/
}
二、字符流
2.1、字符流的一些基本内容
- 因为字节流操作中文不是特别的方便,所以Java就提供字符流
- 字符流=字节流+编码表
- 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
- 采用何种规则编码,就要采用对应的规则解码,否则就会出现乱码
2.2、字符串和字符流中的编码解码问题
编码:
- byte[] getBytes():使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中
- byte[] getBytes(String charsetName):使用命名的字符集将此
String
编码为字节序列,将结果存储到新的字节数组中
解码:
-
String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String
-
String(byte[] bytes, String charsetName):通过指定的字符集解码指定的字节数组来构造新的String
字符流的抽象基类
- Reader:字符输入流的抽象类
- Writer:字符输出流的抽象类
字符流中和编码解码问题相关的两个类:
- InputStreamReader
- OutPutStreamWriter
//字符串中的编码解码问题
public class StringDemo01 {
public static void main(String[] args) throws UnsupportedEncodingException {
//定义一个字符串
String s = "中国";
//byte[] getBytes():使用平台的默认字符集将此 String编码为字节序列,将结果存储到新的字节数组中
byte[] bys = s.getBytes();//[-28, -72, -83, -27, -101, -67]
//byte[] getBytes(String charsetName):使用命名的字符集将此 `String`编码为字节序列,将结果存储到新的字节数组中
// 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(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String
// String ss = new String(bys);//结果为中国
//String(byte[] bytes, String charsetName):通过指定的字符集解码指定的字节数组来构造新的String
// String ss = new String(bys,"UTF-8");//结果为中国
String ss = new String(bys,"GBK");//乱码了
System.out.println(ss);
}
}
//字符流中的编码解码问题
public class CharacterStreamDemo01 {
public static void main(String[] args) throws IOException {
//OutputStreamWriter(OutputStream out):创建一个使用默认字符编码的OutputStreamWriter
//OutputStreamWriter(OutputStream out, String charsetName):创建一个使用命名字符集的OutputStreamWriter
// FileOutputStream fos = new FileOutputStream("Java基础语法\\osw.txt");
// OutputStreamWriter osw = new OutputStreamWriter(fos);
//把上面两句合并写
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Java基础语法\\osw.txt"));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Java基础语法\\osw.txt"),"UTF-8");
osw.write("中国");
osw.close();
// InputStreamReader(InputStream in):创建一个使用默认字符集的InputStreamReader。
// InputStreamReader(InputStream in, String charsetName):创建一个使用命名字符集的InputStreamReader。
InputStreamReader isr = new InputStreamReader(new FileInputStream("Java基础语法\\osw.txt"),"UTF-8");
//一次读取一个字符数据
int ch;
while ((ch=isr.read())!=-1){
System.out.print((char)ch);
}
}
}
2.3、字符流写数据的5种方式
public class OutputStreamWriterdemo {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Java基础语法\\osw.txt"));
//void writer(int c):写一个字符的
// osw.write(97);
// //void flush():刷新流
// osw.flush();
// osw.write(98);
// osw.flush();
// osw.write(99);
//void writer(char[] cbuf):写一个字符数组
char[] chs = {'a','b','c','d','e'};
// osw.write(chs);
//void writer(char[] cbuf,int off,int len):写一个字符数组的一部分
// osw.write(chs,0,chs.length);
// osw.write(chs,1,3);
//void writer(String str):写一个字符串
// osw.write("abcde");
//void writerString str,int off,int len):写一个字符串的一部分
osw.write("abcde",1,3);
osw.close();
}
}
2.4、字符流读数据的2种方式
-
int read():读一个字符
-
int read(char[] cbuf, int offset, int length):将字符读入数组的一部分。
public class InputStreamdemo {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("Java基础语法\\osw.txt"));
//int read():读一个字符
// int ch;
// while((ch=isr.read())!=-1){
// System.out.print((char)ch);
// }
//int read(char[] cbuf, int offset, int length):将字符读入数组的一部分。
char[] chs = new char[1024];
int len;
while((len=isr.read(chs))!=-1){
System.out.print(new String(chs,0,len));
}
//释放资源
isr.close();
}
}
2.5、字符流复制java文件
public class Demo01 {
public static void main(String[] args) throws IOException {
//创建输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("Java基础语法\\CharacterStreamDemo01.java"));
//创建输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Java基础语法\\Copy.java"));
//读写数据,复制文件
//一次读取一个字符
// int ch;
// while((ch=isr.read())!=-1){
// osw.write(ch);
// }
//一次读取一个字符数组
char[] chs = new char[1024];
int len;
while((len=isr.read(chs))!=-1){
osw.write(chs,0,len);
}
//释放资源
isr.close();
osw.close();
}
}
//改进版,所需用到InputStreamReader和OutputStreamWriter的子类
//FileReader:用于读取字符文件的便捷类
//FileWriter:用于写入字符文件的便捷类
//FileReader(String fileName):创建一个新的 FileReader ,给定要读取的文件的名称。
//FileWriter(String fileName):构造一个给定文件名的FileWriter对象。
public class Demo02 {
public static void main(String[] args) throws IOException {
//创建字符输入流对象
FileReader fr = new FileReader("Java基础语法\\CharacterStreamDemo01.java");
//创建字符输出流对象
FileWriter fw = new FileWriter("Java基础语法\\Copy.java");
//读取数据,复制文件
//一次读取一个字符
// int ch;
// while((ch=fr.read())!=-1){
// fw.write(ch);
// }
//一次读取一个字符数组
char[] chs = new char[1024];
int len;
while((len=fr.read(chs))!=-1){
fw.write(chs,0,len);
}
//释放资源
fr.close();
fw.close();
}
}
2.6、字符缓冲流
-
BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。
-
BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取。可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。
构造方法:
- BufferedWriter(Writer out):创建使用默认大小的输出缓冲区的缓冲字符输出流。
- BufferedReader(Reader in): 创建使用默认大小的输入缓冲区的缓冲字符输入流。
public class BufferedStreamdemo {
public static void main(String[] args) throws IOException {
// FileWriter fw = new FileWriter("Java基础语法\\bw.txt");
// BufferedWriter bw = new BufferedWriter(fw);
//合并
// BufferedWriter bw = new BufferedWriter(new FileWriter("Java基础语法\\bw.txt"));
// bw.write("hello\r\n");
// bw.write("js");
// bw.close();
BufferedReader br = new BufferedReader(new FileReader("Java基础语法\\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();
}
}
//案例:利用字符缓冲流来复制java文件
public class demo03 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("Java基础语法\\CharacterStreamDemo01.java"));
BufferedWriter bw = new BufferedWriter(new FileWriter("Java基础语法\\Copy.java"));
// int ch;
// while((ch=br.read())!=-1){
// bw.write(ch);
// }
char[] chs = new char[1024];
int len;
while((len=br.read(chs))!=-1){
bw.write(chs,0,len);
}
br.close();
bw.close();
}
}
2.7、字符缓冲流特有功能
- BufferedWriter
- void newLine():写一行行分隔符,行分隔符字符串由系统属性定义
- BufferedReader
- public String readLine():读一行文字,结构包含行的内容的字符串,不包括任何终止字符,如果流的结尾已经到达,则为null
public class BufferedStreamdemo02 {
public static void main(String[] args) throws IOException {
// BufferedWriter bw = new BufferedWriter(new FileWriter("Java基础语法\\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("Java基础语法\\bw.txt"));
String ch;
while((ch=br.readLine())!=null){
System.out.println(ch);
}
br.close();
}
}
//案例:利用字符流特有功能复制java文件
public class demo04 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("Java基础语法\\CharacterStreamDemo01.java"));
BufferedWriter bw = new BufferedWriter(new FileWriter("Java基础语法\\Copy.java"));
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
bw.close();
}
}