Day 17
2019年5月18日。
这是我学习Java的第十七天。
这一天,我学到了以下的知识。
IO流
IO流,用来处理设备之间的数据传输,Java对数据的操作是通过流的方式,而Java用于操作流的对象都在IO包中
IO流按照数据流向,可分为:输入流(从硬盘读取数据到内存),输出流(从内存写入数据到硬盘)
IO流按照数据类型,可分为:
-
字节流
可以读写任何类型的文件,比如音频、视频、文本文件
抽象基类如下:-
InputStream
常用具体子类:1.FileInputStream
构造方法:FileInputStream(File file)
:通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定
FileInputStream(String name)
:通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定常用的成员方法
- 读取功能
int read(byte[] b)
:一次读取一个字节数组
- 当该方法返回 -1 时,表明已经读完了数据。一般可用该值来判断数据是否已经遍历完成
- 关闭功能
public void close() throws IOException
:关闭文件流,释放资源
2.BufferedInputStream
为了对应BufferedOutputStream,Java提供了BufferedInputStream
构造方法:BufferedInputStream(InputStream in)
:创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用 - 读取功能
-
OutputStream
常用具体子类:1.FileOutputStream
构造方法:FileOutputStream(File file)
:创建一个向指定 File 对象表示的文件中写入数据的文件输出流
FileOutputStream(String name)
:创建一个向具有指定名称的文件中写入数据的输出文件流
常用的成员方法- 写入功能
public void write(int b)
:写一个字节 超过一个字节 砍掉前面的字节public void write(byte[] b)
:写一个字节数组public void write(byte[] b,int off,int len)
:写一个字节数组的一部分
- 关闭功能
public void close() throws IOException
:关闭文件流,释放资源
面试题:为什么一定要close()?
a: 通知系统释放关于管理a.txt文件的资源
b: 让Io流对象变成垃圾,等待垃圾回收器对其回收
2.BufferedOutputStream
字节流一次读写一个数组的速度,明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流,即BufferedOutputStream
构造方法:BufferedOutputStream(OutputStream out)
:创建一个新的缓冲输出流,以将数据写入指定的底层输出流 - 写入功能
-
-
字符流
只能读写文本文件
由于字节流操作中文不是特别方便,所以,java就提供了字符流
介绍字符流之前,首先介绍编码和解码的概念:扫描二维码关注公众号,回复: 6456106 查看本文章-
编码
- 把一个字符串转换成一个字节数组
-public byte[] getBytes()
:使用平台的默认字符集将此 String编码为 byte 序列,并将结果存储到一个新的 byte 数组中
-public byte[] getBytes(String charsetName)
:使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中 -
解码
- 把字节数组转换成字符串
-public String(byte[] bytes)
:通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String
-public String(byte[] bytes, String charsetName)
:通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String
抽象基类如下:
-
Writer
常用具体子类:1.OutputStreamWriter——FileWriter(便携类)
构造方法:OutputStreamWriter(OutputStream out)
:根据默认编码(GBK)把字节流的数据转换为字符流
OutputStreamWriter(OutputStream out,String charsetName)
:根据指定编码把字节流数据转换为字符流
常用的成员方法- 写入功能
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)
:写一个字符串的一部分
- 写入功能
2.BufferedWriter
高效的字符输出流
构造方法:public BufferedWriter(Writer w)
:创建一个使用默认大小输出缓冲区的缓冲字符输出流
特殊方法:public void newLine()
:根据系统来决定换行符,具有系统兼容性的换行符l-
Reader
常用具体子类:1.InputStreamReader——FileReader(便携类)
构造方法:InputStreamReader(InputStream is)
:用默认的编码(GBK)读取数据
InputStreamReader(InputStream is,String charsetName)
:用指定的编码读取数据
常用的成员方法- 读取功能
public int read()
:一次读取一个字符public int read(char[] cbuf)
:一次读取一个字符数组,如果没有读到,则返回-1
- 读取功能
2.BufferedReader
高效的字符输入流
构造方法:public BufferedReader(Reader e)
:创建一个使用默认大小输入缓冲区的缓冲字符输入流
特殊方法:public String readLine()
:一次读取一行数据 ,是以换行符为标记的,读到换行符就换行,没读到数据返回null -
IO流的异常处理
IO流的异常处理,分为字节流和字符流
- 字节流
以FileOutputStream为例,代码如下
public class MyTest {
public static void main(String[] args) {
//流的异常处理
FileOutputStream out = null;
try {
out = new FileOutputStream("d.txt");
out.write(100);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 字符流
以InPutStreamReader和OutputStreamWriter为例,代码如下
public class MyTest {
public static void main(String[] args) {
//处理流的异常
//一次多写一些
InputStreamReader in = null;
OutputStreamWriter out = null;
try {
in = new InputStreamReader(new FileInputStream("MyTest.java"));
out = new OutputStreamWriter(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\MyTest.java"));
//定义一个字符缓冲区
char[] chars = new char[2000];
int len = 0;//记录每次读取到的有效字符个数
while ((len = in.read(chars)) != -1) {
out.write(chars, 0, len);
out.flush();
}
} catch (IOException e) {
//处理逻辑,默认打印异常的详细堆栈信息
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
IO流的经典算法
- ArrayList集合中的字符串数据存储到文本文件中,以及将文本文件中的数据反向读入到ArrayList集合中
代码如下
//1.ArrayList集合中的字符串数组存储到文本文件
public class MyTest {
public static void main(String[] args) throws IOException {
//需求:把ArrayList集合中的字符串数据存储到文本文件
ArrayList<String> list = new ArrayList<>();
list.add("冯小刚");
list.add("张艺谋");
list.add("宁浩");
list.add("徐峥");
list.add("小四");
//把集合中的数据保存到文件文件中
//思路,遍历集合,取出数据写入文本文件
BufferedWriter writer = new BufferedWriter(new FileWriter("username.txt"));
for (String s : list) {
writer.write(s);
writer.newLine();
writer.flush();
}
writer.close();
}
}
//2.文本文件中的数据反向读入到ArrayList集合
public class MyTest2 {
public static void main(String[] args) throws IOException {
//需求是,把文本文件中的数据读取到集合中
ArrayList<String> list = new ArrayList<>();
BufferedReader reader = new BufferedReader(new FileReader("username.txt"));
while (true){
String s = reader.readLine();
if(s!=null){
list.add(s);
}else{
break;
}
}
System.out.println(list);
}
}
- 多级文件夹复制
代码如下
public class HomeTest {
public static void main(String[] args) throws IOException {
//需求:复制多级文件夹
//1.封装源文件夹
File srcFolder = new File("C:\\test2");
//2.封装目标文件夹
File targetFolder = new File("D:\\test2");
if (!targetFolder.exists()) {
targetFolder.mkdirs();
}
//进行复制
copyFolder(srcFolder, targetFolder);
System.out.println("复制完成");
}
private static void copyFolder(File srcFolder, File targetFolder) throws IOException {
//遍历源文件夹下,所有的文件,复制到目标文件夹下去
File[] files = srcFolder.listFiles();
for (File f : files) {
if(f.isFile()){
copyFiles(f, targetFolder);
}else{
//targetFolder = new File(targetFolder.getPath() + "\\" + f.getName());
//递归
File file = new File(targetFolder,f.getName());
if (!file.exists()) {
file.mkdirs();
}
copyFolder(f, file);
}
}
}
//复制文件
private static void copyFiles(File f, File targetFolder) throws IOException {
//使用字节流来复制
FileInputStream in = new FileInputStream(f);//封装源文件
//封装目标文件
//File file = new File(targetFolder, f.getName());
//System.out.println(file);
FileOutputStream out = new FileOutputStream(new File(targetFolder, f.getName()));
int len = 0;
byte[] bytes = new byte[1024 * 8];
while ((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
out.flush();
}
//是否资源
in.close();
out.close();
}
}
- 录入学生信息到文件中
代码如下
//学生类
public class Student implements Comparable<Student>{
private String name;
private int score;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.score = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return score;
}
public void setAge(int age) {
this.score = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", grade=" + score +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return score == student.score &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, score);
}
@Override
public int compareTo(Student o) {
int num=this.score-o.score;
int num2=num==0?this.name.compareTo(o.name):num;
return num2;
}
}
//测试类
public class HomeTest {
public static void main(String[] args) throws IOException {
//需求: 键盘录入学生信息按照总分排序并写入文本文件
Scanner scanner = new Scanner(System.in);
Student student;
TreeSet<Student> treeSet = new TreeSet<>();
BufferedWriter buf = new BufferedWriter(new FileWriter("Student.txt"));
for (int i = 1; i < 4; i++) {
scanner = new Scanner(System.in);
student = new Student();
System.out.println("请输入第" + i + "位学生的姓名");
String name = scanner.nextLine();
student.setName(name);
System.out.println("请输入第" + i + "位学生的成绩");
int score = scanner.nextInt();
student.setAge(score);
treeSet.add(student);
}
buf.write(treeSet.toString());
buf.close();
}
}