1-IO流
I:input(输入 | 读取); O:output(输出 | 写出)
读取数据,和写出数据
1.1-作用
-
用于数据的传输
文件拷贝:
1.文件上传(读取本地文件,将数据写到服务器)
2.文件下载(读取服务器文件,将数据写到本地)
....
1.2-分类
1.按流向分:
-
输入流
-
输出流
2.按类型分:
-
字节流:万能流,计算机中任何一个文件或数据,底层都是以字节的形式进行存储
注意:字节流虽然可以操作任意类型的文件,但是操作纯文本文件的时候,有可能会出现中文乱码问题
-纯文本文件:用记事本打开,可以直接看得懂的文件
-
字符流:用于读取纯文本文件,能够保证没有中文乱码
1.3-IO流的体系结构
2-字节流
2.1-字节流写出数据
作用:用来写数据
2.1.1-FileOutputStream
类
构造方法
-
public FileOutputStream(File file)
: 创建一个字节输出流 , 向指定File对象的文件中写入内容 -
public FileOutputStream(File file, boolean append)
: 第二个参数为true, 表示追加写数据 -
public FileOutputStream(String name)
: 创建一个字节输出流 , 向指定名称的文件中写入内容 -
public FileOutputStream(String name, boolean append)
: 第二个参数为true, 表示追加写数据
成员方法
-
public void write(int b )
: 将指定字节写入到文件中 -
public void write(byte[] b)
: 将字节数组中的字节写入到文件中 -
public void write(byte[] b, int off, int len)
: 将字节数组的一部分写到文件中 , b代表的是字节数组, off代表开始索引, len代表个数 -
public void close()
: 释放资源 , 断开流与文件之间的联系
注意 : 字节输出流是否可以写一个字符串 ?
-
-String类 :
public byte[] getBytes();
字节流常见的两个问题
-
换行 :
windows : \r\n 举例 : 输出流对对象.write("\r\n".getBytes())
mac : \r
linux : \n
-
追加 :
public FileOutputStream(String file, boolean append)
: 第二个参数为true, 表示追加写数据注意 : 如果构造方法没有打开追加写入的开关, 执行构造会把文件中内容清空
示例
JDK7之前:
package com.lyl.io.output;
import java.io.FileOutputStream;
import java.io.IOException;
public class IODemo3 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("day10\\a.txt", true);
fos.write("哈哈哈".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
//目的:就算程序死了,流也要关,所以放在finally里,finally里的代码是一定会执行的
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
JDK7之后
package com.lyl.io.output;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class IODemo4 {
public static void main(String[] args) throws FileNotFoundException {
//将需要关流的对象放在try的小括号里,这样就会自动调用close方法了
try (FileOutputStream fos = new FileOutputStream("day10\\a.txt");){
fos.write("JDK7之后的方法".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.2-字节流读取数据
作用:用来读数据
2.2.1-FileInputStream
类
构造方法
-
public FileInputStream(File file)
: 创建一个字节输入流对象, 从指定File对象的文件中读取数据 -
public FileInputStream(String name)
: 创建一个字节输入流对象, 从指定名称的文件中读取数据
成员方法
-
public int read()
: 读取一个字节数据并返回 , 读到末位返回 -1 -
public int read(byte[] b)
: 把数据读取字节数组中, 并返读到数据的个数返回
读取方式 : 一次读取一个数据 ;一次读取一个字节数组
案例 : 字节流拷贝文件
package com.lyl.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFileTest1 {
public static void main(String[] args) throws IOException {
//1,创建字节输入流对象,管理数据源
FileInputStream fis = new FileInputStream("day10\\a.txt");
//2,创建字节输出流对象,管理数据目的
FileOutputStream fos = new FileOutputStream("day10\\copy.txt");
//3,一个一个读,一个一个写
int i;
while ((i = fis.read())!=-1){
fos.write(i);
}
//4,关闭流释放资源
fis.close();
fos.close();
}
}
package com.lyl.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFileTest2 {
public static void main(String[] args) throws IOException {
//1,创建字节输入流对象,管理数据源
FileInputStream fis = new FileInputStream("day10\\a.txt");
//2,创建字节输出流对象,管理数据目的
FileOutputStream fos = new FileOutputStream("day10\\copy2.txt");
byte[] bys = new byte[2048];
//3.读写操作,一次读取一个数组
int i;
while ((i = fis.read(bys)) != -1){
fos.write(bys,0,i);
}
//4,关闭流释放资源
fis.close();
fos.close();
}
}
3-字节缓冲流
介绍 : 提高读写效率
3.1-输入
构造方法 : public BufferedInputStream(InputStream in)
: 创建一个缓冲输入流对象,参数是基本的字节输入流
3.2-输出
构造方法 : public BufferedOutputStream(OutputStream out)
: 创建一个缓冲输出流对象, 参数是基本的字节输出流
3.3-案例 : 拷贝文件, 测试效率
测试程序大小:29.9 MB (31,367,480 字节)
普通字节流, 单个字节拷贝
package com.lyl.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFileTest1 {
public static void main(String[] args) throws IOException {
//测试程序大小:29.9 MB (31,367,480 字节)
FileInputStream fis = new FileInputStream("D:\\test.exe");
FileOutputStream fos = new FileOutputStream("E:\\copy.exe");
//开始时间
long start = System.currentTimeMillis();
//一个一个读,一个一个写
int i;
while ((i = fis.read())!=-1){
fos.write(i);
}
fis.close();
fos.close();
//结束时间
long end = System.currentTimeMillis();
//打印时间差,计算耗时
System.out.println(end - start);
}
}
输出结果:
131855
-
耗时131855毫秒
普通字节流 + 自定义数组拷贝
package com.lyl.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFileTest2 {
public static void main(String[] args) throws IOException {
//1,创建字节输入流对象,管理数据源
FileInputStream fis = new FileInputStream("D:\\test.exe");
//2,创建字节输出流对象,管理数据目的
FileOutputStream fos = new FileOutputStream("E:\\copy.exe");
//开始时间
long start = System.currentTimeMillis();
//底层源码数组大小为8192,我们让其保持一致
byte[] bys = new byte[8192];
//3.读写操作,一次读取一个数组
int i;
while ((i = fis.read(bys)) != -1){
fos.write(bys,0,i);
}
//4,关闭流释放资源
fis.close();
fos.close();
//结束时间
long end = System.currentTimeMillis();
//打印时间差,计算耗时
System.out.println(end - start);
}
}
输出结果:
43
-
耗时225毫秒
缓冲流单个字节拷贝
package com.lyl.io;
import java.io.*;
public class CopyFileTest3 {
public static void main(String[] args) throws IOException {
//缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\test.exe"));
//缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\copy.exe"));
long start = System.currentTimeMillis();
int i;
while ((i = bis.read()) != -1) {
bos.write(i);
}
bis.close();
bos.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
输出结果:
957
-
耗时957毫秒
缓冲流 + 自定义数组拷贝
package com.lyl.io;
import java.io.*;
public class CopyFileTest4 {
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\test.exe"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\copy.exe"));
long start = System.currentTimeMillis();
//自定义数组
byte[] bys = new byte[8192];
int i;
while ((i = bis.read(bys)) != -1) {
bos.write(bys,0,i);
}
bis.close();
bos.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
输出结果:
53
-
耗时53毫秒
结论
首选普通字节流 + 自定义数组拷贝更好,因为代码少,效率高,还是自己编写的,逻辑更清晰
注意事项
缓冲流不具备读写功能, 只提供缓冲区, 读写操作, 还是需要依赖于基本的流
4-过渡知识 - 字符集
字符集 : 说的就是编码表
编码表 : 计算机中, 字符到字节的一套对应关系
-
ASCII 码表
-
问题 : 计算机中, 存储 a 字符是怎么存的 ?
-
思考 : 计算机中存储数据的单位是什么 ?
字节
-
思考 : 字节再往下是什么 ?
二进制
所以, 计算机存储任何数据, 都是以二进制的形式进行存储
需要记住的结论
我们在文件中存储的字符, 实际上都有一份数值的表示形式 !
4.1-常见的编码表
-
ASCII : 所有码表都囊括了 ASCII 码表
-
GBK : 中国的码表, 每个中文, 占用2个字节
-
Unicode - UTF-8:万国码, 每个中文, 占用3个字节
4.2-编码-解码
概念介绍 :
编码 : 将看得懂的, 变成看不懂的 (字符转字节)
解码 : 将看不懂的, 变成看得懂的 (字节转字符)
编码
package com.lyl.test;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
String s = "你好,你好";
byte[] bytes = s.getBytes();
System.out.println(Arrays.toString(bytes));
}
}
输出结果:
[-28, -67, -96, -27, -91, -67, 44, -28, -67, -96, -27, -91, -67]
解码
package com.lyl;
public class Test2 {
public static void main(String[] args) {
byte[] bytes = {-28, -67, -96, -27, -91, -67, 44, -28, -67, -96, -27, -91, -67};
String s = new String(bytes);
System.out.println(s);
}
}
输出结果:
你好,你好
字符串类 String 的编码解码
4.3-需要重点记住的
如果今后出现了乱码 : 查看编码和解码的方式是否一致
GBK : 每个中文占用2个字节
UTF-8 : 每个中文占用3个字节
英文, 数字, 标点符号, 都占用1个字节
中文的字节表示形式, 第一个肯定是负数
5-IO流-字符流
字符流应用:字节流虽然可以操作任意类型的文件,但是读中文时,可能会出现乱码,字符流就可以解决读写过程中出现乱码的问题
5.1-字符流组成
字节流 + 编码表
5.2-字符流方法
读数据方法:
public int read()
:一次读取一个字符
public int read(char[] cbuf)
:一次读取一个字符数组
5.3-分类
FileReader
(字符输入流)
概述 : 用来读取字符文件的便捷类
构造方法:public FileReader(String fileName)
: 据给定的文件名构造一个FileReader对象
package com.lyl.reader;
import java.io.FileReader;
import java.io.IOException;
public class ReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("day10\\a.txt");
char[] chars = new char[1024];
int len;
while ((len = fr.read(chars)) != -1) {
String s = new String(chars, 0, len);
System.out.println(s);
}
}
}
a.txt 中的内容:FileReader读取字符文件...展示
输出结果:
FileReader读取字符文件...展示