JavaSE学习笔记(二十八)—— IO流练习
一、复制文本文件
复制数据,如果我们知道用记事本打开并能够读懂,就用字符流,否则用字节流。
通过该原理,我们知道我们应该采用字符流更方便一些。
而字符流有5种方式,所以做这个题目我们有5种方式。推荐掌握第5种——字符缓冲流一次读写一个字符串
/** * 数据源: * e:\\a.txt -- FileReader -- BufferdReader * 目的地: * d:\\b.txt -- FileWriter -- BufferedWriter */ public class CopyFileDemo { public static void main(String[] args) throws IOException { String srcString = "E:\\a.txt"; String destString = "D:\\b.txt"; // method1(srcString, destString); // method2(srcString, destString); // method3(srcString, destString); // method4(srcString, destString); method5(srcString, destString); } // 字符缓冲流一次读写一个字符串(重点掌握) private static void method5(String srcString, String destString) throws IOException { BufferedReader br = new BufferedReader(new FileReader(srcString)); BufferedWriter bw = new BufferedWriter(new FileWriter(destString)); String line = null; while ((line = br.readLine()) != null) { bw.write(line); bw.newLine(); bw.flush(); } bw.close(); br.close(); } // 字符缓冲流一次读写一个字符串 private static void method4(String srcString, String destString) throws IOException { BufferedReader br = new BufferedReader(new FileReader(srcString)); BufferedWriter bw = new BufferedWriter(new FileWriter(destString)); char[] chs = new char[1024]; int len = 0; while ((len = br.read(chs)) != -1) { bw.write(chs, 0, len); } br.close(); bw.close(); } // 字符缓冲流一次读写一个字符 private static void method3(String srcString, String destString) throws IOException { BufferedReader br = new BufferedReader(new FileReader(srcString)); BufferedWriter bw = new BufferedWriter(new FileWriter(destString)); int ch = 0; while ((ch = br.read()) != -1) { bw.write(ch); } bw.close(); br.close(); } // 基本字符流一次读写一个字符数组 private static void method2(String srcString, String destString) throws IOException { FileReader fr = new FileReader(srcString); FileWriter fw = new FileWriter(destString); char[] chs = new char[1024]; int len = 0; while ((len = fr.read(chs)) != -1) { fw.write(chs, 0, len); } fw.close(); fr.close(); } // 基本字符流一次读写一个字符 private static void method1(String srcString, String destString) throws IOException { FileReader fr = new FileReader(srcString); FileWriter fw = new FileWriter(destString); int ch = 0; while ((ch = fr.read()) != -1) { fw.write(ch); } fw.close(); fr.close(); } }
二、复制图片
复制数据,如果我们知道用记事本打开并能够读懂,就用字符流,否则用字节流。
通过该原理,我们知道我们应该采用字节流。
而字节流有4种方式,所以做这个题目我们有4种方式。推荐掌握第4种——字节缓冲流一次读写一个字节数组
/** * 数据源: * e:\\a.jpg -- FileInputStream -- BufferedInputStream * 目的地: * d:\\b.jpg -- FileOutputStream -- BufferedOutputStream */ public class CopyImageDemo { public static void main(String[] args) throws IOException { // 使用字符串作为路径 // String srcString = "c:\\a.jpg"; // String destString = "d:\\b.jpg"; // 使用File对象做为参数 File srcFile = new File("E:\\a.jpg"); File destFile = new File("D:\\b.jpg"); // method1(srcFile, destFile); // method2(srcFile, destFile); // method3(srcFile, destFile); method4(srcFile, destFile); } // 字节缓冲流一次读写一个字节数组(重点掌握) private static void method4(File srcFile, File destFile) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile)); byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } // 字节缓冲流一次读写一个字节 private static void method3(File srcFile, File destFile) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile)); int by = 0; while ((by = bis.read()) != -1) { bos.write(by); } bis.close(); bos.close(); } // 基本字节流一次读写一个字节数组 private static void method2(File srcFile, File destFile) throws IOException { FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); byte[] bys = new byte[1024]; int len = 0; while ((len = fis.read(bys)) != -1) { fos.write(bys, 0, len); } fos.close(); fis.close(); } // 基本字节流一次读写一个字节 private static void method1(File srcFile, File destFile) throws IOException { FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); int by = 0; while ((by = fis.read()) != -1) { fos.write(by); } fos.close(); fis.close(); } }
三、将集合的数据存储到文本文件
需求:把ArrayList集合中的字符串数据存储到文本文件
/** * 分析: * 通过题目的意思我们可以知道如下的一些内容, * ArrayList集合里存储的是字符串。 * 遍历ArrayList集合,把数据获取到。 * 然后存储到文本文件中。 * 文本文件说明使用字符流。 * * 数据源: * ArrayList<String> -- 遍历得到每一个字符串数据 * 目的地: * a.txt -- FileWriter -- BufferedWriter */ public class ArrayListToFileDemo { public static void main(String[] args) throws IOException { // 封装数据与(创建集合对象) ArrayList<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); list.add("java"); // 封装目的地 BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt")); // 遍历集合 for (String s : list) { // 写数据 bw.write(s); bw.newLine(); bw.flush(); } // 释放资源 bw.close(); } }
四、把文本文件中的数据存储到集合中
需求:从文本文件中读取数据(每一行为一个字符串数据)到集合中,并遍历集合
/** * 分析: * 通过题目的意思我们可以知道如下的一些内容, * 数据源是一个文本文件。 * 目的地是一个集合。 * 而且元素是字符串。 * * 数据源: * b.txt -- FileReader -- BufferedReader * 目的地: * ArrayList<String> */ public class FileToArrayListDemo { public static void main(String[] args) throws IOException { // 封装数据源 BufferedReader br = new BufferedReader(new FileReader("a.txt")); // 封装目的地(创建集合对象) ArrayList<String> list = new ArrayList<>(); // 读取数据存储到集合中 String line = null; while ((line = br.readLine()) != null) { list.add(line); } // 释放资源 br.close(); // 遍历集合 for (String s : list) { System.out.println(s); } } }
五、随机获取文本文件中的姓名
需求:我有一个文本文件中存储了几个名称,请写一个程序实现随机获取一个人的名字。
/** * 分析: * A:把文本文件中的数据存储到集合中 * B:随机产生一个索引 * C:根据该索引获取一个值 */ public class GetName { public static void main(String[] args) throws IOException { // 把文本文件中的数据存储到集合中 BufferedReader br = new BufferedReader(new FileReader("a.txt")); ArrayList<String> list = new ArrayList<>(); String line = null; while ((line = br.readLine()) != null) { list.add(line); } br.close(); // 随机产生一个索引 Random r = new Random(); int index = r.nextInt(list.size()); // 根据该索引获取一个值 String name = list.get(index); System.out.println("该幸运者是:" + name); } }
六、复制单极文件夹
/** * 数据源:e:\\demo * 目的地:e:\\test * * 分析: * A:封装目录 * B:获取该目录下的所有文本的File数组 * C:遍历该File数组,得到每一个File对象 * D:把该File进行复制 */ public class CopyFolderDemo { public static void main(String[] args) throws IOException { // 封装目录 File srcFolder = new File("E:\\demo"); // 封装目的地 File destFolder = new File("E:\\test"); // 如果目的地文件夹不存在,就创建 if (!destFolder.exists()) { destFolder.mkdir(); } // 获取该目录下的所有文本的File数组 File[] files = srcFolder.listFiles(); // 遍历该File数组,得到每一个File对象 for (File file : files) { // System.out.println(file); // 数据源:e:\\demo\\e.mp3 // 目的地:e:\\test\\e.mp3 String name = file.getName();// e.mp3 File newFile = new File(destFolder, name);// e:\\test\\e.mp3 copyFile(file, newFile); } } private static void copyFile(File file, File newFile) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile)); byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } }
七、复制指定目录下指定后缀名的文件并修改名称
/** * 需求:复制指定目录下的指定文件,并修改后缀名。 * 指定的文件是:.java文件。 * 指定的后缀名是:.jad * 指定的目录是:jad * * 数据源:e:\\java\\A.java * 目的地:e:\\jad\\A.jad * * 分析: * A:封装目录 * B:获取该目录下的java文件的File数组 * C:遍历该File数组,得到每一个File对象 * D:把该File进行复制 * E:在目的地目录下改名 */ public class CopyFolderDemo2 { public static void main(String[] args) throws IOException { // 封装目录 File srcFolder = new File("E:\\java"); // 封装目的地 File destFolder = new File("E:\\jad"); // 如果目的地目录不存在,就创建 if (!destFolder.exists()) { destFolder.mkdir(); } // 获取该目录下的java文件的File数组 File[] files = srcFolder.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return new File(dir, name).isFile() && name.endsWith(".java"); } }); // 遍历该File数组,得到每一个File对象 for (File file : files) { // System.out.println(file); // 数据源:e:\java\DataTypeDemo.java // 目的地:e:\\jad\DataTypeDemo.java String name = file.getName(); File newFile = new File(destFolder, name); copyFile(file, newFile); } // 在目的地目录下改名 File[] destFileArray = destFolder.listFiles(); for (File destFile : destFileArray) { // System.out.println(destFile); // e:\\jad\DataTypeDemo.java // e:\\jad\\DataTypeDemo.jad String name = destFile.getName(); String newName = name.replace(".java", ".jad"); File newFile = new File(destFolder, newName); destFile.renameTo(newFile); } } private static void copyFile(File file, File newFile) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream( file)); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(newFile)); byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } }
八、复制多极文件夹
/** * 需求:复制多极文件夹 * * 数据源:E:\\demos * 目的地:D:\\ * * 分析: * A:封装数据源File * B:封装目的地File * C:判断该File是文件夹还是文件 * a:是文件夹 * 就在目的地目录下创建该文件夹 * 获取该File对象下的所有文件或者文件夹File对象 * 遍历得到每一个File对象 * 回到C * b:是文件 * 就复制(字节流) */ public class CopyFoldersDemo { public static void main(String[] args) throws IOException { // 封装数据源File File srcFile = new File("E:\\demos"); // 封装目的地Fil File destFile = new File("D:\\"); // 复制文件夹的功能 copyFolder(srcFile, destFile); } private static void copyFolder(File srcFile, File destFile) throws IOException { // 判断该File是文件夹还是文件 if (srcFile.isDirectory()) { // 文件夹 File newFolder = new File(destFile, srcFile.getName()); newFolder.mkdir(); // 获取该File对象下的所有文件或者文件夹File对象 File[] files = srcFile.listFiles(); for (File file : files) { copyFolder(file, newFolder); } } else { // 文件 File newFile = new File(destFile, srcFile.getName()); copyFile(srcFile, newFile); } } private static void copyFile(File file, File newFile) throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream( file)); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(newFile)); byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } }
九、键盘录入学生信息按照总分排序并写入文本文件
/** * 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低存入文本文件 * * 分析: * A:创建学生类 * B:创建集合对象 * TreeSet<Student> * C:键盘录入学生信息存储到集合 * D:遍历集合,把数据写到文本文件 */ public class StudentDemo { public static void main(String[] args) throws IOException { // 创建集合对象 TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() { @Override public int compare(Student s1, Student s2) { int num = s1.getSum() - s2.getSum(); int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num; int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2; int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3; int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName()) : num4; return num5; } }); // 键盘录入学生信息存储到集合 for (int x = 1; x <= 5; x++) { Scanner sc = new Scanner(System.in); System.out.println("请录入第" + x + "个学生的学习信息"); System.out.println("姓名:"); String name = sc.nextLine(); System.out.println("语文成绩:"); int chinese = sc.nextInt(); System.out.println("数学成绩:"); int math = sc.nextInt(); System.out.println("英语成绩:"); int english = sc.nextInt(); // 创建学生对象 Student s = new Student(); s.setName(name); s.setChinese(chinese); s.setMath(math); s.setEnglish(english); // 把学生信息添加到集合 set.add(s); } // 遍历集合,把数据写到文本文件 BufferedWriter bw = new BufferedWriter(new FileWriter("student.txt")); bw.write("学生信息如下:"); bw.newLine(); bw.flush(); bw.write("姓名,语文成绩,数学成绩,英语成绩"); bw.newLine(); bw.flush(); for (Student s : set) { StringBuilder sb = new StringBuilder(); sb.append(s.getName()).append(",").append(s.getChinese()).append(",").append(s.getMath()).append(s.getEnglish()); bw.write(sb.toString()); bw.newLine(); bw.flush(); } // 释放资源 bw.close(); System.out.println("学习信息存储完毕"); } }
十、把一个文件中的字符串排序后再写入另一个文件
/** * 已知a.txt文件中有这样的一个字符串:“hcexfgijkamdnoqrzstuvwybpl” * 请编写程序读取数据内容,把数据排序后写入b.txt中。 * * 分析: * A:把a.txt这个文件给做出来 * B:读取该文件的内容,存储到一个字符串中 * C:把字符串转换为字符数组 * D:对字符数组进行排序 * E:把排序后的字符数组转换为字符串 * F:把字符串再次写入b.txt中 */ public class StringDemo { public static void main(String[] args) throws IOException { // 读取该文件的内容,存储到一个字符串中 BufferedReader br = new BufferedReader(new FileReader("a.txt")); String line = br.readLine(); br.close(); // 把字符串转换为字符数组 char[] chs = line.toCharArray(); // 对字符数组进行排序 Arrays.sort(chs); // 把排序后的字符数组转换为字符串 String s = new String(chs); //把字符串再次写入b.txt中 BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); bw.write(s); bw.newLine(); bw.flush(); bw.close(); } }
十一、用Reader模拟BufferedReader的readLine
自定义MyBufferedReader
/** * 用Reader模拟BufferedReader的readLine()功能 * * readLine():一次读取一行,根据换行符判断是否结束,只返回内容,不返回换行符 */ public class MyBufferedReader { private Reader reader; public MyBufferedReader(Reader reader) { this.reader = reader; } /** * 写一个方法,返回值是一个字符串。 * @return */ public String readLine() throws IOException { /* * 我要返回一个字符串,我该怎么办呢? 我们必须去看看reader对象能够读取什么东西呢? 两个读取方法,一次读取一个字符或者一次读取一个字符数组 * 那么,我们要返回一个字符串,用哪个方法比较好呢? 我们很容易想到字符数组比较好,但是问题来了,就是这个数组的长度是多长呢? * 根本就没有办法定义数组的长度,你定义多长都不合适。 所以,只能选择一次读取一个字符。 * 但是呢,这种方式的时候,我们再读取下一个字符的时候,上一个字符就丢失了 所以,我们又应该定义一个临时存储空间把读取过的字符给存储起来。 * 这个用谁比较和是呢?数组,集合,字符串缓冲区三个可供选择。 * 经过简单的分析,最终选择使用字符串缓冲区对象。并且使用的是StringBuilder */ StringBuilder sb = new StringBuilder(); // 做这个读取最麻烦的是判断结束,但是在结束之前应该是一直读取,直到-1 int ch = 0; while ((ch = reader.read()) != -1) { if (ch == '\r') { continue; } if (ch == '\n') { return sb.toString(); } else { sb.append((char) ch); } } // 为了防止数据丢失,判断sb的长度不能大于0 if (sb.length() > 0) { return sb.toString(); } return null; } /** * 关闭方法 * @throws IOException */ public void close() throws IOException { this.reader.close(); } }
测试MyBufferedReader的时候,你就把它当作BufferedReader一样的使用
public class MyBufferedReaderDemo { public static void main(String[] args) throws IOException { MyBufferedReader mbr = new MyBufferedReader(new FileReader("a.txt")); String line = null; while ((line = mbr.readLine()) != null) { System.out.println(line); } mbr.close(); } }
十二、自定义类模拟LineNumberReader的获取行号功能
LineNumberReader是BufferedReader的子类,它的特有功能有:
- public int getLineNumber()获得当前行号。
- public void setLineNumber(int lineNumber)
public class LineNumberReaderDemo { public static void main(String[] args) throws IOException { LineNumberReader lnr = new LineNumberReader(new FileReader("my.txt")); // 从10开始才比较好 // lnr.setLineNumber(10); // System.out.println(lnr.getLineNumber()); // System.out.println(lnr.getLineNumber()); // System.out.println(lnr.getLineNumber()); String line = null; while ((line = lnr.readLine()) != null) { System.out.println(lnr.getLineNumber() + ":" + line); } lnr.close(); } }
我们要做的就是自定义一个类来模拟LineNumberReader的getLineNumber()功能
public class MyLineNumberReader { private Reader reader; private int lineNumber = 0; public MyLineNumberReader(Reader reader) { this.reader = reader; } public int getLineNumber() { return lineNumber; } public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } public String readLine() throws IOException { lineNumber++; StringBuilder sb = new StringBuilder(); int ch = 0; while ((ch = reader.read()) != -1) { if (ch == '\r') { continue; } if (ch == '\n') { return sb.toString(); } else { sb.append((char) ch); } } if (sb.length() > 0) { return sb.toString(); } return null; } public void close() throws IOException { this.reader.close(); } }
用继承来优化MyLineNumberReader:
public class MyLineNumberReader2 extends MyBufferedReader { private Reader reader; private int lineNumber = 0; public MyLineNumberReader2(Reader reader) { super(reader); } public int getLineNumber() { return lineNumber; } public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } @Override public String readLine() throws IOException { lineNumber++; return super.readLine(); } }
测试类:
public class MyLineNumberReaderTest { public static void main(String[] args) throws IOException { // MyLineNumberReader mlnr = new MyLineNumberReader(new FileReader("a.txt")); MyLineNumberReader2 mlnr = new MyLineNumberReader2(new FileReader("a.txt")); /*mlnr.setLineNumber(10); System.out.println(mlnr.getLineNumber()); System.out.println(mlnr.getLineNumber()); System.out.println(mlnr.getLineNumber());*/ String line = null; while ((line = mlnr.readLine()) != null) { System.out.println(mlnr.getLineNumber() + ":" + line); } mlnr.close(); } }