java中文本I/O、日期与时间API
一、文本I/O
1、字符流
字符流是以字符(char)为单位读写数据的:一次处理一个Unicode
- 字符流的底层仍然是基本的字节流
- 字符流封装了字符的编码解码算法
字符输出流:
/**
* @document: 文件字符输出流
* @Author:SmallG
* @CreateTime:2023/8/3+15:05
*/
public class Demo01 {
public static void main(String[] args) {
FileWriter writer = null;
try {
writer = new FileWriter("F:/hello.txt");
//往文件中写入内容
writer.write("SmallG大帅锅\n");
writer.write("SmallY大美铝\n");
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
//再finally中关闭流 关闭前提:write不为空
//try语句块执行后,如果在执行try出错了,writer对象没创建成功,所以不用关
if (writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字符输入流:
/**
* @document: 字符文件输入流:读取文件内容
* @Author:SmallG
* @CreateTime:2023/8/3+15:15
*/
public class Demo02 {
public static void main(String[] args) {
FileReader reader = null;
try {
reader = new FileReader("F:/hello.txt");
//定义读取字符的容器 一次读5个字符
char[] data = new char[5];
int len = -1;
while ((len = reader.read(data)) != -1) {
//转换为字符串
String str = new String(data, 0, len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
try-with-resources语法
- 目的是为了简化try-catch-finally语句块
- finally语句块不能范围try语句中声明的变量,这样有了try-with-resources语句
- try后面的()称为资源说明头,用于创建语句块中使用的资源对象
- 资源说明头中创建的对象必须实现java.lang.AutoCloseable接口,该接口只有一个方法-close()
/**
* @document: try-with-resources语法
* @Author:SmallG
* @CreateTime:2023/8/3+15:31
*/
public class Demo03 {
public static void main(String[] args) {
try (
MyStream1 stream1 = new MyStream1();
MyStream2 stream2 = new MyStream2()
) {
System.out.println("try with resources");
System.out.println(stream1);
System.out.println(stream2);
} catch (Exception e) {
}
}
}
class MyStream1 implements Closeable {
@Override
public void close() throws IOException {
System.out.println("MyStream1流关闭了");
}
}
class MyStream2 implements Closeable {
@Override
public void close() throws IOException {
System.out.println("MyStream2流关闭了");
}
}
2、字符缓冲流
- BufferedReader---------->字符输入缓冲流,缓冲区大小为8192个字符
- BufferedWriter----------->字符输出缓冲流,缓冲区大小为8192个字符
- BufferedReader,提供了readLine:读取一行内容,以'\n','\r'来识别,返回的内容不包括换行符。skip:跳过指定数量的字符。
- BufferedWriter中没有提供相似的writeLine方法,但提供了newLine方法,达到换行效果。
字符输出缓冲流
/**
* @document: 字符输出缓冲流
* @Author:SmallG
* @CreateTime:2023/8/3+15:47
*/
public class Demo04 {
public static void main(String[] args) {
try (
FileWriter writer = new FileWriter("F:/hello.txt");
BufferedWriter bw = new BufferedWriter(writer)
) {
bw.write("第一行内容:SmallG大帅锅\n");
bw.newLine();
bw.write("第二行内容:Hello BufferedWriter");
bw.newLine();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
字符输入缓冲流
/**
* @document: 字符输入缓冲流
* @Author:SmallG
* @CreateTime:2023/8/3+15:52
*/
public class Demo05 {
public static void main(String[] args) {
try (
FileReader reader = new FileReader("F:/hello.txt");
BufferedReader br = new BufferedReader(reader);
) {
String line = br.readLine();
while (line!=null){
System.out.println(line);
line = br.readLine();
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
3、转换流
用于字节流和字符流之间的转换
- InputStreamReader:字节输入流------->字符输入流
- OutputStreamWrite:字符输出流------->字节输出流
/**
* @document: 转换流:字节文件------>字符文件
* @Author:SmallG
* @CreateTime:2023/8/3+16:22
*/
public class Demo06 {
public static void main(String[] args) throws IOException {
// 字节流转换为字符流后效率会高一些
FileOutputStream fos = new FileOutputStream("F:/hello.txt");
//创建转换流 转换为字符流 增加读取速度
OutputStreamWriter osw = new OutputStreamWriter(fos);
//创建缓冲流进一步提高读取效率
BufferedWriter bw = new BufferedWriter(osw);
bw.write("第一行数据:大帅锅");
bw.newLine();
bw.write("第二行数据:is SmallG");
bw.newLine();
bw.close();
osw.close();
fos.close();
}
}
/**
* @document: 字符转换输入流:字节流------>字符流
* @Author:SmallG
* @CreateTime:2023/8/3+16:36
*/
public class Demo07 {
public static void main(String[] args) throws IOException {
//定义一个字节文件输入流 加载字符文件
FileInputStream fis = new FileInputStream("F:/hello.txt");
//定义转换流
InputStreamReader isr = new InputStreamReader(fis,"utf-8");
//定义字符输入缓冲流进一步提高效率
BufferedReader bfr = new BufferedReader(isr);
String line = bfr.readLine();
while (line!=null){
System.out.println(line);
line = bfr.readLine(); //继续读取
}
bfr.close();
isr.close();
fis.close();
}
}
4、数据统计实例
/**
* @document: 统计每个站点6月份最高温的平均值
* @Author:SmallG
* @CreateTime:2023/8/4+9:07
*/
public class DataAvgDemo {
public static void main(String[] args) {
try (
//加载数据文件
FileReader reader = new FileReader("F:/data1.csv");
//创建缓冲流提高效率
BufferedReader br = new BufferedReader(reader);
//创建输出文件
FileWriter writer = new FileWriter("F:/data2.csv");
//创建缓冲流
BufferedWriter bw = new BufferedWriter(writer);
) {
//写入第一行表中信息
bw.write("STATION,AVG");
//统计数据 共五个站点 分组求平均值 分五组
//去除除六月份的数据
//定义一个保持所有站点的数组
String[] stations = new String[]{"99727199999", "72505394728", "72055399999", "99774399999", "72503014732"};
//定义一个保存所有站点6月最高温度平均值的数组
BigDecimal[] tempDatas = new BigDecimal[5];
for (int i = 0; i < tempDatas.length; i++) {
tempDatas[i] = new BigDecimal(0);
}
//统计每个站点六月份共统计了几天
int[] dataCount = new int[5];
// 读取数据
String line = br.readLine(); // 第一行是表头要忽略
line = br.readLine(); // 从第二行数据开始读取
while (line != null) {
//处理数据
String[] dataArray = line.split(",");
//去除非6月份的数据
if (!dataArray[1].startsWith("2019/6")) {
line = br.readLine();
continue; //当前数据不处理
}
//取出温度
BigDecimal temp = new BigDecimal(dataArray[2]);
//判断当前是那个站点
if (dataArray[0].equals(stations[0])) {
tempDatas[0] = tempDatas[0].add(temp);
dataCount[0]++;
} else if (dataArray[0].equals(stations[1])) {
tempDatas[1] = tempDatas[1].add(temp);
dataCount[1]++;
} else if (dataArray[0].equals(stations[2])) {
tempDatas[2] = tempDatas[2].add(temp);
dataCount[2]++;
} else if (dataArray[0].equals(stations[3])) {
tempDatas[3] = tempDatas[3].add(temp);
dataCount[3]++;
} else if (dataArray[0].equals(stations[4])) {
tempDatas[4] = tempDatas[4].add(temp);
dataCount[4]++;
}
System.out.println(dataArray[1]);
//继续读取下一行
line = br.readLine();
}
for (int i = 0; i < tempDatas.length; i++) {
//保留两位小数 四舍五入
BigDecimal avg = tempDatas[i].divide(new BigDecimal(dataCount[i]), 2, RoundingMode.HALF_UP);
StringBuilder builder = new StringBuilder();
builder.append(stations[i]).append(",").append(avg);
//写入一行数据
bw.newLine(); // 换行
bw.write(builder.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
二、日期与时间API
1、Date类
Date类的每一个实例表示一个时间,内部维护一个long值:自标准基准时间以来的毫秒数
/**
* @document: Date类 能够表示日期和时间
* @Author:SmallG
* @CreateTime:2023/8/4+10:27
*/
public class Demo08 {
public static void main(String[] args) {
//创建date对象
Date now = new Date();
System.out.println(now); //Fri Aug 04 10:29:15 CST 2023
//Date中大部分方法都已经过时了
long time = now.getTime();
System.out.println(time);
now.setTime(0); //1970年1月1日 08:00:00
}
}
2、SimpleDateFormat类
对输出的Date对象进行格式化,会自动调用Date类中的toString方法。
构造方法:
- SimpleDateFormat()
- SimpleDateFormat(String patter)
常用方法:
- String format(Date date):将Date对象代表的时间格式化为字符串
- Date parse(String source):将字符串解析为Date对象
/**
* @document: 日期时间格式化:SimpleDateFormat
* @Author:SmallG
* @CreateTime:2023/8/4+10:47
*/
public class Demo09 {
public static void main(String[] args) {
//创建日期对象
Date now = new Date();
// 创建日期时间格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss a E");
//把当前的系统时间 转换为固定格式的日期时间
String format = sdf.format(now);
System.out.println(format);
}
}
3、新日期时间类概述
本地化的日期时间
- LocalDate:表示日期
- LocalTime:表示时间
- LocalDateTime:两者组合
/**
* @document: 本地化的时间日期
* @Author:SmallG
* @CreateTime:2023/8/4+11:11
*/
public class Demo10 {
public static void main(String[] args) {
//创建当前的时间对象
LocalDateTime ldt1 = LocalDateTime.now();
System.out.println(ldt1);
//获取年月日信息
System.out.print(ldt1.getYear() + "年");
System.out.print(ldt1.getMonthValue() + "月");
System.out.print(ldt1.getDayOfMonth() + "日");
//获取时分秒信息
System.out.print(ldt1.getHour() + "时");
System.out.print(ldt1.getMinute() + "分");
System.out.print(ldt1.getSecond() + "秒");
System.out.println();
//指定一个时间
LocalDateTime ldt2 = LocalDateTime.of(2023, 10, 1, 10, 10, 0);
System.out.println(ldt2);
// 计算时间 当前时间加上6小时
LocalDateTime ldt3 = ldt1.plus(6, ChronoUnit.HOURS)
.plusMinutes(10); //再加十分钟;
System.out.println(ldt3);
//当前时间减去1小时
LocalDateTime ldt4 = ldt1.minus(1, ChronoUnit.HOURS)
.minusMinutes(10); //再减去10分钟
System.out.println(ldt4);
}
}
时区操作
now():方法可以获取当前时区的时间,在now中添加参数ZoneId.of("时区名"),可以获取相应时区的时间。
/**
* @document: ZoneDateTime
* @Author:SmallG
* @CreateTime:2023/8/4+11:29
*/
public class Demo11 {
public static void main(String[] args) {
//创建时区对象
ZonedDateTime zdt1 = ZonedDateTime.now();
System.out.println(zdt1); //默认时区中国东八区时间
//指定时区的时间
ZonedDateTime zdt2 = ZonedDateTime.now(ZoneId.of("America/Los_Angeles")); //美国西部时间(洛杉矶)
System.out.println(zdt2);
//通过LocalDateTime转换为ZoneDateTime
LocalDateTime ldt = LocalDateTime.of(2023, 10, 1, 10, 10, 10);
ZonedDateTime zdt3 = ldt.atZone(ZoneId.systemDefault()); //默认时区
System.out.println(zdt3);
ZonedDateTime zdt4 = ldt.atZone(ZoneId.of("America/New_York")); //美国东部时间
System.out.println(zdt4);
ZonedDateTime zdt5 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
//转换为巴黎时间
ZonedDateTime zdt6 = zdt5.withZoneSameInstant(ZoneId.of("Europe/Paris"));
System.out.println(zdt5);
System.out.println(zdt6);
}
}
日期时间格式化
DateTimeFormatter方法:
ofPattern():用于格式化时间
format():用于输出
/**
* @document: DateTimeFormatter
* @Author:SmallG
* @CreateTime:2023/8/4+11:47
*/
public class Demo12 {
public static void main(String[] args) {
//创建当前时间
ZonedDateTime zdt = ZonedDateTime.now();
//创建日期格式
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//输出日期
System.out.println(formatter1.format(zdt));
//换一种方式得到时间
DateTimeFormatter formatter2 = DateTimeFormatter
.ofPattern("yyyy MM dd EE HH:mm:ss", Locale.CHINA);
System.out.println(formatter2.format(zdt));
//获得英国的时间
DateTimeFormatter formatter3 = DateTimeFormatter
.ofPattern("E, MM/dd/yyyy HH:mm:ss", Locale.UK);
System.out.println(formatter3.format(zdt));
//指定时间
DateTimeFormatter formatter4 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String time = "2023-10-01 10:10:10";
LocalDateTime ldt = LocalDateTime.parse(time, formatter4);
System.out.println(ldt);
}
}
三、练习
1 读取文本文件中的每一行数据信息,求其和再存入最后一行
文本文件pw.txt的内容如下所示:
操作完毕之后的文本文件pw.txt的内容如下所示:
提示:基于字符流缓冲流实现。
/**
* @document: 读取文本文件中的每一行数据信息,求其和再存入最后一行 字符流
* @Author:SmallG
* @CreateTime:2023/8/3+18:08
*/
public class ReadFile {
public static void main(String[] args) {
try (
FileReader reader = new FileReader("src/day04/homework/pw.txt");
FileWriter writer = new FileWriter("src/day04/homework/pw.txt", true)
) {
char[] data = new char[5];
int len = -1;
StringBuilder builder = new StringBuilder();
while ((len = reader.read(data)) != -1) {
String str = new String(data,0,len);
builder.append(str.replace("\n","").replace("\r",""));
}
writer.write(builder.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
2 日期计算练习
程序启动后,要求用户在控制台输入自己的生日,格式为:yyyy-MM-dd。然后经过程序计算,输出:
1、用户到今天为止一共活了多少天
2、输出其出生10000天的纪念日,格式为yyyy-MM-dd
提示:请基于Java 8提供的新日期时间API实现
程序运行效果如下所示:
/**
* @document:日期计算
* @Author:SmallG
* @CreateTime:2023/8/4+18:10
*/
public class Birthday {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入您的生日:");
String birthday = scanner.next();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate now = LocalDate.now();
LocalDate birth = LocalDate.parse(birthday, dtf);
//相减
long days = birth.until(now, ChronoUnit.DAYS);
System.out.println("恭喜您,一共活了" + days + "天!请继续保持!");
LocalDate res = birth.plus(10000, ChronoUnit.DAYS);
System.out.println("您出生10000天的纪念日为:" + res);
}
}