面试题之——java交织读取两个文件中单词,然后写入新的文件
面试题之——java交叉读取两个文件中单词,然后写入新的文件
代码不足之处
改进后代码
今天看到一道面试题,题目为:编写一个程序,将a.txt文件中的单词与b.txt文件中的单词进行交替合并到c.txt文件中 。a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格分开。
文章中给出的代码是
-
import java.io.File; import java.io.FileReader; import java.io.FileWriter; public class MainClass { public static void main(String[] args) throws Exception { FileManager a = new FileManager("a.txt", new char[]{'\n'}); FileManager b = new FileManager("b.txt", new char[]{'\n', ' '}); FileWriter c = new FileWriter("c.txt"); String aWord = null; String bWord = null; while((aWord=a.nextWord())!=null) { c.write(aWord + "\n"); bWord = b.nextWord(); if(bWord!=null) { c.write(bWord + "\n"); } } while((bWord = b.nextWord())!=null) { c.write(bWord + "\n"); } c.close(); } } class FileManager { String[] words = null; int pos = 0; public FileManager(String filename, char[] seperators) throws Exception{ File f = new File(filename); FileReader reader = new FileReader(f); char[] buf = new char[(int)f.length()]; int len = reader.read(buf); String result = new String(buf, 0, len); String regex = null; if(seperators.length>1) { regex = "" + seperators[0] + "|" + seperators[1]; } else { regex ="" + seperators[0]; } words = result.split(regex); } public String nextWord() { if(pos == words.length) { return null; } return words[pos++]; } }
代码不足之处
代码本身能够做到题目的要求,但是有几处考虑不足:
- 在FileManager类中,我们使用FileReader字符流打开了资源,而在程序最后并没有关闭该资源,这是十分危险的操作。
- 在使用FileReader对文件进行读取时,只是简单的读取了一次就把读取到的数据封装成了String字符串。如果我们要读取的文件较小,只有几KB,那没有问题。那么,当我们读取的文件很大,大到一次并不能读取完,这是就出问题了。
- (这处也许是我多虑了)我们都知道,Linux和windows下的文件在回车换行方面处理不同。“\r,\n”都有新起一行的效果,但在两种操作系统中处理方式不同,也就是说,在windows下当我们敲下回车键时,在新起的上一行的最后会自动添加“\r\n”,而Linux下只会添加“\n”。此时就体现出了操作系统的差异性。那么我们对待这两种操作系统要有不同的操作。同时,在我们向新文件即c.txt文件中写入时,如果使用的是c.write(aWord + "\n");,那么在Windows下打开该文件,所有的单词应该显示成一行,而Linux操作系统下则会一个单词一个换行。
对上述不足改进
添加对资源进行关闭的方法
public void close() { if(fis!=null) { //fis是读取文件的字节流 try { fis.close(); } catch (IOException e) { e.printStackTrace(); } finally { fis = null; } } }
对读取文件内容进行改进
byte[] a = new byte[fis.available()]; int len = fis.read(a); int total = 0; //如果total小于字节数组的长度,说明文件没有读取完成 while (total < a.length) { total += len; //向字节数组中写入数据,起始偏移量是已读取数据长度, a.length - total表示剩余数据长度 len = fis.read(a, total, a.length - total); }
改进后代码
package com.zyh.interview; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.net.URL; /** * 将a.txt文件中的单词与b.txt文件中的单词进行交替合并到c.txt文件中 * a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格分开 * @author zyh */ public class Question111 { public static void main(String[] args) throws Exception { /**获取当前操作系统的换行符*/ String lineSeparator = System.getProperty("line.separator"); /**考虑到不同操作系统换行符的不同,Windows下是"\r\n",Linux下是"\n"(Unix下好像是"\r",不太确定)*/ FileManager fma = new FileManager("a.txt", new String[]{"\n","\r\n"}); /**"\\s"表示空格*/ FileManager fmb = new FileManager("b.txt", new String[]{"\n","\r\n","\\s"}); //c.txt文件保存位置是类路径即bin目录下 FileWriter fw = new FileWriter(new File(ClassLoader.getSystemResource("").getFile(), "c.txt")); String aWord = null; String bWord = null; while((aWord=fma.nextWord())!=null) { //添加“A:”是为了观察容易结果是按怎样的顺序写入文件的 fw.write("A:" + aWord + lineSeparator); if((bWord=fmb.nextWord())!=null) { fw.write("B:" +bWord+ lineSeparator); } } while((bWord=fmb.nextWord())!=null) { fw.write("B:" +bWord+ lineSeparator); } fw.flush(); fw.close(); /**关闭文件字符流对a.txt和b.txt资源的连接*/ fma.close(); fmb.close(); } } class FileManager { String[] words = null; int pos = 0; FileInputStream fis = null; public FileManager() { } public FileManager(String fileName, String[] seperators) throws Exception { /**获取当前项目的类路径*/ URL classpath = FileManager.class.getClassLoader().getResource(""); File file = new File(classpath.getFile(), fileName); fis = new FileInputStream(file); /**从文件中读取数据*/ byte[] a = new byte[fis.available()]; int len = fis.read(a); int total = 0; //如果total小于字节数组的长度,说明文件没有读取完成 while (total < a.length) { total += len; //向字节数组中写入数据,起始偏移量是已读取数据长度, a.length - total表示剩余数据长度 len = fis.read(a, total, a.length - total); } StringBuffer regex = new StringBuffer(); for(String seperator : seperators){ regex.append(seperator + "|"); } regex.deleteCharAt(regex.length()-1); words = new String(a).split(regex.toString()); } public String nextWord(){ if(pos >= words.length) { return null; } return words[pos++]; } public void close() { if(fis!=null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } finally { fis = null; } } } }
结果示例
从左到右文件名依次为:b.txt, a.txt, c.txt(c.txt并未显示完结果)