练习:四种拷贝方式效率对比
PS:每次运行程序的用时可能是不一样的,因为在电脑中不仅仅有Java在运行,还有其他的软件。
还有电脑性能不一样,用时也有可能是不一样的。
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
//method1();
//method2(); //16.253秒
//method3(); //95.466秒,虽然也有缓冲区,但是它需要在两个缓冲区之间进行倒手,一个字节一个字节倒。又因为这个倒手是发生在字节中的,但文件太大了,因此也要浪费一点时间的。这就导致了第三种方式的性能反而降低了,低就低在倒手的时间上。
//method4(); //17.686秒
long end = System.currentTimeMillis();
// 注意在除的时候需要加上.0,否则结果只能是整数
System.out.println((end - start) / 1000.0 + "秒");
}
//字节流的基本流:一次读写一个字节4,588,568,576 字节
public static void method1() throws IOException {
FileInputStream fis = new FileInputStream("E:\\aaa\\CentOS-7-x86_64-DVD-1810.iso");
FileOutputStream fos = new FileOutputStream("myio\\copy.iso");
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
fos.close();
fis.close();
}
//字节流的基本流:一次读写一个字节数组
public static void method2() throws IOException {
FileInputStream fis = new FileInputStream("E:\\aaa\\CentOS-7-x86_64-DVD-1810.iso");
FileOutputStream fos = new FileOutputStream("myio\\copy.iso");
byte[] bytes = new byte[8192];
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
fos.close();
fis.close();
}
//字节流的基本流:一次读写一个字节数组
public static void method3() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\aaa\\CentOS-7-x86_64-DVD-1810.iso"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myio\\copy.iso"));
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
bos.close();
bis.close();
}
//字节流的基本流:一次读写一个字节数组
public static void method4() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\aaa\\CentOS-7-x86_64-DVD-1810.iso"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myio\\copy.iso"));
byte[] bytes = new byte[8192];
int len;
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
bos.close();
bis.close();
}
练习:把《出师表》的文章顺序进行恢复到一个新文件中
需求:把《出师表》的文章顺序进行恢复到一个新文件中。
3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
9.今当远离,临表涕零,不知所言。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
如果使用字符流的基本流读也行,但是需要将所有读到的字拼在一起,太麻烦了。
因此这里使用 字符缓冲流
,它里面有一个非常好用的 readLine()
,一次可以读一整行数据。
排序的时候不可以使用字符串排序,因为如果写的再多一点,可能会有序号 11、12、13
等,此时就不能使用字符串排了,因此尽量要考虑代码的通用性。
写法一:
//1.读取数据
BufferedReader br = new BufferedReader(new FileReader("myio\\csb.txt"));
String line;
ArrayList<String> list = new ArrayList<>();
while((line = br.readLine()) != null){
list.add(line);
}
br.close();
//2.排序
//排序规则:按照每一行前面的序号进行排列
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//获取o1和o2的序号
int i1 = Integer.parseInt(o1.split("\\.")[0]);
int i2 = Integer.parseInt(o2.split("\\.")[0]);
return i1 - i2;
}
});
//3.写出
BufferedWriter bw = new BufferedWriter(new FileWriter("myio\\result.txt"));
for (String str : list) {
bw.write(str);
bw.newLine();
}
bw.close();
写法二:
//1.读取数据
BufferedReader br = new BufferedReader(new FileReader("myio\\csb.txt"));
String line;
TreeMap<Integer,String> tm = new TreeMap<>();
while((line = br.readLine()) != null){
String[] arr = line.split("\\.");
//0:序号 1 :内容,注意这里添加的是完整的数据,包括序号
tm.put(Integer.parseInt(arr[0]), line);
}
br.close();
//2.写出数据
BufferedWriter bw = new BufferedWriter(new FileWriter("myio\\result2.txt"));
Set<Map.Entry<Integer, String>> entries = tm.entrySet();
for (Map.Entry<Integer, String> entry : entries) {
String value = entry.getValue();
bw.write(value);
bw.newLine();
}
bw.close();
练习:软件运行四次
实现一个验证程序运行次数的小程序,要求如下:
1.当程序运行超过3次时给出提示:本软件只能免费使用3次,欢迎您注册会员后继续使用~
2.程序运行演示如下:
第一次运行控制台输出: 欢迎使用本软件,第1次使用免费~
第二次运行控制台输出: 欢迎使用本软件,第2次使用免费~
第三次运行控制台输出: 欢迎使用本软件,第3次使用免费~
第四次及之后运行控制台输出:本软件只能免费使用3次,欢迎您注册会员后继续使用~
一、代码示例
注意这里是不能通过定义变量 int count = 0
去统计次数,因为变量是运行在内存中的,程序结束后,变量就会消失,因此不能将变量定义在内存中。
我们可以将它保存在本地文件中。
//1.把文件中的数字读取到内存中
BufferedReader br = new BufferedReader(new FileReader("myio\\count.txt"));
String line = br.readLine(); // 由于只有一行,就没必要循环去遍历了
int count = Integer.parseInt(line);
//表示当前软件又运行了一次
count++;//1
//2.判断
if(count <= 3){
System.out.println("欢迎使用本软件,第"+count+"次使用免费~");
}else{
System.out.println("本软件只能免费使用3次,欢迎您注册会员后继续使用~");
}
BufferedWriter bw = new BufferedWriter(new FileWriter("myio\\count.txt"));
//3.把当前自增之后的count写出到文件当中
bw.write(count + ""); //PS:注意转为字符串,否则如果写的是数字,那么真正写到文件里的是这个数字在字符集中所对应的字符
bw.close();
二、扩展
有的人之前拷贝写习惯了,喜欢将这两种流先创建出来,下面再挨个使用。
BufferedReader br = new BufferedReader(new FileReader("myio\\count.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("myio\\count.txt"));
在这里绝对不行!因为 BufferedWriter
在创建文件的时候,如果文件存在,就会清空。
一旦清空了,下面读取文件的时候就会有空指针。
因此一般在创建 IO流
对象的时候,一般会有这样的原则:IO流
不是随随便便创建的,而是什么时候用什么时候创建,什么时候不用什么时候关闭。
因此上面的代码一旦 br
读完了数据,就要将它立马关掉。
BufferedReader br = new BufferedReader(new FileReader("myio\\count.txt"));
String line = br.readLine(); // 由于只有一行,就没必要循环去遍历了
br.close();