文章目录
1、IO:Input/Output
表示了数据移动的方向
以程序为参照物:流入程序的叫输入流,流出程序的叫输出流。
1.1、按照流的方向分为:
输入流,输出流
2.2、按照流的内容分为:
字节流,字符流
字节流是 8 位通用字节流,字符流是 16 位 Unicode 字符流
字节,流中的内容就是字节,字节流
字符,流中的内容就是字符,字符流
2.认识文件
文件:File
2.1、File类的常用方法
代码案例:IO流中部分方法使用,创建文件夹
public class Test {
public static void main(String[] args) {
// 显示桌面上的文件
File deskTop = new File("E:\\BigDataWorkSpaces\\javaStudentVsCode");
System.out.println(deskTop.isDirectory()); // 输出Boolean值
File[] files = deskTop.listFiles();
System.out.println("名字\t\t日期\t大小");
// 转化为本地化
SimpleDateFormat dfs = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
FileSystemView fsv = FileSystemView.getFileSystemView();
for (File file: files) {
String name = file.getName();
// 创建日期
Date d = new Date(file.lastModified());
String date = dfs.format(d);
String size = file.length()+""; // 长度的单位是:字节
String type = fsv.getSystemTypeDescription(file);
System.out.println(name+"\t\t"+date+"\t"+size+"\t"+type);
}
// 创建文件夹
File file = new File("E:\\BigDataWorkSpaces\\javaStudentVsCode\\a\\b\\c");
System.out.println(file);
System.out.println(file.exists()); // 是否存在该目录
file.mkdir(); // 创建该目录,也就是单层目录
System.out.println(file.exists());
file.mkdirs(); // 创建该目录,+s可以创建多层目录
System.out.println(file.exists());
}
}
2.2、使用FileInputStream 读文本文件
2.3、使用FileOutputStream 写文本文件
代码案例:字节输入流
public class Test2 {
public static void main(String[] args) throws IOException {
// InputStream 字节输入流
File file = new File("E:\\BigDataWorkSpaces\\javaStudentVsCode\\a\\b\\c\\a.txt");
InputStream in = new FileInputStream(file); // 泛化 此处检查异常
System.out.println(in.read()); // 读到的具体内容
System.out.println((char) in.read()); // 读到的数据转换成字符
System.out.println("-------------");
while (true){
int n = in.read();
if (n == -1){
break;
}
System.out.println((char)n);
}
String s = "微";
byte[] bb = s.getBytes();
System.out.println(Arrays.toString(bb));
}
}
2.4、复制文本文件
代码案例:文本,图片
public class Test3 {
public static void main(String[] args) throws IOException{
// new String(byte[])
File file = new File("E:\\BigDataWorkSpaces\\javaStudentVsCode\\a\\b\\c");
File file1 = new File("E:\\BigDataWorkSpaces\\javaStudentVsCode\\a\\b\\d");
int count = 0;
for (File fileNmae: file.listFiles()) {
System.out.println(fileNmae);
InputStream in = new FileInputStream(fileNmae);
File file2 = new File(file1,count+".未知");
OutputStream out = new FileOutputStream(file2);
while (true){
int n = in.read();
if (n == -1){
break;
}
out.write(n);
}
out.close();
in.close();
count ++;
}
System.out.println("ok........");
}
}
更多流学习
字符编码是GBK(国标)
文件中一个汉字占两个字节
一个阿拉伯数字和一个字母占一个字节
字符编码是UTF-8(万国码)
文件中一个汉字占三个字节
一个阿拉伯数字和一个字母占一个字节
字节输入流:FileInputStream 是用来读取
字节输出流:FileOutputStream 是用来写
字符输入流:FileReader
字符输出流:FileWriter
字符缓冲输入流:BufferedReader
字符缓冲输出流:BufferedWriter
二进制输入流:DataInputStream
二进制输出流:DataOutputStream
通常使用缓冲流去对文本读取写入
通常使用二进制流读取视频、图片、音乐…
1.DataOutputStream
:数据输出流 并不是文本,是字节流
练习1:输出流
public class Test {
public static void main(String[] args) throws IOException {
String s = "我爱中国";
int n = 21;
double d = 99.9;
// 输出流
// DataOutputStream:数据输出流 并不是文本,是字节流
// FileOutputStream:文件输出流
DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("data.txt")));
dos.writeUTF(s);
dos.writeInt(n);
dos.writeDouble(d);
// 强制输出
dos.flush();
System.out.println("ok.................");
// 关闭程序
dos.close();
}
}
2.DataInputStream
:数据输入流 并不是文本,是字节流
练习2:输入流
public class Test2 {
public static void main(String[] args) throws IOException {
// 输入流
DataInputStream dis = new DataInputStream(new FileInputStream(new File("data.txt")));
String s = dis.readUTF();
System.out.println(s);
int i = dis.readInt();
System.out.println(i);
double d = dis.readDouble();
System.out.println(d);
// 关闭程序
dis.close();
}
}
缓冲流
BufferedInputStream
BufferedOutputStream
BufferedReader
InputStreamReader
字节流转化字符流
package com.bigdata09.day15.demo1;
import java.io.*;
public class Test3 {
public static void main(String[] args) throws Exception{
//入流和出流
InputStream in = new FileInputStream(new File("d:\\a\\b\\c\\m.jpg"));
OutputStream out = new FileOutputStream(new File("src/main/resources/b.jpg"));
// BufferedInputStream bin =new BufferedInputStream(in);
//BufferedOutputStream bout = new BufferedOutputStream(out);
System.out.println("开始拷贝");
long start = System.currentTimeMillis();//计时⏲
//bout.write(bin.readAllBytes()); //一次性读写
/*int size = bin.available();
int n = size/(1024*1024);
int mod = size%(1024*1024);
for (int i = 0; i < n; i++) {
byte[] bytes =bin.readNBytes();
bout.write(bytes);
bout.flush();
}
bout.write(bin.readNBytes(mod));
bout.flush();*/
byte[] buffer = new byte[1024];
while (true){
int n = in.read(buffer); // n 不再表示字节 将表示读到的字节个数
if (n < buffer.length){//1024) {
out.write(buffer,0,n);
out.flush();
break;
}
out.write(n);
out.flush();
}
long end = System.currentTimeMillis();
long haoshi = end-start;
out.close();
in.close();
System.out.println("ok......."+haoshi);
}
}
PrintWriter
打印字符流(输出并换行)
ObjectOutputStream
字节流
3.案例:记账功能实现
public class Test {
public static void main(String[] args) {
/**
* 1.记账
* 2.结余
* 3.账单
* 4.退出
*/
ZhangDans sys = new ZhangDans();
sys.start();
}
}
public class ZhangDan implements Serializable {
private String type;
private String money;
private String mark;
private final static long serialVersionUID = 1L;
public ZhangDan() {
}
public ZhangDan(String type, String money, String mark) {
this.type = type;
this.money = money;
this.mark = mark;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getMoney() {
return money;
}
public void setMoney(String money) {
this.money = money;
}
public String getMark() {
return mark;
}
public void setMark(String mark) {
this.mark = mark;
}
@Override
public String toString() {
return "ZhangDan{" +
"type='" + type + '\'' +
", money='" + money + '\'' +
", mark='" + mark + '\'' +
'}';
}
}
public class ZhangDans {
private BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
public void start() {
// 所有退出使用异常
while (true){
// 显示菜单
showMenu();
// 输入选项
String key = inputMenu();
// 执行选项操作
execute(key);
}
}
// 执行选项操作
private void execute(String key) {
if ("1".equals(key)){
jiZhang();
System.out.println("开始记账");
}
if ("2".equals(key)){
showJieYu();
System.out.println("显示结余");
}
if ("3".equals(key)){
List<ZhangDan> list = showZhangDans();
for (ZhangDan z: list) {
System.out.println(z);
}
System.out.println("显示历史账单");
}
if ("4".equals(key)){
System.out.println("------------");
throw new RuntimeException("不要惊讶,你没错,我只使用这个退出");
}
}
// 结余
private void showJieYu() {
List<ZhangDan> list = showZhangDans();
double yuE = 0;
double shouRu = 0;
double zhiChu = 0;
for (ZhangDan zDan:list) {
if ("1".equals(zDan.getType())){
yuE += Double.parseDouble(zDan.getMoney());
shouRu += Double.parseDouble(zDan.getMoney());
}
if ("2".equals(zDan.getType())){
yuE -= Double.parseDouble(zDan.getMoney());
zhiChu += Double.parseDouble(zDan.getMoney());
}
}
System.out.println("总余额:"+yuE+"\t总收入:"+shouRu+"\t总支出:"+zhiChu);
}
// 显示历史账单
private List<ZhangDan> showZhangDans() {
/*try (BufferedReader bufferedReader = new BufferedReader(new FileReader(new File("day30/src/main/resources/zhangdan30.txt")))) {
while (true){
String line = bufferedReader.readLine();
if (line == null){
break;
}
System.out.println(line);
}
} catch (IOException e) {
System.out.println(e.getMessage());
throw new RuntimeException("账单查询失败并退出");
}*/
// ↑ 上和下 ↓ 都能实现
// 反序列化
try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("day30/src/main/resources/zhangdan30.txt")))) {
List<ZhangDan> list = (List<ZhangDan>) objectInputStream.readObject();
return list;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return new ArrayList<>();
}
// 记账功能
private void jiZhang() {
System.out.println("类型:1:收入 2:支出");
String type = inputType();
System.out.println("金额:");
String money = inputMoney();
System.out.println("说明");
String mark = inputMark();
ZhangDan zhangDan = new ZhangDan(type,money,mark);
saveZhangDan(zhangDan);
System.out.println("登记成功"+zhangDan);
}
private void saveZhangDan(ZhangDan zhangDan) {
/*// 输出流
try (PrintWriter printWriter = new PrintWriter(new FileWriter(new File("day30/src/main/resources/zhangdan30.txt"),true))){
printWriter.println(zhangDan);
printWriter.flush();
} catch (IOException e) {
System.out.println(e.getMessage());
throw new RuntimeException("账单保存失败并退出");
}*/
// ↑ 上和下 ↓ 都能实现
// 序列化流
File file = new File("day30/src/main/resources/zhangdan30.txt");
List<ZhangDan> list = new ArrayList<>();
if (file.exists()){
list = showZhangDans();
}
list.add(zhangDan);
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("day30/src/main/resources/zhangdan30.txt")))) {
objectOutputStream.writeObject(list);
// 刷新
objectOutputStream.flush();
objectOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 说明
private String inputMark() {
String s = null;
try {
s = cin.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return s;
}
// 金额
private String inputMoney() {
while (true){
try {
String money = cin.readLine();
// 留待学习更多知识后优化,验证,输入的必须是数字
int count = 0;
for (int i = 0; i < money.length(); i++) {
char c = money.charAt(i);
if (c >= '0' && c <= '9'){
continue;
}
if (c == '.' && count == 0){
count++;
continue;
}
throw new Exception("您输入的不是数字!");
}
return money;
} catch (IOException e) {
e.printStackTrace();
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
// 类型
private String inputType() {
while (true){
try {
String type = cin.readLine();
if ("1".equals(type) || "2".equals(type)){
return type;
}
throw new Exception("类型选项不对,你只能输入1或者2!");
} catch (IOException e) {
e.printStackTrace();
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
// 输入菜单
private String inputMenu() {
while (true){
try {
String key = cin.readLine();
if ("1".equals(key) || "2".equals(key) || "3".equals(key) || "4".equals(key)){
return key;
}
throw new Exception("您输入的数字范围不对");
} catch (IOException e) {
System.out.println("出现异常重试一次");
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
// 显示菜单
private void showMenu() {
System.out.println("1.记账\n" +
" 2.结余\n" +
" 3.账单\n" +
" 4.退出");
System.out.println("输入选项吧:");
}
}
4.序列化,反序列化
public class Test {
public static void main(String[] args) {
ZhangDan zhangDan = new ZhangDan("1","77","测试");
// 出流 输出对象类型的数据
// 序列化和反序列化的前提条件是:实现序列化接口 :implements Serializable
// 序列化流
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("day30/src/main/resources/data.d")))) {
objectOutputStream.writeObject(zhangDan);
// 刷新
objectOutputStream.flush();
objectOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化
try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("day30/src/main/resources/data.d")))) {
ZhangDan zhangDan1 = (ZhangDan)(objectInputStream.readObject());
System.out.println(zhangDan1);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
5.NI/O相关知识
NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的有效方式。
NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。