Day19-IO
1. 复习之数据结构
数据结构是计算机存储和组织数据的方式,简单来说 就是用来存储数据的,只不过根据存储的方式和操作以及特性不同,分为几类
数组 : 有序可重复,查询快更改快,删除添加慢
链表 : 有序可重复,添加删除快,查询更改慢
散列表 : 无序不可重复,存储键值对,key唯一,value可以重复
Tree : 无序不可重复,元素按照某种规则自动排序,(Comparator和Comparable)
他们的本质都是用来保存数据的,我们需要把他们的特征记住,然后再根据我们的需求合理选择数据结构进行存储数据,效率会有所提升
2. IO
2.1 概述
流是一组有顺序的,有起点有重点的字节集合,是对数据传输的总称或抽象
简单来说 就是设备之间的数据传递称为流
流的本质 就是数据的传输,根据不同的数据传输特性,抽象出各种类,方便我们直接操作数据
流中的操作对象是指内存中,当前操作的程序而言
输入 : 指往内存中导入数据
输出 : 指从内存中写出数据
I : input 输入
O : output 输出
2.2 分类
按处理数据类型的不同,分为字节流和字符流
按数据流向的不同,分为输入流和输出流。(入和出是相对于内存来讲的)
按功能不同,分为节点流和处理流
节点流:直接操作数据源
2.3 四大抽象类
InputStream 字节输入
OutputStream 字节 输出
Reader 字符输入
Writer 字符输出
2.3.1 InputStream
2.3.2 OutputStream
2.3.3 Reader
2.3.4 Writer
2.4 文件流
原始文件流 : 用于打开链接,操作数据
1 FileInputStream 字节输入
2 FileOutputStream 字节输出
3 FileReader 字符输入
4 FileWriter 字符输出
2.4.1 FileIputStream
2.4.1.1 概述
java.io.InputStream
java.io.FileInputStream; 按照自己的方式在原始文件中读取数据
想要读取一个文件,必须要找到它
怎么找? 定位到某个文件 有两种方式, 1 绝对路径 2 相对路径
相对路径 : 相对当前文件,如何找到 ./ 当前目录 , …/ 上级目录, …/…/…/ 上上上级目录 , / 下级
绝对路径 : 以系统跟目录为准,如何找到这个文件
2.4.1.2 常用方法
// 读取数据
// 读取一个字节,返回下一个字节的值,因为开始光标在顶端,如果到达文件末尾(后面没有了) 就返回-1
int i1 = fis.read();
package com.demo.IO;
import java.io.FileInputStream;
import java.io.IOException;
/**
* 常用方法
*/
public class IO_06_FileInputStream {
public static void main(String[] args) throws IOException {
// 1 创建流对象
FileInputStream fis = new FileInputStream(
"./src/com/demo/io/IO_02_FileInputStream.java");
// 2 可获得字节数
System.out.println(fis.available());//1349
// 3 读取字节数组
byte[] bytes = new byte[5];
fis.read(bytes);
System.out.println(new String(bytes));//packa
System.out.println(fis.available());//1344
// 4 跳过不读
fis.skip(20);
System.out.println(fis.available());//1324
// 5 读取一个
System.out.println(fis.read());//109
// 6 关闭资源
fis.close();
}
}
2.4.1.3 Read
Read( ) 返回下一个字节的值,如果到达文件末尾 返回 -1
package com.demo.IO;
import java.io.FileInputStream;
import java.io.IOException;
/**
* java.io.InputStream
* java.io.FileInputStream; 按照自己的方式在原始文件中读取数据
*
* 想要读取一个文件,必须要找到它
*
* 怎么找? 定位到某个文件 有两种方式, 1 绝对路径 2 相对路径
*
* 相对路径 : 相对当前文件,如何找到 ./ 当前目录 , ../ 上级目录, ../../../ 上上上级目录 , / 下级
*
* 绝对路径 : 以系统跟目录为准,如何找到这个文件
*
*/
public class IO_02_FileInputStream {
public static void main(String[] args) {
// 在Eclipse中 相对的是当前项目 D:\workspace\w20201230_16\JavaSE_08_IO
FileInputStream fis = null ;
try {
// 创建对象 使用相对路径找这个文件
fis = new FileInputStream("G:\\tianLiang\\day20\\code\\demo\\src\\com\\demo\\IO\\IO_02_FileInputStream.java");
// 绝对路径
// FileInputStream fis = new FileInputStream("D:/xxx/xx/xx.txt");
// 读取数据
// 读取一个字节,返回下一个字节的值,因为开始光标在顶端,如果到达文件末尾(后面没有了) 就返回-1
int i1 = fis.read();
int i2 = fis.read();
System.out.println((char)i1);//p
System.out.println((char)i2);//a
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.demo.IO;
import java.io.FileInputStream;
// 使用 read 循环读取
public class IO_03_FileInputStream {
public static void main(String[] args) {
// 自动关闭资源
try (FileInputStream fis = new FileInputStream(
"./src/com/demo/IO/IO_02_FileInputStream.java");) {
//fis.read()当光标为-1 时则读取文件结束
int temp = 0;
while( (temp = fis.read()) != -1 ){
System.out.print((char) temp);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.4.1.4 read(byte[] bytes)
read 方法重载
可以无参,可以传入一个byte数组,
read(byte[] b) : 使用字节数组来存储读取的数据,并一次返回(要么数组装满,要么到达文件末尾),可以提高读取效率
返回值 是本次读取到的字节个数,如果到达文件末尾 返回-1
package com.demo.IO;
import java.io.FileInputStream;
/**
* read 方法重载
*
* 可以无参,可以传入一个byte数组,
* read(byte[] b) : 使用字节数组来存储读取的数据,并一次返回(要么数组装满,要么到达文件末尾),可以提高读取效率
* 返回值 是本次读取到的字节个数,如果到达文件末尾 返回-1
*
*/
public class IO_04_FileInputStream {
public static void main(String[] args) {
// 自动关闭资源
try (FileInputStream fis = new FileInputStream(
"./src/com/demo/IO/IO_02_FileInputStream.java");) {
// 准备数组
byte[] bytes = new byte[1000];
// 返回本次读取的字节个数,
int i1 = fis.read(bytes);
System.out.println(i1);
// 转换 为string
System.out.println(new String(bytes));
// 在读取一次
// 再次使用该数组读取的时候,数组内元素不会清空,而是会用新读取的数据替换原来的
int i2 = fis.read(bytes);
System.out.println(i2);
// 转换 为string
// 如果我们直接把字节数组转换为String的话,有可能产生冗余数据(上次读取的)
// 所以 为了保证数据不冗余,我们可以利用read的返回值,本次读取的字节数
// 我们只把本次读取的字节 转换为String 即可
// 字节数组,从哪开始(包含),个数
System.out.println(new String(bytes,0,i2));
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.demo.IO;
import java.io.FileInputStream;
/**
* 循环读取
*/
public class IO_05_FileInputStream {
public static void main(String[] args) {
// 自动关闭资源
try (FileInputStream fis = new FileInputStream(
"./src/com/demo/io/IO_02_FileInputStream.java");) {
// 准备数组
byte[] bytes = new byte[1024];
int temp = 0;
while((temp = fis.read(bytes)) != -1){
System.out.println( new String(bytes,0,temp));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.4.2 FileReader
2.4.2.1 概述
FileRead : 一次读一个字符,也就是2字节,而 unicode编码也是2字节
所以 字符串输入流 一般用于读取纯文本文件,像压缩包,图片等还是使用字节流
2.4.2.2 常用方法
read一样有方法重载,
read() : 读取一个字符,返回下一个的字符数据,到达文件末尾返回-1
read(char[] c) : 读取一个字符数组,返回读取到的字符数,到达文件末尾返回-1
2.4.2.3 使用方式
package com.demo.IO;
import java.io.FileReader;
/**
* FileRead : 一次读一个字符,也就是2字节,而 unicode编码也是2字节
*
* 所以 字符串输入流 一般用于读取纯文本文件,像压缩包,图片等还是使用字节流
*
* read一样有方法重载,
* read() : 读取一个字符,返回下一个的字符数据,到达文件末尾返回-1
* read(char[] c) : 读取一个字符数组,返回读取到的字符数,到达文件末尾返回-1
*
*/
public class IO_07_FileReader {
public static void main(String[] args) {
try(
FileReader fr = new FileReader("G:\\tianLiang\\day20\\test.java");
) {
// 字符数组
char[] chars = new char[512];
int tmp = 0;
while((tmp = fr.read(chars)) != -1){
System.out.print(new String(chars,0,tmp));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.4.3 FileOutputStream
2.4.3.1 概述
java.io.OutputStream
java.io.FileOutputStream
将程序中内容 写出到硬盘中
输入流 找不到指定文件 会报错 , 但是输出流不会报错,会自动创建该文件,但是不会创建文件夹(目录)
2.4.3.2 常用方法
构造方法 :
FileOutputStream(String) : 把内容输出到指定文件中,并会覆盖原文件中内容
FileOutputStream(String,boolean) : 如果第二个参数是true,把内容输出到指定文件中,并在原文件中追加数据
成员方法 :
write(int i) : 写出整型
write(byte[] b) : 写出字节数组,想要输出字符串可以利用字符串中的getBytes()方法,把字符串转换为字节数组
flush() : 刷缓存,强制把缓冲区写出,避免造成数据遗漏
2.4.3.3 使用方式
package com.demo.IO;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* java.io.OutputStream
* java.io.FileOutputStream
* 将程序中内容 写出到硬盘中
*
* 输入流 找不到指定文件 会报错 , 但是输出流不会报错,会自动创建该文件,但是不会创建文件夹(目录)
*
* 构造方法 :
* FileOutputStream(String) : 把内容输出到指定文件中,并会覆盖原文件中内容
* FileOutputStream(String,boolean) : 如果第二个参数是true,把内容输出到指定文件中,并在原文件中追加数据
* 成员方法 :
* write(int i) : 写出整型
* write(byte[] b) : 写出字节数组,想要输出字符串可以利用字符串中的getBytes()方法,把字符串转换为字节数组
* flush() : 刷缓存,强制把缓冲区写出,避免造成数据遗漏
*/
public class IO_08_FileOutputStream {
public static void main(String[] args) throws IOException {
// 创建输出流对象,如果没有传递boolean值,默认是false,会覆盖原文件中内容
// FileOutputStream fos = new FileOutputStream("G:\\tianLiang\\day20\\test.txt");
// 追加式写入
FileOutputStream fos = new FileOutputStream("G:\\tianLiang\\day20\\test.txt", true);
for (int i = 0; i < 26; i++) {
fos.write(i + 97);
}
// 写出字符串
String str = "Hello world";
byte[] bytes = str.getBytes();
fos.write(bytes);
// 刷缓存
fos.flush();
// 关闭流
fos.close();
}
}
2.4.4 FileWriter
2.4.4.1 概述
java.io.Writer
java.io.File.Writer 字符输出流
和字节输出流基本一致,新增字符串写出
2.4.4.2 常用方法
2.4.4.3 使用方式
package com.demo.IO;
import java.io.FileWriter;
/**
* java.io.Writer
*
* java.io.File.Writer 字符输出流
*
* 和字节输出流基本一致,新增字符串写出
*
*/
public class IO_09_FileWriter {
public static void main(String[] args) {
try (
// 默认是覆盖写入
FileWriter fw = new FileWriter("G:\\tianLiang\\day20\\test.txt");
){
// \n是换行
fw.write("你好吗\n");
char[] chars = {'a','b','c','d'};
fw.write(chars);
fw.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.5 缓冲流
2.5.1 概述
缓冲流 是包装流,创建对象的时候,传入的参数不再是文件地址,而是文件流对象
作用 : 把每次读入的数据存入到一个缓冲区,然后一次写入
把输出的数据存入一个缓冲区,然后一次写出
如果缓存流关闭,那么传入的对应的文件流对象也会被关闭
BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter
针对字符操作,提供了两个新方法
readLine() : 读一行,返回值就是读到的这一行的数据,到达文件末尾,返回null
newLine() : 换行,就等于\n
【特点】
主要是为了提高效率而存在的,减少物理读取次数
提供readLine()、newLine()这样的便捷的方法(针对缓冲字符流)
2.5.2 BufferedInputStream
和 FileInputStream方法几乎一致,只是效率提高
package com.demo.IO;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
/**
* 缓冲流 是包装流,创建对象的时候,传入的参数不再是文件地址,而是文件流对象
*
* 作用 : 把每次读入的数据存入到一个缓冲区,然后一次写入
* 把输出的数据存入一个缓冲区,然后一次写出
*
* 如果缓存流关闭,那么传入的对应的文件流对象也会被关闭
* BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter
*
针对字符操作,提供了两个新方法
* readLine() : 读一行,返回值就是读到的这一行的数据,到达文件末尾,返回null
* newLine() : 换行,就等于\n
*/
public class IO_10_BufferedInputStream {
public static void main(String[] args) {
try(
// 创建字节输入流
FileInputStream fis = new FileInputStream("./src/com/demo/io/IO_02_FileInputStream.java");
// 创建字节输入缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
) {
// 读取下一个字节,到达末尾返回 -1
System.out.println((char)bis.read());
// 读取一个数组,返回读取到的长度,到达末尾返回-1
byte[] bytes = new byte[10];
int temp =bis.read(bytes);
System.out.println(new String(bytes,0,temp));
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.5.3 BufferedOutputStream
package com.demo.IO;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
public class IO_11_BufferedOutputStream {
public static void main(String[] args) {
try (
// 创建字节输出流对象
FileOutputStream fos = new FileOutputStream("G:\\\\tianLiang\\\\day20\\\\test.txt");
// 创建字节输出缓冲流对象,并把字节输出流传入
BufferedOutputStream bos = new BufferedOutputStream(fos);
){
// 写出单个
bos.write(97);
byte[] bytes = "ni hao ma ".getBytes();
bos.write(bytes);
// 刷缓存
bos.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.5.4 BuffereReader
新增方法 readLine() 读取一行
package com.demo.IO;
import java.io.BufferedReader;
import java.io.FileReader;
public class IO_12_BufferedReader {
public static void main(String[] args) {
try (
// 创建字符输入流
FileReader fr = new FileReader("./src/com/demo/io/IO_02_FileInputStream.java");
// 创建字符输入缓冲流,并把字符输入流传入
BufferedReader br = new BufferedReader(fr);
) {
// 读取一行,返回读到的内容,到达文件末尾 返回 null
// String tmp = br.readLine();
// System.out.println(tmp);
// 循环读取
String tmp = null;
while( (tmp=br.readLine()) != null ){
System.out.println(tmp);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.5.5 BufferedWriter
新增输出换行方法 newLine()
package com.demo.IO;
import java.io.BufferedWriter;
import java.io.FileWriter;
public class IO_13_BufferedWriter {
public static void main(String[] args) {
try (
// 创建字符输出流,默认覆盖写出
FileWriter fw = new FileWriter("G:\\tianLiang\\day20\\test.txt");
// 创建字符输出缓冲流,并把字符输出流传入
BufferedWriter bw = new BufferedWriter(fw);
){
bw.write("你好吗");
// 输出换行
bw.newLine();
bw.write("你吃了吗");
// 刷缓存
bw.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.6 转换流
2.6.1 概述
转换流 是字节流和字符流之间转换 的桥梁,可以通过转换 流把字节流转换为字符流
并且 还可以再转换过程中 指定字符编码
特点
转换流是指将字节流向字符流的转换,主要有InputStreamReader和OutputStreamWriter
InputStreamReader主要是将字节流输入流转换成字符输入流
OutputStreamWriter主要是将字节流输出流转换成字符输出流
2.6.2 InputStreamReader
2.6.2.1 常用方法
2.6.2.2 使用方式
package com.demo.IO;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
/**
* 转换流 是字节流和字符流之间转换 的桥梁,可以通过转换 流把字节流转换为字符流
* 并且 还可以再转换过程中 指定字符编码
*/
public class IO_14_InputStreamReader {
public static void main(String[] args) {
try (
// 创建一个字节输入流对象
FileInputStream fis = new FileInputStream("./src/com/demo/io/IO_02_FileInputStream.java");
// 创建转换流对象 并把字节输入流传入,转换为字符流
InputStreamReader isr = new InputStreamReader(fis);
// 创建字符输入缓冲流,把转换流传入
BufferedReader br = new BufferedReader(isr);
){
String tmp = br.readLine();
System.out.println(tmp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.6.3 OutputStreamWriter
参考上面InputStreamReader的字节 转字符即可
2.7 打印流
2.7.1 概述
【特点】
打印流是输出最方便的类
包含字节打印流PrintStream,字符打印流PrintWriter
PrintStream是OutputStream的子类,把一个输出流的实例传递到打印流之后,可以更加方便地输出内容,相当于把输出流重新包装一下
PrintStream类的print()方法被重载很多次print(int i)、print(boolean b)、print(char c)
【标准输入/输出】
Java的标准输入/输出分别通过System.in和System.out来代表,在默认的情况下分别代表键盘和显示器,当程序通过System.in来获得输入时,实际上是通过键盘获得输入。当程序通过System.out执行输出时,程序总是输出到屏幕。
在System类中提供了三个重定向标准输入/输出的方法
static void setErr(PrintStream err) 重定向“标准”错误输出流
static void setIn(InputStream in) 重定向“标准”输入流
static void setOut(PrintStream out)重定向“标准”输出流
2.7.2 使用方式
package com.demo.IO;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
public class IO_15_PrintStream {
public static void main(String[] args) throws FileNotFoundException {
// out是标准的打印流,打印到控制台
System.out.println("你好啊");
// 创建输出流
FileOutputStream fos = new FileOutputStream("G:\\tianLiang\\day20\\test.txt");
// 创建打印流,并传入输出流
PrintStream ps = new PrintStream(fos);
// 调用打印方法,打印到指定文件
ps.println("日志系统");
// 可以设置System中的out
System.setOut(ps);
// 设置到system中后,再使用打印语句 会打印到指定地方
System.out.println("------------");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
System.out.println("m1开始执行 : " + sdf.format(new Date()));
m1();
System.out.println("m1执行结束 : " + sdf.format(new Date()));
}
public static void m1() {
System.out.println("m1 method execute!!!");
}
}
2.7.3 练习题
使用打印流 完成文件复制
比如 把 D盘下 123.txt 复制到 E盘下 123.txt
package com.demo.IO;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
/**
* 使用打印流 完成文件复制
比如 把 D盘下 123.txt 复制到 E盘下 123.txt
// 1 复制 就是输入和输出
// 2 先获取数据
// 3 再输出数据
*/
public class IO_16_PrintStream {
public static void main(String[] args) {
try (
//复制 数据 输出
FileInputStream fis = new FileInputStream("G:\\tianLiang\\day20\\test.txt");
//从数据输入
FileOutputStream fos = new FileOutputStream("g:/123.txt");
//控制台打印
PrintStream ps = new PrintStream(fos);
){
//给定一个字节数组作为缓冲
byte[] bytes = new byte[1024];
int tmp = 0;
while( (tmp = fis.read(bytes)) != -1 ){
ps.println(new String(bytes,0,tmp));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}