IO流认识一下:
根据数据流向进行分类:
????????输入流(其他设备->内存) ????????输出流:(内存->其他设备)
根据数据流向单位进行分类: ????????字节流:输入输出以字节为单位 ????????字符流:输入输出以字符为单位
上面俩俩组合后就是IO流的4大基类,这4个都是抽象类
字节输入流 InputStream 字节输出流 OutputStream 字符输入流 ?Reader 字符输出流 ?Writer
文件字节输出流 FileOutputStream类 java.io
解:针对文件以字节为单位进行输出操作的工具类。
FileOutputStream类构造器?? ? ? FileOutputStream(File file)? ? ? FileOutputStream(File file, boolean append)? ? ? FileOutputStream(String name) //指定一个相对路径,往哪个里输出。 ? ? FileOutputStream(String name, boolean append) //append为true则开启文件续写
FileOutputStream类方法 void write(int b) ?//以单字节输出fos.Write(97); void write(byte[] b) ?//以单个字节数组为单位输出 ?fos.Write("尚硅谷".getBytes()) void write(byte[] b, int off, int len) ?//以指定范围的字节数组为单位进行输出,off是起始索引,len是长度 void close() ?//fos.close()关闭流资源
代码小Demo:
public class ExceptionDemo {
public static void main(String[] args) throws ParseException, IOException {
FileOutputStream fos = new FileOutputStream("a.txt");
//以单个字节方式写出到文件a.txt
fos.write(73);
//以字节数组方式写出到文件a.txt
byte[] bytes={' ','l','o','v','e',' '};
fos.write(bytes);
//以字节数组方式写出到文件a.txt
byte[] bytes2 = "龙".getBytes(StandardCharsets.UTF_8);
fos.write(bytes2,0,bytes2.length);
fos.close();
}
}
windows下回车换行命令"\r\n"
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("a.txt");
fos.write("小".getBytes(StandardCharsets.UTF_8));
fos.write("\r\n".getBytes());//回车换行命令,回车换行是俩个命令
fos.write("羽".getBytes(StandardCharsets.UTF_8));
fos.write("\r\n".getBytes());//回车换行命令
fos.write("毛".getBytes(StandardCharsets.UTF_8));
fos.close();
}
}
效果:
输出流的续写功能 输出流在没有打开续写开关时,都会创建一个新的文件覆盖以前的文件。在构造器中打开文件续写开关,默认续写功能关闭 FileOutputStream(String name, boolean append) //append为true则开启文件续写
文件字节输入流 ?FileInputStream java.io 解:针对文件以字节为单位进行输入(读取)操作的工具类。
FileInputStream构造器: FileInputStream(File file)? FileInputStream(String name)?
FileInputStream方法 public void close() public int read()//返回读到的数据字节;如果已到达文件末尾,则返回 -1 public int read(byte[] b)//返回读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回 -1。?
循序渐进大法
1.假设a.txt文件里只有abc三个字母,以单个字节读入
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
//创建文件字节输入流对象
FileInputStream fis = new FileInputStream("a.txt");
//假设a.txt文件里只有abc三个字母,以单个字节读入
System.out.println(fis.read());//读到a-97
System.out.println(fis.read());//读到b-98
System.out.println(fis.read());//读到c-99
System.out.println(fis.read());//读不到,返回-1
}
}
2.坑爹代码,这里每次循环读了2次,故会读的很是不如意。。。
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
//创建文件字节输入流对象
FileInputStream fis = new FileInputStream("a.txt");
//假设a.txt文件里只有abc三个字母,以单个字节读入
//坑爹代码,这里每次循环读了俩次,故会报错
while(fis.read()!=-1){
System.out.println(fis.read());
}
}
}
?3.FileInputStream单个字节地正确的读文件,应该这个样子写
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
//假设a.txt文件里只有abc三个字母,以单个字节读入
int len;
while((len=fis.read())!=-1){
//这里len是读取到的单个字节
System.out.println(len);
}
//关闭资源
fis.close();
}
}
4.以字节数组的方式正确的读取文件
这里byte数组长度我们一般给的值是8192,fis.read()之后,byte数组的内容都在变化。把读的数据放到这个byte数组。
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
print();
}
public static void print() throws IOException {
// 创建文件字节输入流对象
FileInputStream fis=new FileInputStream("a.txt");
// 来个小推车 abc
byte[] bytes=new byte[2];
int len;
while((len=fis.read(bytes))!=-1){
System.out.println("len="+len);//len是读取到的数据个数分别打印2,1
System.out.println("读取到的内容="+new String(bytes,0,len));
System.out.println("变换的byte数组:"+ Arrays.toString(bytes));
System.out.println("============");
}
}
}
文件【图片】的复制:一边读一边写
//以字节数组方式复制图片
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
print();
}
public static void print() throws IOException {
FileInputStream fis = new FileInputStream("girl.jpg");
FileOutputStream fos = new FileOutputStream("girl_copy.jpg");
/* byte数组大小
1、文件的平均单位根据文件进行制定
2、没有指定,约定俗称8192,8KB*/
byte[] bytes = new byte[8192];
int len;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
// 关闭资源的原则,先开后关,后开先关
fos.close();
fis.close();
}
}
字符流的学习目的
使用字节流读取含有中文的文本文件时,会先将中文字符拆分为字节,进行读写操作,再将拆分后的字节进行重新组合。
字符流读写的时候,不会将字符拆分,直接以字符为单位(不管是中文还是英文,都是一个字符)
- 文件字节流:用于读写音频、视频、图片,pdf属于图片类。
- 文件字符流:用于读写文本文件。
文件字符输入流 FileReader ?java.io? 解:针对文件以字符为单位进行输入操作的工具类
构造器
FileReader(File file)? FileReader(String fileName)?
方法: public void close() public int read()//读取单个字符 public int read(char[] cbuf)//
1、字符流以单个字符读取
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
FileReader fr=new FileReader("a.txt");
// 以单个字符读取
int len;
while((len=fr.read())!=-1){
char c=(char) len;
System.out.println(c);
}
fr.close();
}
}
2、字符流以单个字符数组读取
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("a.txt");
// 以单个字符数组读取
char[] chars = new char[8192];
int len;
while ((len = fr.read(chars)) != -1) {
System.out.println(len);//6
System.out.println(new String(chars, 0, len));//XYM小羽毛
}
fr.close();
}
}
?
FileWriter 文件字符输出流 java.io 解:针对文件以字符为单位进行输出操作的工具类
构造器: FileWriter(File file)? FileWriter(File file, boolean append)? FileWriter(String fileName) FileWriter(String fileName, boolean append)?
方法: public void close();//关闭此流之前调用flush() public void flush();
public void write(int c);//写单个字符 public void write(char cbuf);//写单个字符数组 public void write(char cbuf,int off,int len);//写单个字符数组,指定范围 public void write(String str); public void write(String str,int off,int len);//
flush :刷新缓冲区,流对象可以继续使用。 close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了
1、以单个字符,字符数组,字符串输出到文件
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
FileWriter fw=new FileWriter ("a.txt");
// 以单个字符输出
fw.write(97);
fw.write(27801);//写汉字沙
// 以字符数组
fw.write("abc".toCharArray());
// 指定范围字符数组
fw.write("defgk".toCharArray(),0,3);
fw.write("\r\n");//回车换行
// 以字符串方式
fw.write("abc");
// 以指定范围字符串方式
fw.write("defgk",0,3);
//fw.flush();把内存缓冲区的东西写到文本文件中
// 做了两步操作,(1)刷新(2)关闭
fw.close();
}
}
缓冲流:
开了缓冲外挂,可以做高效的读写操作。 缓冲流之所以高效是因为底层封装了一个长度为8192的字节数组。
缓冲字节输入节流 BufferedInputStream java.io 解:针对另外一个字节输入流添加高效输入操作的工具类
构造器: public BufferedInputStream(InputStream in) 方法: public void close(); public int read()// public int read(byte[] b)//
1
缓冲字节输出节流 BufferedOutputStream java.io 解:针对另外一个字节输除流添加高效输出操作的工具类
构造器: public BufferedOutputStream(OutputStream out) 方法: public void close(); public void write(int b);// public void write(byte[] b,int off,int len);//
测试完成211MB的文件复制操作,文件字节流和缓冲字节流效率
结论:在实际开发中往往不会选择缓冲字节流,往往选择长度为8192的字节数组的文件字节流操作,这样会节约很大的空间。
//以单个字节为单位,使用文件字节流读写操作约为80分钟 //以单个字节为单位,使用缓冲字节流读写操作约为12.85秒
//以单个字节数组【1024】为单位,使用文件字节流读写操作约为6.43秒 //以单个字节数组【1024】为单位,使用缓冲字节流读写操作约为1.48秒
//以单个字节数组【8192】为单位,使用文件字节流读写操作约为1.65秒 //以单个字节数组【8192】为单位,使用缓冲字节流读写操作约为1.43秒
//以单个字节数组【1024*1024】为单位,使用文件字节流读写操作约为0.89秒 //以单个字节数组【1024*1024】为单位,使用缓冲字节流读写操作约为0.98秒
缓冲字符输入流 BufferedReader java.io
构造器 public BufferedReader(Reader in) 特有方法 public String readLine()//获取一个文本行,开发中较为常用
1、缓冲字符流一行一行读
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
// 创建缓冲字符输入流
BufferedReader br=new BufferedReader(new FileReader("a.txt"));
String len;
while((len=br.readLine())!=null){
System.out.println(len);//len是读取的一行文字
}
br.close();
}
}
缓冲字符输出流 BufferedWriter java.io
构造器 public BufferedWriter(Writer out) 特有方法 String newLine()//写入一个分隔符
使用缓冲字符输出流可以换行打印
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
// 使用匿名对象创建缓冲字符输出流
BufferedWriter bw= new BufferedWriter(new FileWriter("a.txt"));
// 进行输出操作
bw.write("尚");
// "\r\n"是windows的回车换行
// bw.write("\r\n");
bw.newLine();//标准的换行
bw.write("尚");
bw.close();
}
}
编码和解码:
- ? ? ? 编码:看得懂的内容->字节。
- ? ? ? 解码: 字节->看得懂的内容
当编码和解码的标准不一致,就会出现乱码?
字符集:字符和十进制对应的表格 常见:ASCII,Unicode,GB, ISO-8859【欧洲】
字符编码:字符集在计算机中的存储规则。
ASCII字符集: | ASCII-128字符编码? ASCII-256字符编码? | Unicode字符集: | ? ?UTF-8字符编码 ? ?UTF-16字符编码[java底层] ? ?UTF-32字符编码 | GB字符集: | ? GB2312字符编码 ? GBK字符编码 ? GB18030字符编码 |
转换输入流 InputStreamReader ?java.io 解:是字节流通向字符流的桥梁,使用指定的 charset 读取字节并将其解码为字符
构造器 InputStreamReader(InputStream in)? InputStreamReader(InputStream in, String charsetName)//以指定编码格式读
转换输出流 OutputStreamWriter ?java.io 解:是字符流通向字节流的桥梁,可使用指定的 charset 将要写入流中的字符编码成字节
构造器
OutputStreamWriter(OutputStream out)? OutputStreamWriter(OutputStream out, String charsetName)//以指定编码格式写
指定以哪种方式读取,以哪种方式写入 场景一:用户上传utf-8编码文件。【开发环境utf-8】,下载utf-8的文件。 场景二:用户上传gbk编码文件。【开发环境utf-8】,下载utf-8的文件。 场景三:用户上传utf-8编码文件。【开发环境utf-8】,下载gbk的文件。 场景四:用户上传gbk编码文件。【开发环境utf-8】,下载gbk的文件。
1、乱码问题
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
//FileWriter.txt这个文件是GBK编码的
FileReader fr = new FileReader("FileWriter.txt");
char[] chars=new char[8192];
int len;
while((len=fr.read(chars))!=-1){
System.out.println(new String(chars,0,len));//此时会输出乱码
}
}
}
2、解决乱码问题
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("FileWriter.txt"),"GBK");
char[] chars=new char[8192];
int len;
while((len=isr.read(chars))!=-1){
System.out.println(new String(chars,0,len));//此时会输出乱码
}
}
}
序列化与反序列化
注意:
- 操作的对象的类要实现序列化接口java.io.Serializable?
- 进行多个对象的序列化操作【用集合】,针对集合对象进行序列化和反序列化操作。
- 在序列化和反序列化中,操作对象所在的类文件不能做任何更改。
- transient 瞬时的 如果在进行序列化中的过程中,哪个属性信息不想被序列化,可以用transient修饰。【如敏感信息】
ObjectOutputStream ?对象输出流 ?java.io
解:针对跨项目使用对象实现序列化操作的工具类
构造器: public ObjectOutputStream(OutputStream out)?
方法: writeObject(Object obj)
ObjectInputStream 对象输入流??java.io 解:针对跨项目使用对象实现反序列化(字节-》对象)操作的工具类
- 对于不想进行序列化的变量,使用 transient 关键字修饰。
- transient 只能修饰变量,不能修饰类和方法。
构造器: public ObjectInputStream (InputStream in) 方法: public final Object readObject();//读取对象
序列化与反序列化演示
public class ExceptionDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
method01();
method02();
}
public static void method01() throws IOException {
//序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
Account account = new Account("001",922113212);// Account要实现序列化接口,启动序列化功能。
oos.writeObject(account);
oos.close();
}
public static void method02() throws IOException, ClassNotFoundException {
//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
Account account = (Account)ois.readObject();
System.out.println(account);
ois.close();
}
?控制台打印:
标准输入流 System.in? ? ? BufferedInputStream类型
1、第二种获取键盘录入的方法:通过 BufferedReader
方式一:
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("输入一个字符串");
Scanner sc = new Scanner(System.in);
String s = sc.next();
System.out.println(s);
sc.close();
}
}
键盘录入方式一运行测试:?不尽人意啊!
方式二:
public class ExceptionDemo {
public static void main(String[] args) throws IOException {
System.out.println("输入一个字符串");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
System.out.println(s);
br.close();
}
}
标准输出流 System.out??
PrintStream类 ?打印流 ? ?java.io? 解:针对文本文件进行快速打印。
构造器: PrintStream(String fileName)? 方法: public void print()
public void println()
设置系统的打印流流向,输出到print.txt? ? ?应用场景:日志
System.out
就是
PrintStream
类型的,只不过它的流向是系统规定的,打印在控制台上。不过,既然 是流对象,我们就可以玩一个"
小把戏
"
,改变它的流向。
public class ExceptionDemo {
public static void main(String[] args) throws IOException{
PrintStream ps=new PrintStream("print.txt");
// 重置标准输出流 设置系统的打印流流向,输出到print.txt
System.setOut(ps);
System.out.println("hello");
System.out.println("xiaoyumao");
ps.println("world");//输出到print.txt
ps.close();
}
}
控制台一行没输入:
在print.txt中:
close 关闭资源 1、IO流关闭规则:先开后关,后开先关。 2、实际开发用try...catch..finally。别用throws
IOUtils 中应该要封装8个方法
封装关闭字节输入流的方法
封装关闭字节输出流的方法
封装关闭字节输入流,字节输出流的方法
封装关闭字节输出流,关闭字节输入流的方法
封装关闭字符输入流的方法
封装关闭字符输出流的方法
封装关闭字符输入流,字符输出流的方法
封装关闭字符输出流,关闭字符输入流的方法
//close 关闭资源的工具类
public class IOUtils {
//构造器私有化
private IOUtils(){
}
//封装关闭字节输入流的方法
public static void close(InputStream is) throws IOException {
if(is!=null){
is.close();
}
}
//封装关闭字节输出流的方法
public static void close(OutputStream os) throws IOException {
if(os!=null){
os.close();
}
}
//封装关闭字节输入流,字节输出流的方法
public static void close(InputStream is,OutputStream os) throws IOException {
try{
close(is);
}finally{
close(os);
}
}
//封装关闭字节输出流,关闭字节输入流的方法
public static void close(OutputStream os,InputStream is) throws IOException {
try{
close(os);
}finally{
close(is);
}
}
}
试试看我们的IOUtils,果然帮我们简化了很多的try...catch..finally,一切尽在不言中
public class ExceptionDemo {
public static void main(String[] args) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
// 缓冲流
bis = new BufferedInputStream(new FileInputStream("girl.jpg"));
bos = new BufferedOutputStream(new FileOutputStream("girl_copy.jpg"));
int len;
while ((len = bis.read()) != -1) {
bos.write(len);//写入字节
}
} catch (Exception e) {
} finally {
try {
// 关闭资源的原则,先开后关,后开先关
IOUtils.close(bos, bis);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果:复制了一张图片
|