目录
1.File类
1.1File类概述
a : File类,来自于java.io包, 表示一个文件或者文件夹的路径(就表示一个文件或者文件夹)
b : 路径, 表示文件或者文件夹存在位置的字符串, 举例 : “D:\\abc.txt”
- 绝对路径 : 表示唯一的, 带有根路径的, 没有任何歧义的路径存在, 在windows操作系统中, 绝对路径是带有盘符的路径
D:\\1012系统班
- 相对路径 : 表示路径存在是相对而言, 不是唯一的, 有一些歧义的
a\\123.txt
c : 在eclipse中, 如果给出的文件是一个相对路径, 那么文件的绝对路径就会拼接当前正在操作的项目工程根目录
1.2 File类中的构造方法
1.File(String path) : 将path所表示的文件或者文件夹路径封装到File类型中
2.File(String fu, String zi) : 将fu+zi拼接成一个完整路径, 路径封装到File类型中
3.File(File fu, String zi) : 将File类型的fu + zi拼接成一个完整路径, 路径封装到File类型中
package com.ujiuye.file;
import java.io.File;
public class Demo01_FileConstructor {
public static void main(String[] args) {
String s = "D:\\1012系统班";
File f = new File(s);
System.out.println(f);// D:\1012系统班
File f1 = new File(s,"day01");
System.out.println(f1);// D:\1012系统班\day01
File f2 = new File(f1, "笔记");
System.out.println(f2);// D:\1012系统班\day01\笔记
}
}
1.3 File类新增功能
1. createNewFile() : 当File表示一个文件, 并且文件路径存在, 文件不存在的时候, 此方法新建出一个空的文件, 返回值类型 boolean类型, 创建文件成功返回true
2. mkdir() : 每次只能创建出File类所表示的最后一级文件夹, 如果最后一级文件夹父路径不存在, 创建失败,返回值类型boolean类 型, 创建成功返回true
3. mkdirs() : 每次可以创建一级或者多级文件夹路径, 返回值类型boolean类型, 创建成功返回true
代码
package com.ujiuye.file;
import java.io.File;
import java.io.IOException;
public class Demo02_FileAddMethod {
public static void main(String[] args) throws IOException{
File f = new File("D:\\123.txt");
// createNewFile() : 当File表示的一个文件, 并且文件路径存在, 文件不存在时候, 此方法新建出一个空的文件,
// 返回值类型boolean类型, 创建成功返回true
boolean boo = f.createNewFile();
System.out.println(boo);
File f1 = new File("D:\\a");
// 每次只能创建出File类所表示的最后一级文件夹, 如果最后一级文件夹父路径不存在,创建失败,返回值类型boolean类型, 创建成功返回true
boolean boo1 = f1.mkdir();
System.out.println(boo1);
File f2 = new File("D:\\create\\file\\day01");
// mkdirs() : 每次可以创建一级或者多级文件夹路径, 返回值类型boolean类型, 创建成功返回true
boolean boo2 = f2.mkdirs();
System.out.println(boo2);
}
}
1.4 File类的删除和重命名功能
1. delete() : 删除File所表示文件或者文件夹, 删除成功返回true. 删除失败返回false
注意 : 如果删除的是文件夹, 要求文件夹是空的才能删除, 这是安全保证; delete方法表示直接删除, 不走回收站
2.renameTo(File f): 将方法调用者的file所表示的文件进行重命名
1.参数f的路径与方法调用者路径一致, 只表示修改文件名
2.参数f的路径与方法调用者路径不一致, 先剪切到目标f路径下, 再重命名
package com.ujiuye.file;
import java.io.File;
public class Demo03_FileDeleteAndRename {
public static void main(String[] args) {
File f = new File("D:\\123.txt");
// 1. 直接删除文件, 如果文件真实存在, 删除成功
System.out.println(f.delete());
File f1 = new File("D:\\a");
// 2. 直接删除一个空的文件夹, 删除功能
System.out.println(f1.delete());
File f2 = new File("D:\\create");
// 3. 删除非空文件夹, 删除失败
System.out.println(f2.delete());
File f3 = new File("D:\\aa.txt");
// 4. f3的路径与参数路径一致, 只表示文件重命名
f3.renameTo(new File("D:\\aabbc.txt"));
File f4 = new File("D:\\bb.txt");
// 5. f3的路径与参数路径不一致 , 先将f3表示的文件剪切到目标参数路径下, 再重命名为change.txt
f4.renameTo(new File("D:\\1012系统班\\change.txt"));
}
}
1.5 File类的判断功能
1. exists() : 验证File所表示文件或者文件夹是否真实存在, 如果存在返回true; 否则返回false;
2. isFile() : 验证File所表示的是否是一个文件, 如果是文件返回true; 否则返回false;
3. isDirectory() : 验证File所表示的是否是一个文件夹, 如果是文件返回true; 否则返回false;
package com.ujiuye.file;
import java.io.File;
public class Demo04_FileCheckMethod {
public static void main(String[] args) {
File f = new File("D:\\1012系统班\\change.txt");
//1. exists() : 验证FIle所表示文件或者文件夹是否真实存在, 如果存在返回true; 否则返回false;
System.out.println(f.exists());// true
System.out.println(new File("D:\\hello.java").exists());// false
// 2. isFile() : 验证File所表示的是否是一个文件, 如果是文件返回true; 否则返回false;
System.out.println(f.isFile());
// 3. isDirectory() : 验证File所表示的是否是一个文件夹, 如果是文件返回true; 否则返回false;
System.out.println(f.isDirectory());// false
}
}
1.6 File类的获取功能
1. getAbsolutePath() : 将File类型所表示的文件或者文件夹的绝对路径以字符串的形式进行返回
2. getPath() : 将File类型所封装的文件或者文件夹路径以字符串的形式进行返回
3. getName() : 将File类型所封装的文件或者文件夹路径最后一个部分的名字获取到, 返回String类型名字结果
4. length() : 表示获取File所表示的文件的长度(文件的大小), 以字节为丈量粒度, 返回值类型long类型(注意 : 不能丈量文件夹的 大小, 文件夹数据不能保证正确)
实际场景使用 : 有时, 需要到指定路径下读取文件, 读取文件之前, 需要判断
File f = new File(“D:\\core.txt”);
if( f.exists() && f.length() > 0){
读取文件内容
}
5.list() : 将File所表示的文件夹路径下, 所有的子级别(当前文件夹级别下)的文件和文件夹都获取到, 将获取到结果放置到String[] 中
6.listFiles() : 将File所表示的文件夹路径下, 所有的子级别(当前文件夹级别下)的文件和文件夹都获取到, 将获取到结果放置到 File[]中。
package com.ujiuye.file;
import java.io.File;
import java.util.Arrays;
public class Demo05_FileGetMethod {
public static void main(String[] args) {
File f = new File("D:\\aabbc.txt");
// 1.getAbsolutePath() : 将File类型所表示的文件或者文件夹的绝对路径以字符串的形式进行返回
String path = f.getAbsolutePath();
System.out.println(path);// D:\aabbc.txt
File f1 = new File("123.txt");
System.out.println(f1.getAbsolutePath());// D:\workspace\day16\123.txt
// 2.getPath() : 将File类型所封装的文件或者文件夹路径以字符串的形式进行返回
System.out.println(f.getPath()); // D:\aabbc.txt
System.out.println(f1.getPath());// 123.txt
// 3.getName() : 将File类型所封装的文件或者文件夹路径最后一个部分的名字获取到, 返回String类型名字结果
System.out.println(f.getName());// aabbc.txt
File f2 = new File("D:\\1012系统班\\day01\\笔记");
System.out.println(f2.getName());//笔记
// 4.length() : 表示获取File所表示的文件的长度(文件的大小), 以字节为丈量粒度
System.out.println(f.length());// 10
// 5. list() : 将File所表示的文件夹路径下, 所有的子级别(当前文件夹级别下)的文件和文件夹都获取到,
// 将获取到结果放置到String[]中
String[] arr = f2.list();
System.out.println(Arrays.toString(arr));
// 6.listFiles() : 将File所表示的文件夹路径下, 所有的子级别(当前文件夹级别下)的文件和文件夹都获取到,
// 将获取到结果放置到File[]中
System.out.println(Arrays.toString(f2.listFiles()));
File f3 = new File("D:\\1012系统班");
System.out.println(Arrays.toString(f3.list()));
}
}
list listFile
public static void main(String []args) {
File f1 = new File("e:\\a");
String []str =f1.list(); //list 输出的是当前文件夹下所有文件以及文件夹
File []f2 = f1.listFiles(); //listFile 输出的是当前文件以及文件夹的File类
//型,并且是全路径
for(int index = 0;index < str.length;index++) {
System.out.println(str[index]);
System.out.println(f2[index]);
}
}
2.IO流介绍
2.1 IO流概述
1,IO : I是i的大写字母, 表示input, 输入
O是o的大写字母, 表示output, 输出
2,IO流的主要作用就是进行数据传输, 不同的设备使用不同的IO流资源进行数据传输
3,IO的流向:
2.2 IO流的分类和使用步骤
1, IO流从功能性上分类:
字节流 : 以字节方式进行文件内容操作(读写)
输入流 : InputStream
输出流 : OutputStream
字符流 : 以字符方式进行文件内容操作(读写)
输入流 : Reader
输出流 : Writer
2,IO流使用的步骤:
1,使用IO流资源之前, 需要导包, java.io
2,使用IO流资源同时, 需要处理异常
3,使用IO流资源结束之后, 必须关系资源, close()
3,字节流
- 直接使用字节进行数据的操作
- 从流向上进行分类:
输入流 : InputStream
输出流 : OutputStream
3.1字节输入流
1,字节输入流 : InputStream, 来自于java.io包, 是所有的字节输入流的父类;
2,因为InputStream是抽象类, 不能实例化对象, 于是需要一个子类, FileInputStream, 来自于java.io包;
3,FileInputStream : 主要功能就是与磁盘上文件进行交互, 可以从磁盘上文件中读取出内容; 所有的文件都是以字节的形式组成, 因此FileInputStream 可以读取很多类型的文件内容, 例如 : txt, 图片, 视频...
4,FileInputStream的构造方法:
①, FileInputStream(String path) : 将path所表示的文件路径封装在一个字节输入流中, 以后字节输入流就可以从绑定的 文件中读取出内容
②,FileInputStream(File file) : 将file所表示的文件路径封装在一个字节输入流中, 以后字节输入流就可以从绑定的文件中 读取出内容
注意 : 构造方法中, 只能封装文件, 千万不能是文件夹, IO流资源只能对文件进行操作, 无法操作文件夹
常用方法:available():返回流中剩余可以读取的字节个数。
close():关闭这个流。
5,读取文件中内容:
1,read() : 表示每次从文件中读取出一个字节, 返回值int类型结果; 返回的就是读取到的字节所对应的整数结果, 如果读取到-1,证明文件读取完毕;
延伸 : 1个字节是8个连续的二进制位, 返回值类型int, 4字节大小, 因此读取到的字节需要补位成为一个4字节大小int, 因此 前三个字节都补充0, 最高位相当于符号位, 0符号位就表示正数, read()方法读取到的结果全部都是正数
2,read(byte[] b) : 表示每次最多从文件中读取出b.length个字节, 读到的数据都同步到了参数b数组中, 通过查看数组b, 就相当于查看文件内容; 返回值类型int, 返回的是本次读取到的字节的个数, 如果读取到-1,证明文件读取完毕.
注意 : 按照数组进行文件内容读取比单个字节读取文件效率高很多
3.读取文件的原理:
单个字节读取文件代码:
package com.ujiuye.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Demo01_FileInputStream {
// 可以随时查看类型之间的继承关系 : 把鼠标定位在类型上, ctrl + T可以查看这个类型的继承关系
public static void main(String[] args) throws IOException{
// 1. 创建出一个字节输入流, 相当于绑定一个数据源
FileInputStream fis = new FileInputStream("D:\\aabbc.txt");
// 注意 : IO流资源只能操作文件, 不能操作文件夹
// FileInputStream fis1 = new FileInputStream(new File("D:\\1012系统班"));
/*int first = fis.read();
int second = fis.read();
int thrid = fis.read();
int four = fis.read();
int five = fis.read();
int six = fis.read();
System.out.println(first);// 97
System.out.println(second);// 98
System.out.println(thrid);// 99
System.out.println(four);// 33
System.out.println(five);// -1
System.out.println(six);// -1
*/
// len表示每次读取到的字节数据
int len;
while((len = fis.read()) != -1) {
System.out.print((char)len);
}
// 一定要关闭资源
fis.close();
}
}
字节数组读取文件代码:
3.2字节输出流
- OutputStream : 是所有字节输出流的抽象父类, 来自于java.io包中
- 因为OutputStream 是抽象类, 不能实例化对象, 因为需要一个子类 FileOutputStream
- FileOutputStream : 是字节输出流, 主要功能就是与文件进行数据交互, 将字节数据写入到文件中, 因为所有文件都是由字节组成的, 因此FileOutputStream 可以向很多类型文件中写入数据, 例如 : txt, 图片, 视频...
- FileOutputStream构造方法:
1,FileOutputStream(String path) : 将path所表示的文件路径封装在一个字节输出流中, 以后字节输出流就可以向目标 文 件 中写入数据内容
2,FileOutputStream(File file) : 将file所表示的文件路径封装在一个字节输出流中, 以后字节输出流就可以向目标文件 中写入数据内容
注意 : 构造方法中, 只能封装文件, 千万不能是文件夹, IO流资源只能对文件进行操作, 无法操作文件夹
FileOutputStream(String path ,boolean b) FileOutputStream(File file, boolean b),后面的布尔类型如果为true, 不覆盖,false会覆盖文件中的内容,从新写入。
5,向文件中写入数据: write方法都没有返回值类型
1,write(int b) : 将字节数据b写入到文件中
2, write(byte[] b) : 将字节数组b中的所有内容写入到文件中
3,write(byte[] b, int index, int length) : 将数组b从index索引位置开始, 写入length个字节到文件中
注意 : 流资源使用完毕, 记得关闭资源; 按照字节数组写入数据比单个字节写入数据性能高很多
package com.ujiuye.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo03_FileOutputStream {
public static void main(String[] args) throws IOException{
File f = new File("second.txt");
if(!f.exists()) {
f.createNewFile();
}
// 1. 创建出一个字节输出流, 相当于绑定一个数据目的
FileOutputStream fos = new FileOutputStream(f);
//aABCDECD
// 2. 向文件中写入数据
// 1)write(int b) : 将字节数据b写入到文件中
fos.write(97);// a
fos.write(65);// A
byte[] b = {66,67,68,69};
// 2)write(byte[] b) : 将字节数组b中的所有内容写入到文件中
fos.write(b);
// 3)write(byte[] b, int index, int length) : 将数组b从index索引位置开始,
// 写入length个字节到文件中
fos.write(b, 1, 2);// 67 68
// getBytes() : 将字符串转成字节数组
fos.write("你好".getBytes());
// 记得关闭资源
fos.close();
}
}
3.3文件的复制
文件复制 : 本质就是边读(数据源)边写(数据目的)
注意 : 实际开发中, 通过数组形式进行文件读写, 可以很大提高IO流的效能, 数组大小一般都是1024的倍数比较常见
最常见 : 1024 1024 * 4 1024 * 8 (1024*8数组大小一般是JDK底层源代码比较倾向的数组大小设置)
package com.ujiuye.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo04_PictureCopy {
public static void main(String[] args) throws IOException{
// 1. 创建出一个字节输入流, 绑定一个数据源
FileInputStream fis = new FileInputStream("D:\\1012系统班\\day02\\图解\\变量定义和赋值过程.png");
// 2. 创建出一个字节输出流, 绑定一个数据目的
FileOutputStream fos = new FileOutputStream("D:\\变量定义copy2.png");
// 3. 单个字节复制
// len表示每次读取到的字节数据结果
/*int len;
while((len = fis.read()) != -1) {
fos.write(len);
}*/
// 4. 使用字节数组读写文件, 提高效率
byte[] b = new byte[1024*4];
// len表示读取到的字节的个数
int len;
while((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
}
fos.close();
fis.close();
}
}
3.4字节高效缓冲流
1, 字节高效缓冲流 : 作用就是提高普通字节流资源的读写效率, 缓冲流底层自动使用1024*8字节数组进行文件的读写
BufferedInputStream : 字节高效缓冲输入流, 也是一个包装类, 功能将一个普通字节输入流,包装成一个高效字节缓冲流
2, 通过构造方法可以看到包装过程 : BufferedInputStream
(
InputStream in)
BufferedOutputStream : 字节高效缓冲输出流, 也是一个包装类, 功能将一个普通字节输出流,包装成一个高效字节缓冲流
3, 通过构造方法可以看到包装过程 : BufferedOutputStream
(
OutputStream out)
4, 高效原理:
BufferedInputStream : 当创建出一个BufferedInputStream 类型的输入流资源, 代码底层自动创建出一个大小为8192(1024 * 8)的字节数组; 每次调用read方法读取数据, 都最多从文件中读取出8192个字节, 将读取到的字节数据放置到底层数组缓冲中, 以后读取数据,从底层数组缓冲中读取, 以此减少与磁盘交互, 从而提高读取效能; 直到读取到的结果为-1,读取完毕
BufferedOutputStream : 当创建出一个BufferedOutputStream 类型输出流资源,代码底层自动创建出一个大小为8192(1024 * 8)字节数组;每次向文件中写入数据, 都是写入到了底层数组缓冲中, 等到将8192数组写满, 自动同步数据到文件中; 如果数组没有写满, 可以通过close方法, 关闭资源, 关闭资源之前, 会先将数组缓冲中的数据同步到文件中, 后关闭资源; 减少了与磁盘交互, 从而提高写入效能
package com.ujiuye.file;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class BufferedInputStream01 {
public static void main(String[] args) throws IOException{
InputStream is =new FileInputStream("e:\\a\\01.day14内容回顾.mp4");
OutputStream os = new FileOutputStream("e:\\day1内容回顾.mp4");
BufferedInputStream bs = new BufferedInputStream(new FileInputStream("e:\\a\\01.day14内容回顾.mp4"));
BufferedOutputStream bO = new BufferedOutputStream(new FileOutputStream("e:\\create\\day1内容回顾.mp4"));
int len = 0;
long beginTime = System.currentTimeMillis();
while((len = bs.read())!=-1) {
bO.write(len);
}
long endTime = System.currentTimeMillis();
System.out.println(endTime-beginTime);
long beginTime1 = System.currentTimeMillis();
int len1 = 0;
while((len1 = is.read()) != -1) {
os.write(len1);
}
long endTime1 = System.currentTimeMillis();
System.out.println(endTime1 - beginTime1);
os.close();
is.close();
bs.close();
bO.close();
}
}
BufferedOutputStream的效率远高于FileOutputStream.
4.字符流
4.1字节流读取中文乱码问题
1,问题 : 通过字节输入流读取一个带有中文文本文件
1,按照单个字节进行读取, 读取到结果乱码(实际结果与预期结果不符), 原因 : 默认的GBK编码中, 一个中文占有2个字节, 通 过单个字节读取文件, 就将中文拆分了, 拆分之后转换成对应的字符, 导致乱码
2,按照字节数组读取, 设置大小为2字节数组, 如果文件中是中英文混合, 仍然有可能将中文拆分开读取, 结果还是乱
结论 : 不要使用字节流读取带有中文的文本文件
2,解决中文文本读取乱码问题? 按照字符读取,就可以解决中文被拆分的问题, 因为一个字母, 一个符号, 或者是一个中文, 一个数 字, 统统都是一个字符
package com.ujiuye.io;
import java.io.FileInputStream;
import java.io.IOException;
public class Demo01_FileInputStreamReadChinese {
public static void main(String[] args) throws IOException{
// 1. 绑定一个数据源
FileInputStream fis = new FileInputStream("chinese.txt");
// 2. 使用单个字节进行文件内容读取
// len表示每次读取到的字节对应的数据结果
/* int len;
while((len = fis.read()) != -1) {
System.out.print((char)len);
}*/
// 3. 使用字节数组读取文件内容
byte[] b = new byte[2];
// len表示每次读取到的字节的个数
int len;
while((len = fis.read(b)) != -1) {
System.out.print(new String(b,0,len));
}
fis.close();
}
}
4.2字符输入流
1,Reader : 字符输入流抽象父类, 来自于java.io包
2,抽象类不能实例化对象, 因此需要子类 FileReader, 来自于java.io包, 作用就是通过字符读取文件内容, 注意 : FileReader主要读取文本文件(txt文件)
3.字符输入流FileReader读取原理:
所有文件都是字节组成, 在默认的GBK编码表中, 一个数字, 一个符号, 一个大小写字母, 都占有一个字节, 来自于ASCII编码表中, 都是正数(0-127); 一个中文占有2个字节, 第一个字节为负数;
字符输入流会先从文件中读取出一个字节, 判断如果这个字节为正数, 证明读取到了ASCII编码表中的一个字符, 直接参考编码表转字符; 如果读取到的第一个字节是负数, 那么动态再向下读取出另外一个字节, 将两个字节一起参考编码表转换成字符
4,FileReader构造方法:
a : FileReader(String fileName)
b: FileReader(File file)
5,读取文件的方式:
read() : 每次读取一个字符, 返回值类型int, 返回的就是读取到的字符在编码表中的整数结果, 如果返回-1,证明读取完毕
read(char[] ch) : 每次最多读取出ch.length个字符, 将读取到的字符数据同步到参数ch数组中, 查看ch数组相当于在查看文件内容; 返回值类型int, 表示本次读取到的字符的个数, 如果读取到-1,证明文件读取完毕
package com.ujiuye.io;
import java.io.FileReader;
import java.io.IOException;
public class Demo02_FileReader {
public static void main(String[] args) throws IOException{
// 1. 创建出一个字符输入流, 绑定一个数据源
FileReader fr = new FileReader("chinese.txt");
// 2. 使用单个字符读取文件内容
// len表示读取到的字符在编码表中对应的整数结果
/*int len;
while((len = fr.read()) != -1 ) {
System.out.print((char)len);
}*/
// 3. 使用字符数组读取文件内容
char[] ch = new char[3];
// len表示读取到的字符的个数
int len;
while((len = fr.read(ch)) != -1) {
System.out.print(new String(ch, 0, len));
}
fr.close();
}
}
4.3字符输出流
1,Writer : 字符输出流的抽象父类, 来自于java.io包
2,抽象类不能实例化对象, 因此需要子类FileWriter, 来自于java.io包. 主要功能就是以字符方式向文件中写入数据
3,FileWriter构造方法:
FileWriter(String fileName)
FileWriter(File file)
4,向文件中写入数据方式: write方法返回值类型 void
write(int c) : 表示每次写个一个字符
write(char[] ch) : 表示每次可以将ch数组中的所有字符内容写入到文件中
write(char[] ch , int index , int length) : 表示每次将ch数组中的一部分写入到文件中; 从index索引位置开始写, 写入length 个 字符
write(String s): 将字符串s写入到文件中
write(String s, int index, int length) : 表示将字符串s从index索引位置开始, 写入length个字符到文件中
package com.ujiuye.io;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Demo03_FileWriter {
public static void main(String[] args) throws IOException{
File f = new File("abc.txt");
if(!f.exists()) {
f.createNewFile();
}
// 1. 创建出一个字符输出流, 绑定一个数据目的
FileWriter fw = new FileWriter(f);
//A1a&中a&我爱我家,天气真好我家,天
// 2. 向文件中写入数据
// 写入单个字符
fw.write('A');
char[] ch = {'1','a','&','中'};
// 写入字符数组
fw.write(ch);
// 写入字符数组一部分
fw.write(ch, 1, 2);
String s = "我爱我家,天气真好";
// 写入字符串
fw.write(s);
// 写入字符串一部分
fw.write(s, 2, 4);
// 3. 一定要关闭资源
fw.close();
}
}
4.4flush和close方法的比较
IO流资源中的数组缓冲 : 带有数组缓冲流资源在读写效能上更高, 但是举例 : 向文件中写入内容; 写的数据都是自动存储在底层数组缓冲区域中, 如果缓冲区写满, 自动同步到文件中; 或者通过flush或者close方法让缓冲区中的数据同步到文件中
1,flush() : 表示刷新, 将当前正在使用的IO流资源在底层缓冲区中的数据同步到文件中, flush刷新之后的流资源还可以继续使用
2,close() : 表示关闭资源, 当调用close方法关闭资源之前, 先调用flush功能, 将缓冲区中数据同步到文件中, 同步数据结束, 再关闭流资源和相关系统资源; close关闭资源之后,流资源不能再继续使用
注意 : 使用IO流, 一定必须要关闭资源
package com.ujiuye.io;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Demo03_FileWriter {
public static void main(String[] args) throws IOException{
File f = new File("abc.txt");
if(!f.exists()) {
f.createNewFile();
}
// 1. 创建出一个字符输出流, 绑定一个数据目的
FileWriter fw = new FileWriter(f);
//A1a&中a&我爱我家,天气真好我家,天
// 2. 向文件中写入数据
// 写入单个字符
fw.write('A');
char[] ch = {'1','a','&','中'};
// 写入字符数组
fw.write(ch);
// 写入字符数组一部分
fw.write(ch, 1, 2);
// 刷新数组缓冲区中数据到文件中
fw.flush();
String s = "我爱我家,天气真好";
// 写入字符串
fw.write(s);
// 写入字符串一部分
fw.write(s, 2, 4);
// 3. 一定要关闭资源
fw.close();
// 关闭流资源之后, 流不能再继续使用, 否则代码会报错 : IOException
// fw.write("helloworld");
}
}
4.5字符流复制纯文本文件
结论 :
如果使用字符流复制文件, 只能复制纯文本文件(使用txt记事本形式可以打开, 还能读懂的文件, 称为纯文本文件)
复制过程效率不高(效率低)
package com.ujiuye.io;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo04_字符串Copy {
public static void main(String[] args) throws IOException{
// 1. 创建出一个字符输入流, 读取文件 , 绑定一个数据源
FileReader fr = new FileReader("abc.txt");
// 2. 创建出一个字符输出流, 写入文件, 绑定一个数据目的
FileWriter fw = new FileWriter("abcCopy.txt");
// len表示每次读取到的字符的个数
int len;
char[] ch = new char[10];
while((len = fr.read(ch)) != -1) {
fw.write(ch, 0, len);
}
fw.close();
fr.close();
}
}
4.6字符流不能复制非纯文本文件
非纯文本文件中字节, 例如 : 图片,音频,视频...在编码表中不存在, 也没有办法转换成正确字符, 导致文件复制过程中, 字节转换成字符的过程出错; 将错误的字符转换成字节, 写入到目的文件中, 目的文件中字节与源文件已经不同, 导致复制失败
package com.ujiuye.io;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo05_字符流复制非纯文本失败 {
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("D:\\1012系统班\\day06\\图解\\两个对象在内存中理解.png");
FileWriter fw = new FileWriter("D:\\对象Copy.png");
int len;
char[] ch = new char[1024];
while((len = fr.read(ch)) != -1) {
fw.write(ch, 0, len);
}
fw.close();
fr.close();
}
}
4.7高效缓冲字符流
- 高效缓冲字符流 : 作用就是可以提高字符流读写效率, 将字符数组作为读写的缓冲, 从而减少与磁盘交互, 进而提高读写效率
- BufferedReader: 是Reader的子类, 称为高效缓冲字符输入流, 本身是一个包装类, 将一个最普通字符输入流,包装成一个高效字符输入流
从构造方法封装可以看出包装性 : BufferedReader
(
Reader in)
3.BufferedWriter: 是Writer的子类, 称为高效缓冲字符输出流, 本身是一个包装类, 将一个最普通字符输出流,包装成一个高效字 符输出流
4,从构造方法封装可以看出包装性 : BufferedWriter
(
Writer out)
- 简单描述高效缓冲流的高效原理:
- BufferedReader, 当创建出一个BufferedReader类型流资源对象时, 代码底层自动创建出一个大小为8192(1024*8)的字符数组, 每次调用read方法读取文件, 都最多读取出8129个字符放置到底层字符数组中, 以后读取就从底层数组中读取, 如果8192读取完毕,继续从文件中最多读8192个,以此类推, 直到读取到-1,文件结束为止; 如此减少与磁盘的交互, 提高读取效率
- BufferedWriter, 当创建出一个BufferedWriter流资源对象时, 代码底层自动创建出一个大小为8192(1024*8)的字符数组, 每次向文件中写入数据, 都是先写入到底层数组中, 如果8192写满了, 自动将数组中的内容同步到文件中, 如果8192没有写满, 可以使用flush或者close方法将缓冲区中数据同步到文件中; 如此减少与磁盘的交互, 提高读取效率
package com.ujiuye.io;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo06_BufferedStream {
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(
new FileReader("chinese.txt"));
BufferedWriter bw = new BufferedWriter(
new FileWriter("chineseCopy.txt"));
int len;
while((len = br.read()) != -1) {
bw.write(len);
}
br.close();
bw.close();
}
}
4.8高效缓冲字符流特有方法
- BufferedReader : 中有特殊方法功能
readLine() : 每次从文件中读取出一行文字, 返回值类型String类型; 如果返回的结果为null, 证明文件读取完毕
- BufferedWriter : 中有特殊方法功能
newLine() : 在文件中写入一个换行符, 不受操作系统限制
package com.ujiuye.io;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo07_字符缓冲流特有方法 {
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(
new FileReader("javaCode.txt"));
BufferedWriter bw = new BufferedWriter(
new FileWriter("javaCodeCopy.txt"));
// s表示每次读取到的一行内容
String s;
while((s = br.readLine()) != null) {
bw.write(s);
// 向文件中写入回车换行
bw.newLine();
}
bw.close();
br.close();
}
}
5,转换流
- 编码表 :
GBK : 中国标准码表, 底层兼容ASCII编码, 一个中文占有2字节大小
UTF-8 : 万国码表, 底层兼容ASCII编码, 一个中文占有3字节大小
- 读写带有中文文本文件时, 发生乱码情况一般有两种:
流资源选择不正确, 例如字节流读取中文, 可能将中文拆开读取, 导致乱码, 改成字符流读取
读写文件时, 因为文件的编码集不同, 也会导致读写文件是发生乱码问题, 使用转换流解决不同编码集文件读写乱码问题
- 将文件编码集进行修改 : 如下图
点击指定需要修改编码集的文件--->鼠标右键--->properties(属性)
4.转换流 : 主要功能就是可以根据文件指定的编码集读写文件
1),InputStreamReader : 字节到字符的桥梁, 父类Reader, 字符输入流
构造方法 : InputStreamReader
(
InputStream in, String charsetName)
a : 第一个参数 in , 表示一个字节输入流, 从文件中读取出字节数据
b : 将读取到的字节通过第二个参数charsetName编码集, 将字节通过指定编码集转换成字符
2),OutputStreamWriter : 字符到字节桥梁, 父类Writer, 字符输出流
构造方法 : OutputStreamWriter
(
OutputStream out, String charsetName)
a : 将文件中读取到的字符, 参考第二个参数charsetName, 参考指定编码表转换成字节数据
b : 将字节使用第一个参数out写入到文件中
注意 : 使用转换流时, 给出编码集与要操作的文件的编码集一致
举例 : 例如需要读取的文件编码是UTF-8, 转换流中给出的编码集就是UTF-8
例如需要写入的文件的编码是GBK, 转换流中给出的编码集就是GBK
package com.ujiuye.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class Demo10_转换流 {
public static void main(String[] args) throws IOException{
// 1. 创建出一个输入流, 读取文件
InputStreamReader isr = new InputStreamReader(
new FileInputStream("UTF-8.txt"), "UTF-8");
// 2. 创建出一个输出流, 向文件中写入数据
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("GBK.txt"), "GBK");
int len;
while((len = isr.read()) != -1) {
osw.write(len);
}
osw.close();
isr.close();
}
}
6.IO流的标准异常处理方式(扩展)
- 标准IO流异常处理方式很繁琐,但是很安全!
- 从JDK1.7版本开始, 为IO流资源使用提供新的异常处理语法结构:
try(
IO流资源创建写入在try的小括号中;
){
// 可能会发生异常的代码, 主要IO流资源的读写使用
}catch(异常类型 变量名){
// 对于异常处理方式
}
3,try代码块中的小括号作用 : 会在流资源使用结束后, 自动关闭资源; 因此新的语法结构中, IO流资源不需要手动关闭
JDK7对于IO流新异常处理方式:
package com.ujiuye.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo12_JDK7IO流资源新异常处理 {
public static void main(String[] args) {
try(
FileInputStream fis = new FileInputStream("abc.txt");
FileOutputStream fos = new FileOutputStream("abcCopy.txt");
){
int len;
while((len = fis.read()) != -1) {
fos.write(len);
}
}catch(IOException ex) {
ex.printStackTrace();
}
}
}